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/9.0/sys/dev/acpica/acpi_resource.c 223383 2011-06-21 21:30:20Z jhb $");
   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     BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ?
  139         INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
  140         INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
  141 }
  142 
  143 struct acpi_resource_context {
  144     struct acpi_parse_resource_set *set;
  145     device_t    dev;
  146     void        *context;
  147 };
  148 
  149 #ifdef ACPI_DEBUG_OUTPUT
  150 static const char *
  151 acpi_address_range_name(UINT8 ResourceType)
  152 {
  153     static char buf[16];
  154 
  155     switch (ResourceType) {
  156     case ACPI_MEMORY_RANGE:
  157             return ("Memory");
  158     case ACPI_IO_RANGE:
  159             return ("IO");
  160     case ACPI_BUS_NUMBER_RANGE:
  161             return ("Bus Number");
  162     default:
  163             snprintf(buf, sizeof(buf), "type %u", ResourceType);
  164             return (buf);
  165     }
  166 }
  167 #endif
  168             
  169 static ACPI_STATUS
  170 acpi_parse_resource(ACPI_RESOURCE *res, void *context)
  171 {
  172     struct acpi_parse_resource_set *set;
  173     struct acpi_resource_context *arc;
  174     UINT64 min, max, length, gran;
  175     const char *name;
  176     device_t dev;
  177 
  178     arc = context;
  179     dev = arc->dev;
  180     set = arc->set;
  181 
  182     switch (res->Type) {
  183     case ACPI_RESOURCE_TYPE_END_TAG:
  184         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
  185         break;
  186     case ACPI_RESOURCE_TYPE_FIXED_IO:
  187         if (res->Data.FixedIo.AddressLength <= 0)
  188             break;
  189         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
  190             res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength));
  191         set->set_ioport(dev, arc->context, res->Data.FixedIo.Address,
  192             res->Data.FixedIo.AddressLength);
  193         break;
  194     case ACPI_RESOURCE_TYPE_IO:
  195         if (res->Data.Io.AddressLength <= 0)
  196             break;
  197         if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
  198             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
  199                 res->Data.Io.Minimum, res->Data.Io.AddressLength));
  200             set->set_ioport(dev, arc->context, res->Data.Io.Minimum,
  201                 res->Data.Io.AddressLength);
  202         } else {
  203             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
  204                 res->Data.Io.Minimum, res->Data.Io.Maximum,
  205                 res->Data.Io.AddressLength));
  206             set->set_iorange(dev, arc->context, res->Data.Io.Minimum,
  207                 res->Data.Io.Maximum, res->Data.Io.AddressLength,
  208                 res->Data.Io.Alignment);
  209         }
  210         break;
  211     case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
  212         if (res->Data.FixedMemory32.AddressLength <= 0)
  213             break;
  214         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
  215             res->Data.FixedMemory32.Address,
  216             res->Data.FixedMemory32.AddressLength));
  217         set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address, 
  218             res->Data.FixedMemory32.AddressLength);
  219         break;
  220     case ACPI_RESOURCE_TYPE_MEMORY32:
  221         if (res->Data.Memory32.AddressLength <= 0)
  222             break;
  223         if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) {
  224             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
  225                 res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength));
  226             set->set_memory(dev, arc->context, res->Data.Memory32.Minimum,
  227                 res->Data.Memory32.AddressLength);
  228         } else {
  229             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
  230                 res->Data.Memory32.Minimum, res->Data.Memory32.Maximum,
  231                 res->Data.Memory32.AddressLength));
  232             set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum,
  233                 res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength,
  234                 res->Data.Memory32.Alignment);
  235         }
  236         break;
  237     case ACPI_RESOURCE_TYPE_MEMORY24:
  238         if (res->Data.Memory24.AddressLength <= 0)
  239             break;
  240         if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) {
  241             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
  242                 res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength));
  243             set->set_memory(dev, arc->context, res->Data.Memory24.Minimum,
  244                 res->Data.Memory24.AddressLength);
  245         } else {
  246             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
  247                 res->Data.Memory24.Minimum, res->Data.Memory24.Maximum,
  248                 res->Data.Memory24.AddressLength));
  249             set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum,
  250                 res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength,
  251                 res->Data.Memory24.Alignment);
  252         }
  253         break;
  254     case ACPI_RESOURCE_TYPE_IRQ:
  255         /*
  256          * from 1.0b 6.4.2 
  257          * "This structure is repeated for each separate interrupt
  258          * required"
  259          */
  260         set->set_irq(dev, arc->context, res->Data.Irq.Interrupts,
  261             res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
  262             res->Data.Irq.Polarity);
  263         break;
  264     case ACPI_RESOURCE_TYPE_DMA:
  265         /*
  266          * from 1.0b 6.4.3 
  267          * "This structure is repeated for each separate DMA channel
  268          * required"
  269          */
  270         set->set_drq(dev, arc->context, res->Data.Dma.Channels,
  271             res->Data.Dma.ChannelCount);
  272         break;
  273     case ACPI_RESOURCE_TYPE_START_DEPENDENT:
  274         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
  275         set->set_start_dependent(dev, arc->context,
  276             res->Data.StartDpf.CompatibilityPriority);
  277         break;
  278     case ACPI_RESOURCE_TYPE_END_DEPENDENT:
  279         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
  280         set->set_end_dependent(dev, arc->context);
  281         break;
  282     case ACPI_RESOURCE_TYPE_ADDRESS16:
  283     case ACPI_RESOURCE_TYPE_ADDRESS32:
  284     case ACPI_RESOURCE_TYPE_ADDRESS64:
  285     case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
  286         switch (res->Type) {
  287         case ACPI_RESOURCE_TYPE_ADDRESS16:
  288             gran = res->Data.Address16.Granularity;
  289             min = res->Data.Address16.Minimum;
  290             max = res->Data.Address16.Maximum;
  291             length = res->Data.Address16.AddressLength;
  292             name = "Address16";
  293             break;
  294         case ACPI_RESOURCE_TYPE_ADDRESS32:
  295             gran = res->Data.Address32.Granularity;
  296             min = res->Data.Address32.Minimum;
  297             max = res->Data.Address32.Maximum;
  298             length = res->Data.Address32.AddressLength;
  299             name = "Address32";
  300             break;
  301         case ACPI_RESOURCE_TYPE_ADDRESS64:
  302             gran = res->Data.Address64.Granularity;
  303             min = res->Data.Address64.Minimum;
  304             max = res->Data.Address64.Maximum;
  305             length = res->Data.Address64.AddressLength;
  306             name = "Address64";
  307             break;
  308         default:
  309             KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
  310                 ("should never happen"));
  311             gran = res->Data.ExtAddress64.Granularity;
  312             min = res->Data.ExtAddress64.Minimum;
  313             max = res->Data.ExtAddress64.Maximum;
  314             length = res->Data.ExtAddress64.AddressLength;
  315             name = "ExtAddress64";
  316             break;
  317         }
  318         if (length <= 0)
  319             break;
  320         if (res->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
  321             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  322                 "ignored %s %s producer\n", name,
  323                 acpi_address_range_name(res->Data.Address.ResourceType)));
  324             break;
  325         }
  326         if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
  327             res->Data.Address.ResourceType != ACPI_IO_RANGE) {
  328             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  329                 "ignored %s for non-memory, non-I/O\n", name));
  330             break;
  331         }
  332 
  333 #ifdef __i386__
  334         if (min > ULONG_MAX || (res->Data.Address.MaxAddressFixed && max >
  335             ULONG_MAX)) {
  336             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s above 4G\n",
  337                 name));
  338             break;
  339         }
  340         if (max > ULONG_MAX)
  341                 max = ULONG_MAX;
  342 #endif
  343         if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED &&
  344             res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
  345             if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
  346                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n",
  347                     name, (uintmax_t)min, (uintmax_t)length));
  348                 set->set_memory(dev, arc->context, min, length);
  349             } else {
  350                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name,
  351                     (uintmax_t)min, (uintmax_t)length));
  352                 set->set_ioport(dev, arc->context, min, length);
  353             }
  354         } else {
  355             if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
  356                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  357                     "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
  358                     (uintmax_t)max, (uintmax_t)length));
  359                 set->set_memoryrange(dev, arc->context, min, max, length, gran);
  360             } else {
  361                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
  362                     name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
  363                 set->set_iorange(dev, arc->context, min, max, length, gran);
  364             }
  365         }                   
  366         break;
  367     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  368         if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
  369             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
  370             break;
  371         }
  372         set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
  373             res->Data.ExtendedIrq.InterruptCount,
  374             res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
  375         break;
  376     case ACPI_RESOURCE_TYPE_VENDOR:
  377         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  378             "unimplemented VendorSpecific resource\n"));
  379         break;
  380     default:
  381         break;
  382     }
  383     return (AE_OK);
  384 }
  385 
  386 /*
  387  * Fetch a device's resources and associate them with the device.
  388  *
  389  * Note that it might be nice to also locate ACPI-specific resource items, such
  390  * as GPE bits.
  391  *
  392  * We really need to split the resource-fetching code out from the
  393  * resource-parsing code, since we may want to use the parsing
  394  * code for _PRS someday.
  395  */
  396 ACPI_STATUS
  397 acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
  398                      struct acpi_parse_resource_set *set, void *arg)
  399 {
  400     struct acpi_resource_context arc;
  401     ACPI_STATUS         status;
  402 
  403     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  404 
  405     set->set_init(dev, arg, &arc.context);
  406     arc.set = set;
  407     arc.dev = dev;
  408     status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
  409     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
  410         printf("can't fetch resources for %s - %s\n",
  411             acpi_name(handle), AcpiFormatException(status));
  412         return_ACPI_STATUS (status);
  413     }
  414     set->set_done(dev, arc.context);
  415     return_ACPI_STATUS (AE_OK);
  416 }
  417 
  418 /*
  419  * Resource-set vectors used to attach _CRS-derived resources 
  420  * to an ACPI device.
  421  */
  422 static void     acpi_res_set_init(device_t dev, void *arg, void **context);
  423 static void     acpi_res_set_done(device_t dev, void *context);
  424 static void     acpi_res_set_ioport(device_t dev, void *context,
  425                                     uint64_t base, uint64_t length);
  426 static void     acpi_res_set_iorange(device_t dev, void *context,
  427                                      uint64_t low, uint64_t high, 
  428                                      uint64_t length, uint64_t align);
  429 static void     acpi_res_set_memory(device_t dev, void *context,
  430                                     uint64_t base, uint64_t length);
  431 static void     acpi_res_set_memoryrange(device_t dev, void *context,
  432                                          uint64_t low, uint64_t high, 
  433                                          uint64_t length, uint64_t align);
  434 static void     acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
  435                                  int count, int trig, int pol);
  436 static void     acpi_res_set_ext_irq(device_t dev, void *context,
  437                                  uint32_t *irq, int count, int trig, int pol);
  438 static void     acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
  439                                  int count);
  440 static void     acpi_res_set_start_dependent(device_t dev, void *context,
  441                                              int preference);
  442 static void     acpi_res_set_end_dependent(device_t dev, void *context);
  443 
  444 struct acpi_parse_resource_set acpi_res_parse_set = {
  445     acpi_res_set_init,
  446     acpi_res_set_done,
  447     acpi_res_set_ioport,
  448     acpi_res_set_iorange,
  449     acpi_res_set_memory,
  450     acpi_res_set_memoryrange,
  451     acpi_res_set_irq,
  452     acpi_res_set_ext_irq,
  453     acpi_res_set_drq,
  454     acpi_res_set_start_dependent,
  455     acpi_res_set_end_dependent
  456 };
  457 
  458 struct acpi_res_context {
  459     int         ar_nio;
  460     int         ar_nmem;
  461     int         ar_nirq;
  462     int         ar_ndrq;
  463     void        *ar_parent;
  464 };
  465 
  466 static void
  467 acpi_res_set_init(device_t dev, void *arg, void **context)
  468 {
  469     struct acpi_res_context     *cp;
  470 
  471     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
  472         bzero(cp, sizeof(*cp));
  473         cp->ar_parent = arg;
  474         *context = cp;
  475     }
  476 }
  477 
  478 static void
  479 acpi_res_set_done(device_t dev, void *context)
  480 {
  481     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  482 
  483     if (cp == NULL)
  484         return;
  485     AcpiOsFree(cp);
  486 }
  487 
  488 static void
  489 acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
  490                     uint64_t length)
  491 {
  492     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  493 
  494     if (cp == NULL)
  495         return;
  496     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
  497 }
  498 
  499 static void
  500 acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
  501                      uint64_t high, uint64_t length, uint64_t align)
  502 {
  503     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  504 
  505     if (cp == NULL)
  506         return;
  507     device_printf(dev, "I/O range not supported\n");
  508 }
  509 
  510 static void
  511 acpi_res_set_memory(device_t dev, void *context, uint64_t base,
  512                     uint64_t length)
  513 {
  514     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  515 
  516     if (cp == NULL)
  517         return;
  518 
  519     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
  520 }
  521 
  522 static void
  523 acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
  524                          uint64_t high, uint64_t length, uint64_t align)
  525 {
  526     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  527 
  528     if (cp == NULL)
  529         return;
  530     device_printf(dev, "memory range not supported\n");
  531 }
  532 
  533 static void
  534 acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
  535     int trig, int pol)
  536 {
  537     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  538 
  539     if (cp == NULL || irq == NULL)
  540         return;
  541 
  542     /* This implements no resource relocation. */
  543     if (count != 1)
  544         return;
  545 
  546     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
  547 }
  548 
  549 static void
  550 acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
  551     int trig, int pol)
  552 {
  553     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  554 
  555     if (cp == NULL || irq == NULL)
  556         return;
  557 
  558     /* This implements no resource relocation. */
  559     if (count != 1)
  560         return;
  561 
  562     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
  563 }
  564 
  565 static void
  566 acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
  567 {
  568     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  569 
  570     if (cp == NULL || drq == NULL)
  571         return;
  572     
  573     /* This implements no resource relocation. */
  574     if (count != 1)
  575         return;
  576 
  577     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
  578 }
  579 
  580 static void
  581 acpi_res_set_start_dependent(device_t dev, void *context, int preference)
  582 {
  583     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  584 
  585     if (cp == NULL)
  586         return;
  587     device_printf(dev, "dependent functions not supported\n");
  588 }
  589 
  590 static void
  591 acpi_res_set_end_dependent(device_t dev, void *context)
  592 {
  593     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  594 
  595     if (cp == NULL)
  596         return;
  597     device_printf(dev, "dependent functions not supported\n");
  598 }
  599 
  600 /*
  601  * Resource-owning placeholders for IO and memory pseudo-devices.
  602  *
  603  * This code allocates system resources that will be used by ACPI
  604  * child devices.  The acpi parent manages these resources through a
  605  * private rman.
  606  */
  607 
  608 static int      acpi_sysres_rid = 100;
  609 
  610 static int      acpi_sysres_probe(device_t dev);
  611 static int      acpi_sysres_attach(device_t dev);
  612 
  613 static device_method_t acpi_sysres_methods[] = {
  614     /* Device interface */
  615     DEVMETHOD(device_probe,     acpi_sysres_probe),
  616     DEVMETHOD(device_attach,    acpi_sysres_attach),
  617 
  618     {0, 0}
  619 };
  620 
  621 static driver_t acpi_sysres_driver = {
  622     "acpi_sysresource",
  623     acpi_sysres_methods,
  624     0,
  625 };
  626 
  627 static devclass_t acpi_sysres_devclass;
  628 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
  629     0, 0);
  630 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
  631 
  632 static int
  633 acpi_sysres_probe(device_t dev)
  634 {
  635     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
  636 
  637     if (acpi_disabled("sysresource") ||
  638         ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
  639         return (ENXIO);
  640 
  641     device_set_desc(dev, "System Resource");
  642     device_quiet(dev);
  643     return (BUS_PROBE_DEFAULT);
  644 }
  645 
  646 static int
  647 acpi_sysres_attach(device_t dev)
  648 {
  649     device_t bus;
  650     struct resource_list_entry *bus_rle, *dev_rle;
  651     struct resource_list *bus_rl, *dev_rl;
  652     int done, type;
  653     u_long start, end, count;
  654 
  655     /*
  656      * Loop through all current resources to see if the new one overlaps
  657      * any existing ones.  If so, grow the old one up and/or down
  658      * accordingly.  Discard any that are wholly contained in the old.  If
  659      * the resource is unique, add it to the parent.  It will later go into
  660      * the rman pool.
  661      */
  662     bus = device_get_parent(dev);
  663     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
  664     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
  665     STAILQ_FOREACH(dev_rle, dev_rl, link) {
  666         if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
  667             continue;
  668 
  669         start = dev_rle->start;
  670         end = dev_rle->end;
  671         count = dev_rle->count;
  672         type = dev_rle->type;
  673         done = FALSE;
  674 
  675         STAILQ_FOREACH(bus_rle, bus_rl, link) {
  676             if (bus_rle->type != type)
  677                 continue;
  678 
  679             /* New resource wholly contained in old, discard. */
  680             if (start >= bus_rle->start && end <= bus_rle->end)
  681                 break;
  682 
  683             /* New tail overlaps old head, grow existing resource downward. */
  684             if (start < bus_rle->start && end >= bus_rle->start) {
  685                 bus_rle->count += bus_rle->start - start;
  686                 bus_rle->start = start;
  687                 done = TRUE;
  688             }
  689 
  690             /* New head overlaps old tail, grow existing resource upward. */
  691             if (start <= bus_rle->end && end > bus_rle->end) {
  692                 bus_rle->count += end - bus_rle->end;
  693                 bus_rle->end = end;
  694                 done = TRUE;
  695             }
  696 
  697             /* If we adjusted the old resource, we're finished. */
  698             if (done)
  699                 break;
  700         }
  701 
  702         /* If we didn't merge with anything, add this resource. */
  703         if (bus_rle == NULL)
  704             bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
  705     }
  706 
  707     /* After merging/moving resources to the parent, free the list. */
  708     resource_list_free(dev_rl);
  709 
  710     return (0);
  711 }

Cache object: 6ad3df537e058e7b0ab5265d54e889dc


[ 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.