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

Cache object: 2d18e5d076972319f28cc6908c34156b


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