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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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: head/sys/dev/acpica/acpi_resource.c 346066 2019-04-09 21:18:02Z 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 #ifdef INTRNG
   49 #include "acpi_bus_if.h"
   50 #endif
   51 
   52 /* Hooks for the ACPI CA debugging infrastructure */
   53 #define _COMPONENT      ACPI_BUS
   54 ACPI_MODULE_NAME("RESOURCE")
   55 
   56 struct lookup_irq_request {
   57     ACPI_RESOURCE *acpi_res;
   58     u_int       irq;
   59     int         counter;
   60     int         rid;
   61     int         found;
   62     int         checkrid;
   63     int         trig;
   64     int         pol;
   65 };
   66 
   67 static ACPI_STATUS
   68 acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
   69 {
   70     struct lookup_irq_request *req;
   71     size_t len;
   72     u_int irqnum, irq, trig, pol;
   73 
   74     switch (res->Type) {
   75     case ACPI_RESOURCE_TYPE_IRQ:
   76         irqnum = res->Data.Irq.InterruptCount;
   77         irq = res->Data.Irq.Interrupts[0];
   78         len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
   79         trig = res->Data.Irq.Triggering;
   80         pol = res->Data.Irq.Polarity;
   81         break;
   82     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
   83         irqnum = res->Data.ExtendedIrq.InterruptCount;
   84         irq = res->Data.ExtendedIrq.Interrupts[0];
   85         len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
   86         trig = res->Data.ExtendedIrq.Triggering;
   87         pol = res->Data.ExtendedIrq.Polarity;
   88         break;
   89     default:
   90         return (AE_OK);
   91     }
   92     if (irqnum != 1)
   93         return (AE_OK);
   94     req = (struct lookup_irq_request *)context;
   95     if (req->checkrid) {
   96         if (req->counter != req->rid) {
   97             req->counter++;
   98             return (AE_OK);
   99         }
  100         KASSERT(irq == req->irq, ("IRQ resources do not match"));
  101     } else {
  102         if (req->irq != irq)
  103             return (AE_OK);
  104     }
  105     req->found = 1;
  106     req->pol = pol;
  107     req->trig = trig;
  108     if (req->acpi_res != NULL)
  109         bcopy(res, req->acpi_res, len);
  110     return (AE_CTRL_TERMINATE);
  111 }
  112 
  113 ACPI_STATUS
  114 acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
  115     ACPI_RESOURCE *acpi_res)
  116 {
  117     struct lookup_irq_request req;
  118     ACPI_STATUS status;
  119 
  120     req.acpi_res = acpi_res;
  121     req.irq = rman_get_start(res);
  122     req.counter = 0;
  123     req.rid = rid;
  124     req.found = 0;
  125     req.checkrid = 1;
  126     status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
  127         acpi_lookup_irq_handler, &req);
  128     if (ACPI_SUCCESS(status) && req.found == 0)
  129         status = AE_NOT_FOUND;
  130     return (status);
  131 }
  132 
  133 void
  134 acpi_config_intr(device_t dev, ACPI_RESOURCE *res)
  135 {
  136     u_int irq;
  137     int pol, trig;
  138 
  139     switch (res->Type) {
  140     case ACPI_RESOURCE_TYPE_IRQ:
  141         KASSERT(res->Data.Irq.InterruptCount == 1,
  142             ("%s: multiple interrupts", __func__));
  143         irq = res->Data.Irq.Interrupts[0];
  144         trig = res->Data.Irq.Triggering;
  145         pol = res->Data.Irq.Polarity;
  146         break;
  147     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  148         KASSERT(res->Data.ExtendedIrq.InterruptCount == 1,
  149             ("%s: multiple interrupts", __func__));
  150         irq = res->Data.ExtendedIrq.Interrupts[0];
  151         trig = res->Data.ExtendedIrq.Triggering;
  152         pol = res->Data.ExtendedIrq.Polarity;
  153         break;
  154     default:
  155         panic("%s: bad resource type %u", __func__, res->Type);
  156     }
  157 
  158 #if defined(__amd64__) || defined(__i386__)
  159     /*
  160      * XXX: Certain BIOSes have buggy AML that specify an IRQ that is
  161      * edge-sensitive and active-lo.  However, edge-sensitive IRQs
  162      * should be active-hi.  Force IRQs with an ISA IRQ value to be
  163      * active-hi instead.
  164      */
  165     if (irq < 16 && trig == ACPI_EDGE_SENSITIVE && pol == ACPI_ACTIVE_LOW)
  166         pol = ACPI_ACTIVE_HIGH;
  167 #endif
  168     BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ?
  169         INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
  170         INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
  171 }
  172 
  173 #ifdef INTRNG
  174 int
  175 acpi_map_intr(device_t dev, u_int irq, ACPI_HANDLE handle)
  176 {
  177     struct lookup_irq_request req;
  178     int trig, pol;
  179 
  180     trig = ACPI_LEVEL_SENSITIVE;
  181     pol = ACPI_ACTIVE_HIGH;
  182     if (handle != NULL) {
  183         req.found = 0;
  184         req.acpi_res = NULL;
  185         req.irq = irq;
  186         req.counter = 0;
  187         req.rid = 0;
  188         req.checkrid = 0;
  189         AcpiWalkResources(handle, "_CRS", acpi_lookup_irq_handler, &req);
  190         if (req.found != 0) {
  191             trig = req.trig;
  192             pol = req.pol;
  193         }
  194     }
  195     return ACPI_BUS_MAP_INTR(device_get_parent(dev), dev, irq,
  196         (trig == ACPI_EDGE_SENSITIVE) ?  INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL,
  197         (pol == ACPI_ACTIVE_HIGH) ?  INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
  198 }
  199 #endif
  200 
  201 struct acpi_resource_context {
  202     struct acpi_parse_resource_set *set;
  203     device_t    dev;
  204     void        *context;
  205     bool        ignore_producer_flag;
  206 };
  207 
  208 #ifdef ACPI_DEBUG_OUTPUT
  209 static const char *
  210 acpi_address_range_name(UINT8 ResourceType)
  211 {
  212     static char buf[16];
  213 
  214     switch (ResourceType) {
  215     case ACPI_MEMORY_RANGE:
  216             return ("Memory");
  217     case ACPI_IO_RANGE:
  218             return ("IO");
  219     case ACPI_BUS_NUMBER_RANGE:
  220             return ("Bus Number");
  221     default:
  222             snprintf(buf, sizeof(buf), "type %u", ResourceType);
  223             return (buf);
  224     }
  225 }
  226 #endif
  227             
  228 static ACPI_STATUS
  229 acpi_parse_resource(ACPI_RESOURCE *res, void *context)
  230 {
  231     struct acpi_parse_resource_set *set;
  232     struct acpi_resource_context *arc;
  233     UINT64 min, max, length, gran;
  234 #ifdef ACPI_DEBUG
  235     const char *name;
  236 #endif
  237     device_t dev;
  238 
  239     arc = context;
  240     dev = arc->dev;
  241     set = arc->set;
  242 
  243     switch (res->Type) {
  244     case ACPI_RESOURCE_TYPE_END_TAG:
  245         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
  246         break;
  247     case ACPI_RESOURCE_TYPE_FIXED_IO:
  248         if (res->Data.FixedIo.AddressLength <= 0)
  249             break;
  250         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
  251             res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength));
  252         set->set_ioport(dev, arc->context, res->Data.FixedIo.Address,
  253             res->Data.FixedIo.AddressLength);
  254         break;
  255     case ACPI_RESOURCE_TYPE_IO:
  256         if (res->Data.Io.AddressLength <= 0)
  257             break;
  258         if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
  259             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
  260                 res->Data.Io.Minimum, res->Data.Io.AddressLength));
  261             set->set_ioport(dev, arc->context, res->Data.Io.Minimum,
  262                 res->Data.Io.AddressLength);
  263         } else {
  264             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
  265                 res->Data.Io.Minimum, res->Data.Io.Maximum,
  266                 res->Data.Io.AddressLength));
  267             set->set_iorange(dev, arc->context, res->Data.Io.Minimum,
  268                 res->Data.Io.Maximum, res->Data.Io.AddressLength,
  269                 res->Data.Io.Alignment);
  270         }
  271         break;
  272     case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
  273         if (res->Data.FixedMemory32.AddressLength <= 0)
  274             break;
  275         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
  276             res->Data.FixedMemory32.Address,
  277             res->Data.FixedMemory32.AddressLength));
  278         set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address, 
  279             res->Data.FixedMemory32.AddressLength);
  280         break;
  281     case ACPI_RESOURCE_TYPE_MEMORY32:
  282         if (res->Data.Memory32.AddressLength <= 0)
  283             break;
  284         if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) {
  285             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
  286                 res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength));
  287             set->set_memory(dev, arc->context, res->Data.Memory32.Minimum,
  288                 res->Data.Memory32.AddressLength);
  289         } else {
  290             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
  291                 res->Data.Memory32.Minimum, res->Data.Memory32.Maximum,
  292                 res->Data.Memory32.AddressLength));
  293             set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum,
  294                 res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength,
  295                 res->Data.Memory32.Alignment);
  296         }
  297         break;
  298     case ACPI_RESOURCE_TYPE_MEMORY24:
  299         if (res->Data.Memory24.AddressLength <= 0)
  300             break;
  301         if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) {
  302             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
  303                 res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength));
  304             set->set_memory(dev, arc->context, res->Data.Memory24.Minimum,
  305                 res->Data.Memory24.AddressLength);
  306         } else {
  307             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
  308                 res->Data.Memory24.Minimum, res->Data.Memory24.Maximum,
  309                 res->Data.Memory24.AddressLength));
  310             set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum,
  311                 res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength,
  312                 res->Data.Memory24.Alignment);
  313         }
  314         break;
  315     case ACPI_RESOURCE_TYPE_IRQ:
  316         /*
  317          * from 1.0b 6.4.2 
  318          * "This structure is repeated for each separate interrupt
  319          * required"
  320          */
  321         set->set_irq(dev, arc->context, res->Data.Irq.Interrupts,
  322             res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
  323             res->Data.Irq.Polarity);
  324         break;
  325     case ACPI_RESOURCE_TYPE_DMA:
  326         /*
  327          * from 1.0b 6.4.3 
  328          * "This structure is repeated for each separate DMA channel
  329          * required"
  330          */
  331         set->set_drq(dev, arc->context, res->Data.Dma.Channels,
  332             res->Data.Dma.ChannelCount);
  333         break;
  334     case ACPI_RESOURCE_TYPE_START_DEPENDENT:
  335         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
  336         set->set_start_dependent(dev, arc->context,
  337             res->Data.StartDpf.CompatibilityPriority);
  338         break;
  339     case ACPI_RESOURCE_TYPE_END_DEPENDENT:
  340         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
  341         set->set_end_dependent(dev, arc->context);
  342         break;
  343     case ACPI_RESOURCE_TYPE_ADDRESS16:
  344     case ACPI_RESOURCE_TYPE_ADDRESS32:
  345     case ACPI_RESOURCE_TYPE_ADDRESS64:
  346     case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
  347         switch (res->Type) {
  348         case ACPI_RESOURCE_TYPE_ADDRESS16:
  349             gran = res->Data.Address16.Address.Granularity;
  350             min = res->Data.Address16.Address.Minimum;
  351             max = res->Data.Address16.Address.Maximum;
  352             length = res->Data.Address16.Address.AddressLength;
  353 #ifdef ACPI_DEBUG
  354             name = "Address16";
  355 #endif
  356             break;
  357         case ACPI_RESOURCE_TYPE_ADDRESS32:
  358             gran = res->Data.Address32.Address.Granularity;
  359             min = res->Data.Address32.Address.Minimum;
  360             max = res->Data.Address32.Address.Maximum;
  361             length = res->Data.Address32.Address.AddressLength;
  362 #ifdef ACPI_DEBUG
  363             name = "Address32";
  364 #endif
  365             break;
  366         case ACPI_RESOURCE_TYPE_ADDRESS64:
  367             gran = res->Data.Address64.Address.Granularity;
  368             min = res->Data.Address64.Address.Minimum;
  369             max = res->Data.Address64.Address.Maximum;
  370             length = res->Data.Address64.Address.AddressLength;
  371 #ifdef ACPI_DEBUG
  372             name = "Address64";
  373 #endif
  374             break;
  375         default:
  376             KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
  377                 ("should never happen"));
  378             gran = res->Data.ExtAddress64.Address.Granularity;
  379             min = res->Data.ExtAddress64.Address.Minimum;
  380             max = res->Data.ExtAddress64.Address.Maximum;
  381             length = res->Data.ExtAddress64.Address.AddressLength;
  382 #ifdef ACPI_DEBUG
  383             name = "ExtAddress64";
  384 #endif
  385             break;
  386         }
  387         if (length <= 0)
  388             break;
  389         if (!arc->ignore_producer_flag &&
  390             res->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
  391             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  392                 "ignored %s %s producer\n", name,
  393                 acpi_address_range_name(res->Data.Address.ResourceType)));
  394             break;
  395         }
  396         if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
  397             res->Data.Address.ResourceType != ACPI_IO_RANGE) {
  398             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  399                 "ignored %s for non-memory, non-I/O\n", name));
  400             break;
  401         }
  402 
  403 #ifdef __i386__
  404         if (min > ULONG_MAX || (res->Data.Address.MaxAddressFixed && max >
  405             ULONG_MAX)) {
  406             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s above 4G\n",
  407                 name));
  408             break;
  409         }
  410         if (max > ULONG_MAX)
  411                 max = ULONG_MAX;
  412 #endif
  413         if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED &&
  414             res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
  415             if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
  416                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n",
  417                     name, (uintmax_t)min, (uintmax_t)length));
  418                 set->set_memory(dev, arc->context, min, length);
  419             } else {
  420                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name,
  421                     (uintmax_t)min, (uintmax_t)length));
  422                 set->set_ioport(dev, arc->context, min, length);
  423             }
  424         } else {
  425             if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
  426                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  427                     "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
  428                     (uintmax_t)max, (uintmax_t)length));
  429                 set->set_memoryrange(dev, arc->context, min, max, length, gran);
  430             } else {
  431                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
  432                     name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
  433                 set->set_iorange(dev, arc->context, min, max, length, gran);
  434             }
  435         }                   
  436         break;
  437     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  438         if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
  439             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
  440             break;
  441         }
  442         set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
  443             res->Data.ExtendedIrq.InterruptCount,
  444             res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
  445         break;
  446     case ACPI_RESOURCE_TYPE_VENDOR:
  447         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  448             "unimplemented VendorSpecific resource\n"));
  449         break;
  450     default:
  451         break;
  452     }
  453     return (AE_OK);
  454 }
  455 
  456 /*
  457  * Fetch a device's resources and associate them with the device.
  458  *
  459  * Note that it might be nice to also locate ACPI-specific resource items, such
  460  * as GPE bits.
  461  *
  462  * We really need to split the resource-fetching code out from the
  463  * resource-parsing code, since we may want to use the parsing
  464  * code for _PRS someday.
  465  */
  466 ACPI_STATUS
  467 acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
  468                      struct acpi_parse_resource_set *set, void *arg)
  469 {
  470     struct acpi_resource_context arc;
  471     ACPI_STATUS         status;
  472 
  473     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  474 
  475     set->set_init(dev, arg, &arc.context);
  476     arc.set = set;
  477     arc.dev = dev;
  478     arc.ignore_producer_flag = false;
  479 
  480     /* UARTs on ThunderX2 set ResourceProducer on memory resources. */
  481     if (acpi_MatchHid(handle, "ARMH0011") != ACPI_MATCHHID_NOMATCH)
  482             arc.ignore_producer_flag = true;
  483 
  484     status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
  485     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
  486         printf("can't fetch resources for %s - %s\n",
  487             acpi_name(handle), AcpiFormatException(status));
  488         return_ACPI_STATUS (status);
  489     }
  490     set->set_done(dev, arc.context);
  491     return_ACPI_STATUS (AE_OK);
  492 }
  493 
  494 /*
  495  * Resource-set vectors used to attach _CRS-derived resources 
  496  * to an ACPI device.
  497  */
  498 static void     acpi_res_set_init(device_t dev, void *arg, void **context);
  499 static void     acpi_res_set_done(device_t dev, void *context);
  500 static void     acpi_res_set_ioport(device_t dev, void *context,
  501                                     uint64_t base, uint64_t length);
  502 static void     acpi_res_set_iorange(device_t dev, void *context,
  503                                      uint64_t low, uint64_t high, 
  504                                      uint64_t length, uint64_t align);
  505 static void     acpi_res_set_memory(device_t dev, void *context,
  506                                     uint64_t base, uint64_t length);
  507 static void     acpi_res_set_memoryrange(device_t dev, void *context,
  508                                          uint64_t low, uint64_t high, 
  509                                          uint64_t length, uint64_t align);
  510 static void     acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
  511                                  int count, int trig, int pol);
  512 static void     acpi_res_set_ext_irq(device_t dev, void *context,
  513                                  uint32_t *irq, int count, int trig, int pol);
  514 static void     acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
  515                                  int count);
  516 static void     acpi_res_set_start_dependent(device_t dev, void *context,
  517                                              int preference);
  518 static void     acpi_res_set_end_dependent(device_t dev, void *context);
  519 
  520 struct acpi_parse_resource_set acpi_res_parse_set = {
  521     acpi_res_set_init,
  522     acpi_res_set_done,
  523     acpi_res_set_ioport,
  524     acpi_res_set_iorange,
  525     acpi_res_set_memory,
  526     acpi_res_set_memoryrange,
  527     acpi_res_set_irq,
  528     acpi_res_set_ext_irq,
  529     acpi_res_set_drq,
  530     acpi_res_set_start_dependent,
  531     acpi_res_set_end_dependent
  532 };
  533 
  534 struct acpi_res_context {
  535     int         ar_nio;
  536     int         ar_nmem;
  537     int         ar_nirq;
  538     int         ar_ndrq;
  539     void        *ar_parent;
  540 };
  541 
  542 static void
  543 acpi_res_set_init(device_t dev, void *arg, void **context)
  544 {
  545     struct acpi_res_context     *cp;
  546 
  547     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
  548         bzero(cp, sizeof(*cp));
  549         cp->ar_parent = arg;
  550         *context = cp;
  551     }
  552 }
  553 
  554 static void
  555 acpi_res_set_done(device_t dev, void *context)
  556 {
  557     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  558 
  559     if (cp == NULL)
  560         return;
  561     AcpiOsFree(cp);
  562 }
  563 
  564 static void
  565 acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
  566                     uint64_t length)
  567 {
  568     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  569 
  570     if (cp == NULL)
  571         return;
  572     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
  573 }
  574 
  575 static void
  576 acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
  577                      uint64_t high, uint64_t length, uint64_t align)
  578 {
  579     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  580 
  581     if (cp == NULL)
  582         return;
  583 
  584     /*
  585      * XXX: Some BIOSes contain buggy _CRS entries where fixed I/O
  586      * ranges have the maximum base address (_MAX) to the end of the
  587      * I/O range instead of the start.  These are then treated as a
  588      * relocatable I/O range rather than a fixed I/O resource.  As a
  589      * workaround, treat I/O resources encoded this way as fixed I/O
  590      * ports.
  591      */
  592     if (high == (low + length)) {
  593         if (bootverbose)
  594             device_printf(dev,
  595                 "_CRS has fixed I/O port range defined as relocatable\n");
  596 
  597         bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, low, length);
  598         return;
  599     }
  600 
  601     device_printf(dev, "I/O range not supported\n");
  602 }
  603 
  604 static void
  605 acpi_res_set_memory(device_t dev, void *context, uint64_t base,
  606                     uint64_t length)
  607 {
  608     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  609 
  610     if (cp == NULL)
  611         return;
  612     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
  613 }
  614 
  615 static void
  616 acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
  617                          uint64_t high, uint64_t length, uint64_t align)
  618 {
  619     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  620 
  621     if (cp == NULL)
  622         return;
  623     device_printf(dev, "memory range not supported\n");
  624 }
  625 
  626 static void
  627 acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
  628     int trig, int pol)
  629 {
  630     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  631     rman_res_t intr;
  632 
  633     if (cp == NULL || irq == NULL)
  634         return;
  635 
  636     /* This implements no resource relocation. */
  637     if (count != 1)
  638         return;
  639 
  640     intr = *irq;
  641     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, intr, 1);
  642 }
  643 
  644 static void
  645 acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
  646     int trig, int pol)
  647 {
  648     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  649     rman_res_t intr;
  650 
  651     if (cp == NULL || irq == NULL)
  652         return;
  653 
  654     /* This implements no resource relocation. */
  655     if (count != 1)
  656         return;
  657 
  658     intr = *irq;
  659     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, intr, 1);
  660 }
  661 
  662 static void
  663 acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
  664 {
  665     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  666 
  667     if (cp == NULL || drq == NULL)
  668         return;
  669     
  670     /* This implements no resource relocation. */
  671     if (count != 1)
  672         return;
  673 
  674     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
  675 }
  676 
  677 static void
  678 acpi_res_set_start_dependent(device_t dev, void *context, int preference)
  679 {
  680     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  681 
  682     if (cp == NULL)
  683         return;
  684     device_printf(dev, "dependent functions not supported\n");
  685 }
  686 
  687 static void
  688 acpi_res_set_end_dependent(device_t dev, void *context)
  689 {
  690     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  691 
  692     if (cp == NULL)
  693         return;
  694     device_printf(dev, "dependent functions not supported\n");
  695 }
  696 
  697 /*
  698  * Resource-owning placeholders for IO and memory pseudo-devices.
  699  *
  700  * This code allocates system resources that will be used by ACPI
  701  * child devices.  The acpi parent manages these resources through a
  702  * private rman.
  703  */
  704 
  705 static int      acpi_sysres_rid = 100;
  706 
  707 static int      acpi_sysres_probe(device_t dev);
  708 static int      acpi_sysres_attach(device_t dev);
  709 
  710 static device_method_t acpi_sysres_methods[] = {
  711     /* Device interface */
  712     DEVMETHOD(device_probe,     acpi_sysres_probe),
  713     DEVMETHOD(device_attach,    acpi_sysres_attach),
  714 
  715     DEVMETHOD_END
  716 };
  717 
  718 static driver_t acpi_sysres_driver = {
  719     "acpi_sysresource",
  720     acpi_sysres_methods,
  721     0,
  722 };
  723 
  724 static devclass_t acpi_sysres_devclass;
  725 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
  726     0, 0);
  727 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
  728 
  729 static int
  730 acpi_sysres_probe(device_t dev)
  731 {
  732     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
  733     int rv;
  734 
  735     if (acpi_disabled("sysresource"))
  736         return (ENXIO);
  737     rv = ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids, NULL);
  738     if (rv > 0){
  739         return (rv);
  740     }
  741     device_set_desc(dev, "System Resource");
  742     device_quiet(dev);
  743     return (rv);
  744 }
  745 
  746 static int
  747 acpi_sysres_attach(device_t dev)
  748 {
  749     device_t bus;
  750     struct resource_list_entry *bus_rle, *dev_rle;
  751     struct resource_list *bus_rl, *dev_rl;
  752     int done, type;
  753     rman_res_t start, end, count;
  754 
  755     /*
  756      * Loop through all current resources to see if the new one overlaps
  757      * any existing ones.  If so, grow the old one up and/or down
  758      * accordingly.  Discard any that are wholly contained in the old.  If
  759      * the resource is unique, add it to the parent.  It will later go into
  760      * the rman pool.
  761      */
  762     bus = device_get_parent(dev);
  763     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
  764     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
  765     STAILQ_FOREACH(dev_rle, dev_rl, link) {
  766         if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
  767             continue;
  768 
  769         start = dev_rle->start;
  770         end = dev_rle->end;
  771         count = dev_rle->count;
  772         type = dev_rle->type;
  773         done = FALSE;
  774 
  775         STAILQ_FOREACH(bus_rle, bus_rl, link) {
  776             if (bus_rle->type != type)
  777                 continue;
  778 
  779             /* New resource wholly contained in old, discard. */
  780             if (start >= bus_rle->start && end <= bus_rle->end)
  781                 break;
  782 
  783             /* New tail overlaps old head, grow existing resource downward. */
  784             if (start < bus_rle->start && end >= bus_rle->start) {
  785                 bus_rle->count += bus_rle->start - start;
  786                 bus_rle->start = start;
  787                 done = TRUE;
  788             }
  789 
  790             /* New head overlaps old tail, grow existing resource upward. */
  791             if (start <= bus_rle->end && end > bus_rle->end) {
  792                 bus_rle->count += end - bus_rle->end;
  793                 bus_rle->end = end;
  794                 done = TRUE;
  795             }
  796 
  797             /* If we adjusted the old resource, we're finished. */
  798             if (done)
  799                 break;
  800         }
  801 
  802         /* If we didn't merge with anything, add this resource. */
  803         if (bus_rle == NULL)
  804             bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
  805     }
  806 
  807     /* After merging/moving resources to the parent, free the list. */
  808     resource_list_free(dev_rl);
  809 
  810     return (0);
  811 }

Cache object: 991701da5b5b94a0eb4da077f9d35096


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