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.2/sys/dev/acpica/acpi_resource.c 333080 2018-04-28 00:16:54Z 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 
  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 
  529     /*
  530      * XXX: Some BIOSes contain buggy _CRS entries where fixed I/O
  531      * ranges have the maximum base address (_MAX) to the end of the
  532      * I/O range instead of the start.  These are then treated as a
  533      * relocatable I/O range rather than a fixed I/O resource.  As a
  534      * workaround, treat I/O resources encoded this way as fixed I/O
  535      * ports.
  536      */
  537     if (high == (low + length)) {
  538         if (bootverbose)
  539             device_printf(dev,
  540                 "_CRS has fixed I/O port range defined as relocatable\n");
  541 
  542         bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, low, length);
  543         return;
  544     }
  545 
  546     device_printf(dev, "I/O range not supported\n");
  547 }
  548 
  549 static void
  550 acpi_res_set_memory(device_t dev, void *context, uint64_t base,
  551                     uint64_t length)
  552 {
  553     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  554 
  555     if (cp == NULL)
  556         return;
  557 
  558     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
  559 }
  560 
  561 static void
  562 acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
  563                          uint64_t high, uint64_t length, uint64_t align)
  564 {
  565     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  566 
  567     if (cp == NULL)
  568         return;
  569     device_printf(dev, "memory range not supported\n");
  570 }
  571 
  572 static void
  573 acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
  574     int trig, int pol)
  575 {
  576     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  577 
  578     if (cp == NULL || irq == NULL)
  579         return;
  580 
  581     /* This implements no resource relocation. */
  582     if (count != 1)
  583         return;
  584 
  585     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
  586 }
  587 
  588 static void
  589 acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
  590     int trig, int pol)
  591 {
  592     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  593 
  594     if (cp == NULL || irq == NULL)
  595         return;
  596 
  597     /* This implements no resource relocation. */
  598     if (count != 1)
  599         return;
  600 
  601     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
  602 }
  603 
  604 static void
  605 acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
  606 {
  607     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  608 
  609     if (cp == NULL || drq == NULL)
  610         return;
  611     
  612     /* This implements no resource relocation. */
  613     if (count != 1)
  614         return;
  615 
  616     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
  617 }
  618 
  619 static void
  620 acpi_res_set_start_dependent(device_t dev, void *context, int preference)
  621 {
  622     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  623 
  624     if (cp == NULL)
  625         return;
  626     device_printf(dev, "dependent functions not supported\n");
  627 }
  628 
  629 static void
  630 acpi_res_set_end_dependent(device_t dev, void *context)
  631 {
  632     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  633 
  634     if (cp == NULL)
  635         return;
  636     device_printf(dev, "dependent functions not supported\n");
  637 }
  638 
  639 /*
  640  * Resource-owning placeholders for IO and memory pseudo-devices.
  641  *
  642  * This code allocates system resources that will be used by ACPI
  643  * child devices.  The acpi parent manages these resources through a
  644  * private rman.
  645  */
  646 
  647 static int      acpi_sysres_rid = 100;
  648 
  649 static int      acpi_sysres_probe(device_t dev);
  650 static int      acpi_sysres_attach(device_t dev);
  651 
  652 static device_method_t acpi_sysres_methods[] = {
  653     /* Device interface */
  654     DEVMETHOD(device_probe,     acpi_sysres_probe),
  655     DEVMETHOD(device_attach,    acpi_sysres_attach),
  656 
  657     DEVMETHOD_END
  658 };
  659 
  660 static driver_t acpi_sysres_driver = {
  661     "acpi_sysresource",
  662     acpi_sysres_methods,
  663     0,
  664 };
  665 
  666 static devclass_t acpi_sysres_devclass;
  667 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
  668     0, 0);
  669 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
  670 
  671 static int
  672 acpi_sysres_probe(device_t dev)
  673 {
  674     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
  675 
  676     if (acpi_disabled("sysresource") ||
  677         ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
  678         return (ENXIO);
  679 
  680     device_set_desc(dev, "System Resource");
  681     device_quiet(dev);
  682     return (BUS_PROBE_DEFAULT);
  683 }
  684 
  685 static int
  686 acpi_sysres_attach(device_t dev)
  687 {
  688     device_t bus;
  689     struct resource_list_entry *bus_rle, *dev_rle;
  690     struct resource_list *bus_rl, *dev_rl;
  691     int done, type;
  692     rman_res_t start, end, count;
  693 
  694     /*
  695      * Loop through all current resources to see if the new one overlaps
  696      * any existing ones.  If so, grow the old one up and/or down
  697      * accordingly.  Discard any that are wholly contained in the old.  If
  698      * the resource is unique, add it to the parent.  It will later go into
  699      * the rman pool.
  700      */
  701     bus = device_get_parent(dev);
  702     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
  703     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
  704     STAILQ_FOREACH(dev_rle, dev_rl, link) {
  705         if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
  706             continue;
  707 
  708         start = dev_rle->start;
  709         end = dev_rle->end;
  710         count = dev_rle->count;
  711         type = dev_rle->type;
  712         done = FALSE;
  713 
  714         STAILQ_FOREACH(bus_rle, bus_rl, link) {
  715             if (bus_rle->type != type)
  716                 continue;
  717 
  718             /* New resource wholly contained in old, discard. */
  719             if (start >= bus_rle->start && end <= bus_rle->end)
  720                 break;
  721 
  722             /* New tail overlaps old head, grow existing resource downward. */
  723             if (start < bus_rle->start && end >= bus_rle->start) {
  724                 bus_rle->count += bus_rle->start - start;
  725                 bus_rle->start = start;
  726                 done = TRUE;
  727             }
  728 
  729             /* New head overlaps old tail, grow existing resource upward. */
  730             if (start <= bus_rle->end && end > bus_rle->end) {
  731                 bus_rle->count += end - bus_rle->end;
  732                 bus_rle->end = end;
  733                 done = TRUE;
  734             }
  735 
  736             /* If we adjusted the old resource, we're finished. */
  737             if (done)
  738                 break;
  739         }
  740 
  741         /* If we didn't merge with anything, add this resource. */
  742         if (bus_rle == NULL)
  743             bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
  744     }
  745 
  746     /* After merging/moving resources to the parent, free the list. */
  747     resource_list_free(dev_rl);
  748 
  749     return (0);
  750 }

Cache object: afb38eb74f3baed48e1719b65fa91f19


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