The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/acpica/acpi_resource.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2000 Michael Smith
    3  * Copyright (c) 2000 BSDi
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/10.3/sys/dev/acpica/acpi_resource.c 281687 2015-04-18 08:01:12Z jkim $");
   30 
   31 #include "opt_acpi.h"
   32 #include <sys/param.h>
   33 #include <sys/kernel.h>
   34 #include <sys/bus.h>
   35 #include <sys/limits.h>
   36 #include <sys/malloc.h>
   37 #include <sys/module.h>
   38 
   39 #include <machine/bus.h>
   40 #include <machine/resource.h>
   41 #include <sys/rman.h>
   42 
   43 #include <contrib/dev/acpica/include/acpi.h>
   44 #include <contrib/dev/acpica/include/accommon.h>
   45 
   46 #include <dev/acpica/acpivar.h>
   47 
   48 /* Hooks for the ACPI CA debugging infrastructure */
   49 #define _COMPONENT      ACPI_BUS
   50 ACPI_MODULE_NAME("RESOURCE")
   51 
   52 struct lookup_irq_request {
   53     ACPI_RESOURCE *acpi_res;
   54     struct resource *res;
   55     int         counter;
   56     int         rid;
   57     int         found;
   58 };
   59 
   60 static ACPI_STATUS
   61 acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
   62 {
   63     struct lookup_irq_request *req;
   64     size_t len;
   65     u_int irqnum, irq;
   66 
   67     switch (res->Type) {
   68     case ACPI_RESOURCE_TYPE_IRQ:
   69         irqnum = res->Data.Irq.InterruptCount;
   70         irq = res->Data.Irq.Interrupts[0];
   71         len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
   72         break;
   73     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
   74         irqnum = res->Data.ExtendedIrq.InterruptCount;
   75         irq = res->Data.ExtendedIrq.Interrupts[0];
   76         len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
   77         break;
   78     default:
   79         return (AE_OK);
   80     }
   81     if (irqnum != 1)
   82         return (AE_OK);
   83     req = (struct lookup_irq_request *)context;
   84     if (req->counter != req->rid) {
   85         req->counter++;
   86         return (AE_OK);
   87     }
   88     req->found = 1;
   89     KASSERT(irq == rman_get_start(req->res),
   90         ("IRQ resources do not match"));
   91     bcopy(res, req->acpi_res, len);
   92     return (AE_CTRL_TERMINATE);
   93 }
   94 
   95 ACPI_STATUS
   96 acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
   97     ACPI_RESOURCE *acpi_res)
   98 {
   99     struct lookup_irq_request req;
  100     ACPI_STATUS status;
  101 
  102     req.acpi_res = acpi_res;
  103     req.res = res;
  104     req.counter = 0;
  105     req.rid = rid;
  106     req.found = 0;
  107     status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
  108         acpi_lookup_irq_handler, &req);
  109     if (ACPI_SUCCESS(status) && req.found == 0)
  110         status = AE_NOT_FOUND;
  111     return (status);
  112 }
  113 
  114 void
  115 acpi_config_intr(device_t dev, ACPI_RESOURCE *res)
  116 {
  117     u_int irq;
  118     int pol, trig;
  119 
  120     switch (res->Type) {
  121     case ACPI_RESOURCE_TYPE_IRQ:
  122         KASSERT(res->Data.Irq.InterruptCount == 1,
  123             ("%s: multiple interrupts", __func__));
  124         irq = res->Data.Irq.Interrupts[0];
  125         trig = res->Data.Irq.Triggering;
  126         pol = res->Data.Irq.Polarity;
  127         break;
  128     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  129         KASSERT(res->Data.ExtendedIrq.InterruptCount == 1,
  130             ("%s: multiple interrupts", __func__));
  131         irq = res->Data.ExtendedIrq.Interrupts[0];
  132         trig = res->Data.ExtendedIrq.Triggering;
  133         pol = res->Data.ExtendedIrq.Polarity;
  134         break;
  135     default:
  136         panic("%s: bad resource type %u", __func__, res->Type);
  137     }
  138 
  139 #if defined(__amd64__) || defined(__i386__)
  140     /*
  141      * XXX: Certain BIOSes have buggy AML that specify an IRQ that is
  142      * edge-sensitive and active-lo.  However, edge-sensitive IRQs
  143      * should be active-hi.  Force IRQs with an ISA IRQ value to be
  144      * active-hi instead.
  145      */
  146     if (irq < 16 && trig == ACPI_EDGE_SENSITIVE && pol == ACPI_ACTIVE_LOW)
  147         pol = ACPI_ACTIVE_HIGH;
  148 #endif
  149     BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ?
  150         INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
  151         INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
  152 }
  153 
  154 struct acpi_resource_context {
  155     struct acpi_parse_resource_set *set;
  156     device_t    dev;
  157     void        *context;
  158 };
  159 
  160 #ifdef ACPI_DEBUG_OUTPUT
  161 static const char *
  162 acpi_address_range_name(UINT8 ResourceType)
  163 {
  164     static char buf[16];
  165 
  166     switch (ResourceType) {
  167     case ACPI_MEMORY_RANGE:
  168             return ("Memory");
  169     case ACPI_IO_RANGE:
  170             return ("IO");
  171     case ACPI_BUS_NUMBER_RANGE:
  172             return ("Bus Number");
  173     default:
  174             snprintf(buf, sizeof(buf), "type %u", ResourceType);
  175             return (buf);
  176     }
  177 }
  178 #endif
  179             
  180 static ACPI_STATUS
  181 acpi_parse_resource(ACPI_RESOURCE *res, void *context)
  182 {
  183     struct acpi_parse_resource_set *set;
  184     struct acpi_resource_context *arc;
  185     UINT64 min, max, length, gran;
  186     const char *name;
  187     device_t dev;
  188 
  189     arc = context;
  190     dev = arc->dev;
  191     set = arc->set;
  192 
  193     switch (res->Type) {
  194     case ACPI_RESOURCE_TYPE_END_TAG:
  195         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
  196         break;
  197     case ACPI_RESOURCE_TYPE_FIXED_IO:
  198         if (res->Data.FixedIo.AddressLength <= 0)
  199             break;
  200         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
  201             res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength));
  202         set->set_ioport(dev, arc->context, res->Data.FixedIo.Address,
  203             res->Data.FixedIo.AddressLength);
  204         break;
  205     case ACPI_RESOURCE_TYPE_IO:
  206         if (res->Data.Io.AddressLength <= 0)
  207             break;
  208         if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
  209             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
  210                 res->Data.Io.Minimum, res->Data.Io.AddressLength));
  211             set->set_ioport(dev, arc->context, res->Data.Io.Minimum,
  212                 res->Data.Io.AddressLength);
  213         } else {
  214             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
  215                 res->Data.Io.Minimum, res->Data.Io.Maximum,
  216                 res->Data.Io.AddressLength));
  217             set->set_iorange(dev, arc->context, res->Data.Io.Minimum,
  218                 res->Data.Io.Maximum, res->Data.Io.AddressLength,
  219                 res->Data.Io.Alignment);
  220         }
  221         break;
  222     case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
  223         if (res->Data.FixedMemory32.AddressLength <= 0)
  224             break;
  225         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
  226             res->Data.FixedMemory32.Address,
  227             res->Data.FixedMemory32.AddressLength));
  228         set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address, 
  229             res->Data.FixedMemory32.AddressLength);
  230         break;
  231     case ACPI_RESOURCE_TYPE_MEMORY32:
  232         if (res->Data.Memory32.AddressLength <= 0)
  233             break;
  234         if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) {
  235             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
  236                 res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength));
  237             set->set_memory(dev, arc->context, res->Data.Memory32.Minimum,
  238                 res->Data.Memory32.AddressLength);
  239         } else {
  240             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
  241                 res->Data.Memory32.Minimum, res->Data.Memory32.Maximum,
  242                 res->Data.Memory32.AddressLength));
  243             set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum,
  244                 res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength,
  245                 res->Data.Memory32.Alignment);
  246         }
  247         break;
  248     case ACPI_RESOURCE_TYPE_MEMORY24:
  249         if (res->Data.Memory24.AddressLength <= 0)
  250             break;
  251         if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) {
  252             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
  253                 res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength));
  254             set->set_memory(dev, arc->context, res->Data.Memory24.Minimum,
  255                 res->Data.Memory24.AddressLength);
  256         } else {
  257             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
  258                 res->Data.Memory24.Minimum, res->Data.Memory24.Maximum,
  259                 res->Data.Memory24.AddressLength));
  260             set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum,
  261                 res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength,
  262                 res->Data.Memory24.Alignment);
  263         }
  264         break;
  265     case ACPI_RESOURCE_TYPE_IRQ:
  266         /*
  267          * from 1.0b 6.4.2 
  268          * "This structure is repeated for each separate interrupt
  269          * required"
  270          */
  271         set->set_irq(dev, arc->context, res->Data.Irq.Interrupts,
  272             res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
  273             res->Data.Irq.Polarity);
  274         break;
  275     case ACPI_RESOURCE_TYPE_DMA:
  276         /*
  277          * from 1.0b 6.4.3 
  278          * "This structure is repeated for each separate DMA channel
  279          * required"
  280          */
  281         set->set_drq(dev, arc->context, res->Data.Dma.Channels,
  282             res->Data.Dma.ChannelCount);
  283         break;
  284     case ACPI_RESOURCE_TYPE_START_DEPENDENT:
  285         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
  286         set->set_start_dependent(dev, arc->context,
  287             res->Data.StartDpf.CompatibilityPriority);
  288         break;
  289     case ACPI_RESOURCE_TYPE_END_DEPENDENT:
  290         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
  291         set->set_end_dependent(dev, arc->context);
  292         break;
  293     case ACPI_RESOURCE_TYPE_ADDRESS16:
  294     case ACPI_RESOURCE_TYPE_ADDRESS32:
  295     case ACPI_RESOURCE_TYPE_ADDRESS64:
  296     case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
  297         switch (res->Type) {
  298         case ACPI_RESOURCE_TYPE_ADDRESS16:
  299             gran = res->Data.Address16.Address.Granularity;
  300             min = res->Data.Address16.Address.Minimum;
  301             max = res->Data.Address16.Address.Maximum;
  302             length = res->Data.Address16.Address.AddressLength;
  303             name = "Address16";
  304             break;
  305         case ACPI_RESOURCE_TYPE_ADDRESS32:
  306             gran = res->Data.Address32.Address.Granularity;
  307             min = res->Data.Address32.Address.Minimum;
  308             max = res->Data.Address32.Address.Maximum;
  309             length = res->Data.Address32.Address.AddressLength;
  310             name = "Address32";
  311             break;
  312         case ACPI_RESOURCE_TYPE_ADDRESS64:
  313             gran = res->Data.Address64.Address.Granularity;
  314             min = res->Data.Address64.Address.Minimum;
  315             max = res->Data.Address64.Address.Maximum;
  316             length = res->Data.Address64.Address.AddressLength;
  317             name = "Address64";
  318             break;
  319         default:
  320             KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
  321                 ("should never happen"));
  322             gran = res->Data.ExtAddress64.Address.Granularity;
  323             min = res->Data.ExtAddress64.Address.Minimum;
  324             max = res->Data.ExtAddress64.Address.Maximum;
  325             length = res->Data.ExtAddress64.Address.AddressLength;
  326             name = "ExtAddress64";
  327             break;
  328         }
  329         if (length <= 0)
  330             break;
  331         if (res->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
  332             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  333                 "ignored %s %s producer\n", name,
  334                 acpi_address_range_name(res->Data.Address.ResourceType)));
  335             break;
  336         }
  337         if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
  338             res->Data.Address.ResourceType != ACPI_IO_RANGE) {
  339             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  340                 "ignored %s for non-memory, non-I/O\n", name));
  341             break;
  342         }
  343 
  344 #ifdef __i386__
  345         if (min > ULONG_MAX || (res->Data.Address.MaxAddressFixed && max >
  346             ULONG_MAX)) {
  347             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s above 4G\n",
  348                 name));
  349             break;
  350         }
  351         if (max > ULONG_MAX)
  352                 max = ULONG_MAX;
  353 #endif
  354         if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED &&
  355             res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
  356             if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
  357                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n",
  358                     name, (uintmax_t)min, (uintmax_t)length));
  359                 set->set_memory(dev, arc->context, min, length);
  360             } else {
  361                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name,
  362                     (uintmax_t)min, (uintmax_t)length));
  363                 set->set_ioport(dev, arc->context, min, length);
  364             }
  365         } else {
  366             if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
  367                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  368                     "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
  369                     (uintmax_t)max, (uintmax_t)length));
  370                 set->set_memoryrange(dev, arc->context, min, max, length, gran);
  371             } else {
  372                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
  373                     name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
  374                 set->set_iorange(dev, arc->context, min, max, length, gran);
  375             }
  376         }                   
  377         break;
  378     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  379         if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
  380             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
  381             break;
  382         }
  383         set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
  384             res->Data.ExtendedIrq.InterruptCount,
  385             res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
  386         break;
  387     case ACPI_RESOURCE_TYPE_VENDOR:
  388         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  389             "unimplemented VendorSpecific resource\n"));
  390         break;
  391     default:
  392         break;
  393     }
  394     return (AE_OK);
  395 }
  396 
  397 /*
  398  * Fetch a device's resources and associate them with the device.
  399  *
  400  * Note that it might be nice to also locate ACPI-specific resource items, such
  401  * as GPE bits.
  402  *
  403  * We really need to split the resource-fetching code out from the
  404  * resource-parsing code, since we may want to use the parsing
  405  * code for _PRS someday.
  406  */
  407 ACPI_STATUS
  408 acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
  409                      struct acpi_parse_resource_set *set, void *arg)
  410 {
  411     struct acpi_resource_context arc;
  412     ACPI_STATUS         status;
  413 
  414     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  415 
  416     set->set_init(dev, arg, &arc.context);
  417     arc.set = set;
  418     arc.dev = dev;
  419     status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
  420     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
  421         printf("can't fetch resources for %s - %s\n",
  422             acpi_name(handle), AcpiFormatException(status));
  423         return_ACPI_STATUS (status);
  424     }
  425     set->set_done(dev, arc.context);
  426     return_ACPI_STATUS (AE_OK);
  427 }
  428 
  429 /*
  430  * Resource-set vectors used to attach _CRS-derived resources 
  431  * to an ACPI device.
  432  */
  433 static void     acpi_res_set_init(device_t dev, void *arg, void **context);
  434 static void     acpi_res_set_done(device_t dev, void *context);
  435 static void     acpi_res_set_ioport(device_t dev, void *context,
  436                                     uint64_t base, uint64_t length);
  437 static void     acpi_res_set_iorange(device_t dev, void *context,
  438                                      uint64_t low, uint64_t high, 
  439                                      uint64_t length, uint64_t align);
  440 static void     acpi_res_set_memory(device_t dev, void *context,
  441                                     uint64_t base, uint64_t length);
  442 static void     acpi_res_set_memoryrange(device_t dev, void *context,
  443                                          uint64_t low, uint64_t high, 
  444                                          uint64_t length, uint64_t align);
  445 static void     acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
  446                                  int count, int trig, int pol);
  447 static void     acpi_res_set_ext_irq(device_t dev, void *context,
  448                                  uint32_t *irq, int count, int trig, int pol);
  449 static void     acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
  450                                  int count);
  451 static void     acpi_res_set_start_dependent(device_t dev, void *context,
  452                                              int preference);
  453 static void     acpi_res_set_end_dependent(device_t dev, void *context);
  454 
  455 struct acpi_parse_resource_set acpi_res_parse_set = {
  456     acpi_res_set_init,
  457     acpi_res_set_done,
  458     acpi_res_set_ioport,
  459     acpi_res_set_iorange,
  460     acpi_res_set_memory,
  461     acpi_res_set_memoryrange,
  462     acpi_res_set_irq,
  463     acpi_res_set_ext_irq,
  464     acpi_res_set_drq,
  465     acpi_res_set_start_dependent,
  466     acpi_res_set_end_dependent
  467 };
  468 
  469 struct acpi_res_context {
  470     int         ar_nio;
  471     int         ar_nmem;
  472     int         ar_nirq;
  473     int         ar_ndrq;
  474     void        *ar_parent;
  475 };
  476 
  477 static void
  478 acpi_res_set_init(device_t dev, void *arg, void **context)
  479 {
  480     struct acpi_res_context     *cp;
  481 
  482     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
  483         bzero(cp, sizeof(*cp));
  484         cp->ar_parent = arg;
  485         *context = cp;
  486     }
  487 }
  488 
  489 static void
  490 acpi_res_set_done(device_t dev, void *context)
  491 {
  492     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  493 
  494     if (cp == NULL)
  495         return;
  496     AcpiOsFree(cp);
  497 }
  498 
  499 static void
  500 acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
  501                     uint64_t length)
  502 {
  503     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  504 
  505     if (cp == NULL)
  506         return;
  507     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
  508 }
  509 
  510 static void
  511 acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
  512                      uint64_t high, uint64_t length, uint64_t align)
  513 {
  514     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  515 
  516     if (cp == NULL)
  517         return;
  518     device_printf(dev, "I/O range not supported\n");
  519 }
  520 
  521 static void
  522 acpi_res_set_memory(device_t dev, void *context, uint64_t base,
  523                     uint64_t length)
  524 {
  525     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  526 
  527     if (cp == NULL)
  528         return;
  529 
  530     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
  531 }
  532 
  533 static void
  534 acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
  535                          uint64_t high, uint64_t length, uint64_t align)
  536 {
  537     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  538 
  539     if (cp == NULL)
  540         return;
  541     device_printf(dev, "memory range not supported\n");
  542 }
  543 
  544 static void
  545 acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
  546     int trig, int pol)
  547 {
  548     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  549 
  550     if (cp == NULL || irq == NULL)
  551         return;
  552 
  553     /* This implements no resource relocation. */
  554     if (count != 1)
  555         return;
  556 
  557     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
  558 }
  559 
  560 static void
  561 acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
  562     int trig, int pol)
  563 {
  564     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  565 
  566     if (cp == NULL || irq == NULL)
  567         return;
  568 
  569     /* This implements no resource relocation. */
  570     if (count != 1)
  571         return;
  572 
  573     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
  574 }
  575 
  576 static void
  577 acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
  578 {
  579     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  580 
  581     if (cp == NULL || drq == NULL)
  582         return;
  583     
  584     /* This implements no resource relocation. */
  585     if (count != 1)
  586         return;
  587 
  588     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
  589 }
  590 
  591 static void
  592 acpi_res_set_start_dependent(device_t dev, void *context, int preference)
  593 {
  594     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  595 
  596     if (cp == NULL)
  597         return;
  598     device_printf(dev, "dependent functions not supported\n");
  599 }
  600 
  601 static void
  602 acpi_res_set_end_dependent(device_t dev, void *context)
  603 {
  604     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  605 
  606     if (cp == NULL)
  607         return;
  608     device_printf(dev, "dependent functions not supported\n");
  609 }
  610 
  611 /*
  612  * Resource-owning placeholders for IO and memory pseudo-devices.
  613  *
  614  * This code allocates system resources that will be used by ACPI
  615  * child devices.  The acpi parent manages these resources through a
  616  * private rman.
  617  */
  618 
  619 static int      acpi_sysres_rid = 100;
  620 
  621 static int      acpi_sysres_probe(device_t dev);
  622 static int      acpi_sysres_attach(device_t dev);
  623 
  624 static device_method_t acpi_sysres_methods[] = {
  625     /* Device interface */
  626     DEVMETHOD(device_probe,     acpi_sysres_probe),
  627     DEVMETHOD(device_attach,    acpi_sysres_attach),
  628 
  629     DEVMETHOD_END
  630 };
  631 
  632 static driver_t acpi_sysres_driver = {
  633     "acpi_sysresource",
  634     acpi_sysres_methods,
  635     0,
  636 };
  637 
  638 static devclass_t acpi_sysres_devclass;
  639 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
  640     0, 0);
  641 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
  642 
  643 static int
  644 acpi_sysres_probe(device_t dev)
  645 {
  646     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
  647 
  648     if (acpi_disabled("sysresource") ||
  649         ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
  650         return (ENXIO);
  651 
  652     device_set_desc(dev, "System Resource");
  653     device_quiet(dev);
  654     return (BUS_PROBE_DEFAULT);
  655 }
  656 
  657 static int
  658 acpi_sysres_attach(device_t dev)
  659 {
  660     device_t bus;
  661     struct resource_list_entry *bus_rle, *dev_rle;
  662     struct resource_list *bus_rl, *dev_rl;
  663     int done, type;
  664     u_long start, end, count;
  665 
  666     /*
  667      * Loop through all current resources to see if the new one overlaps
  668      * any existing ones.  If so, grow the old one up and/or down
  669      * accordingly.  Discard any that are wholly contained in the old.  If
  670      * the resource is unique, add it to the parent.  It will later go into
  671      * the rman pool.
  672      */
  673     bus = device_get_parent(dev);
  674     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
  675     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
  676     STAILQ_FOREACH(dev_rle, dev_rl, link) {
  677         if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
  678             continue;
  679 
  680         start = dev_rle->start;
  681         end = dev_rle->end;
  682         count = dev_rle->count;
  683         type = dev_rle->type;
  684         done = FALSE;
  685 
  686         STAILQ_FOREACH(bus_rle, bus_rl, link) {
  687             if (bus_rle->type != type)
  688                 continue;
  689 
  690             /* New resource wholly contained in old, discard. */
  691             if (start >= bus_rle->start && end <= bus_rle->end)
  692                 break;
  693 
  694             /* New tail overlaps old head, grow existing resource downward. */
  695             if (start < bus_rle->start && end >= bus_rle->start) {
  696                 bus_rle->count += bus_rle->start - start;
  697                 bus_rle->start = start;
  698                 done = TRUE;
  699             }
  700 
  701             /* New head overlaps old tail, grow existing resource upward. */
  702             if (start <= bus_rle->end && end > bus_rle->end) {
  703                 bus_rle->count += end - bus_rle->end;
  704                 bus_rle->end = end;
  705                 done = TRUE;
  706             }
  707 
  708             /* If we adjusted the old resource, we're finished. */
  709             if (done)
  710                 break;
  711         }
  712 
  713         /* If we didn't merge with anything, add this resource. */
  714         if (bus_rle == NULL)
  715             bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
  716     }
  717 
  718     /* After merging/moving resources to the parent, free the list. */
  719     resource_list_free(dev_rl);
  720 
  721     return (0);
  722 }

Cache object: 7ed64f1767a98e46e593d02e61dcb134


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.