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$");
   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 if (res->Data.Address.MinAddressFixed != ACPI_ADDRESS_FIXED &&
  425             res->Data.Address.MaxAddressFixed != ACPI_ADDRESS_FIXED) {
  426             /* Fixed size, variable location resource descriptor */
  427             min = roundup(min, gran + 1);
  428             if ((min + length - 1) > max) {
  429                 device_printf(dev,
  430                     "invalid memory range: start: %jx end: %jx max: %jx\n",
  431                     (uintmax_t)min, (uintmax_t)(min + length - 1),
  432                     (uintmax_t)max);
  433             } else {
  434                 if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) {
  435                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  436                         "%s/Memory 0x%jx/%ju\n", name, (uintmax_t)min,
  437                         (uintmax_t)length));
  438                     set->set_memory(dev, arc->context, min, length);
  439                 } else {
  440                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n",
  441                         name, (uintmax_t)min, (uintmax_t)length));
  442                     set->set_ioport(dev, arc->context, min, length);
  443                 }
  444             }
  445         } else {
  446             if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
  447                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  448                     "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min,
  449                     (uintmax_t)max, (uintmax_t)length));
  450                 set->set_memoryrange(dev, arc->context, min, max, length, gran);
  451             } else {
  452                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n",
  453                     name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length));
  454                 set->set_iorange(dev, arc->context, min, max, length, gran);
  455             }
  456         }                   
  457         break;
  458     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  459         if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
  460             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n"));
  461             break;
  462         }
  463         set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts,
  464             res->Data.ExtendedIrq.InterruptCount,
  465             res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity);
  466         break;
  467     case ACPI_RESOURCE_TYPE_VENDOR:
  468         ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  469             "unimplemented VendorSpecific resource\n"));
  470         break;
  471     default:
  472         break;
  473     }
  474     return (AE_OK);
  475 }
  476 
  477 /*
  478  * Fetch a device's resources and associate them with the device.
  479  *
  480  * Note that it might be nice to also locate ACPI-specific resource items, such
  481  * as GPE bits.
  482  *
  483  * We really need to split the resource-fetching code out from the
  484  * resource-parsing code, since we may want to use the parsing
  485  * code for _PRS someday.
  486  */
  487 ACPI_STATUS
  488 acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
  489                      struct acpi_parse_resource_set *set, void *arg)
  490 {
  491     struct acpi_resource_context arc;
  492     ACPI_STATUS         status;
  493 
  494     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  495 
  496     set->set_init(dev, arg, &arc.context);
  497     arc.set = set;
  498     arc.dev = dev;
  499     arc.ignore_producer_flag = false;
  500 
  501     /*
  502      * UARTs on ThunderX2 set ResourceProducer on memory resources, with
  503      * 7.2 firmware.
  504      */
  505     if (acpi_MatchHid(handle, "ARMH0011") != ACPI_MATCHHID_NOMATCH)
  506             arc.ignore_producer_flag = true;
  507 
  508     /*
  509      * ARM Coresight on N1SDP set ResourceProducer on memory resources.
  510      * Coresight devices: ETM, STM, TPIU, ETF/ETR, REP, FUN.
  511      */
  512     if (acpi_MatchHid(handle, "ARMHC500") != ACPI_MATCHHID_NOMATCH ||
  513         acpi_MatchHid(handle, "ARMHC502") != ACPI_MATCHHID_NOMATCH ||
  514         acpi_MatchHid(handle, "ARMHC600") != ACPI_MATCHHID_NOMATCH ||
  515         acpi_MatchHid(handle, "ARMHC979") != ACPI_MATCHHID_NOMATCH ||
  516         acpi_MatchHid(handle, "ARMHC97C") != ACPI_MATCHHID_NOMATCH ||
  517         acpi_MatchHid(handle, "ARMHC98D") != ACPI_MATCHHID_NOMATCH ||
  518         acpi_MatchHid(handle, "ARMHC9FF") != ACPI_MATCHHID_NOMATCH ||
  519         acpi_MatchHid(handle, "ARMHD620") != ACPI_MATCHHID_NOMATCH)
  520             arc.ignore_producer_flag = true;
  521 
  522     status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc);
  523     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
  524         printf("can't fetch resources for %s - %s\n",
  525             acpi_name(handle), AcpiFormatException(status));
  526         return_ACPI_STATUS (status);
  527     }
  528     set->set_done(dev, arc.context);
  529     return_ACPI_STATUS (AE_OK);
  530 }
  531 
  532 /*
  533  * Resource-set vectors used to attach _CRS-derived resources 
  534  * to an ACPI device.
  535  */
  536 static void     acpi_res_set_init(device_t dev, void *arg, void **context);
  537 static void     acpi_res_set_done(device_t dev, void *context);
  538 static void     acpi_res_set_ioport(device_t dev, void *context,
  539                                     uint64_t base, uint64_t length);
  540 static void     acpi_res_set_iorange(device_t dev, void *context,
  541                                      uint64_t low, uint64_t high, 
  542                                      uint64_t length, uint64_t align);
  543 static void     acpi_res_set_memory(device_t dev, void *context,
  544                                     uint64_t base, uint64_t length);
  545 static void     acpi_res_set_memoryrange(device_t dev, void *context,
  546                                          uint64_t low, uint64_t high, 
  547                                          uint64_t length, uint64_t align);
  548 static void     acpi_res_set_irq(device_t dev, void *context, uint8_t *irq,
  549                                  int count, int trig, int pol);
  550 static void     acpi_res_set_ext_irq(device_t dev, void *context,
  551                                  uint32_t *irq, int count, int trig, int pol);
  552 static void     acpi_res_set_drq(device_t dev, void *context, uint8_t *drq,
  553                                  int count);
  554 static void     acpi_res_set_start_dependent(device_t dev, void *context,
  555                                              int preference);
  556 static void     acpi_res_set_end_dependent(device_t dev, void *context);
  557 
  558 struct acpi_parse_resource_set acpi_res_parse_set = {
  559     acpi_res_set_init,
  560     acpi_res_set_done,
  561     acpi_res_set_ioport,
  562     acpi_res_set_iorange,
  563     acpi_res_set_memory,
  564     acpi_res_set_memoryrange,
  565     acpi_res_set_irq,
  566     acpi_res_set_ext_irq,
  567     acpi_res_set_drq,
  568     acpi_res_set_start_dependent,
  569     acpi_res_set_end_dependent
  570 };
  571 
  572 struct acpi_res_context {
  573     int         ar_nio;
  574     int         ar_nmem;
  575     int         ar_nirq;
  576     int         ar_ndrq;
  577     void        *ar_parent;
  578 };
  579 
  580 static void
  581 acpi_res_set_init(device_t dev, void *arg, void **context)
  582 {
  583     struct acpi_res_context     *cp;
  584 
  585     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
  586         bzero(cp, sizeof(*cp));
  587         cp->ar_parent = arg;
  588         *context = cp;
  589     }
  590 }
  591 
  592 static void
  593 acpi_res_set_done(device_t dev, void *context)
  594 {
  595     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  596 
  597     if (cp == NULL)
  598         return;
  599     AcpiOsFree(cp);
  600 }
  601 
  602 static void
  603 acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
  604                     uint64_t length)
  605 {
  606     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  607 
  608     if (cp == NULL)
  609         return;
  610     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
  611 }
  612 
  613 static void
  614 acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
  615                      uint64_t high, uint64_t length, uint64_t align)
  616 {
  617     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  618 
  619     if (cp == NULL)
  620         return;
  621 
  622     /*
  623      * XXX: Some BIOSes contain buggy _CRS entries where fixed I/O
  624      * ranges have the maximum base address (_MAX) to the end of the
  625      * I/O range instead of the start.  These are then treated as a
  626      * relocatable I/O range rather than a fixed I/O resource.  As a
  627      * workaround, treat I/O resources encoded this way as fixed I/O
  628      * ports.
  629      */
  630     if (high == (low + length)) {
  631         if (bootverbose)
  632             device_printf(dev,
  633                 "_CRS has fixed I/O port range defined as relocatable\n");
  634 
  635         bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, low, length);
  636         return;
  637     }
  638 
  639     device_printf(dev, "I/O range not supported\n");
  640 }
  641 
  642 static void
  643 acpi_res_set_memory(device_t dev, void *context, uint64_t base,
  644                     uint64_t length)
  645 {
  646     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  647 
  648     if (cp == NULL)
  649         return;
  650     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
  651 }
  652 
  653 static void
  654 acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low,
  655                          uint64_t high, uint64_t length, uint64_t align)
  656 {
  657     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  658 
  659     if (cp == NULL)
  660         return;
  661     device_printf(dev, "memory range not supported\n");
  662 }
  663 
  664 static void
  665 acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
  666     int trig, int pol)
  667 {
  668     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  669     int i;
  670 
  671     if (cp == NULL || irq == NULL)
  672         return;
  673 
  674     for (i = 0; i < count; i++)
  675         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
  676 }
  677 
  678 static void
  679 acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
  680     int trig, int pol)
  681 {
  682     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  683     int i;
  684 
  685     if (cp == NULL || irq == NULL)
  686         return;
  687 
  688     for (i = 0; i < count; i++)
  689         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
  690 }
  691 
  692 static void
  693 acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
  694 {
  695     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  696 
  697     if (cp == NULL || drq == NULL)
  698         return;
  699     
  700     /* This implements no resource relocation. */
  701     if (count != 1)
  702         return;
  703 
  704     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
  705 }
  706 
  707 static void
  708 acpi_res_set_start_dependent(device_t dev, void *context, int preference)
  709 {
  710     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  711 
  712     if (cp == NULL)
  713         return;
  714     device_printf(dev, "dependent functions not supported\n");
  715 }
  716 
  717 static void
  718 acpi_res_set_end_dependent(device_t dev, void *context)
  719 {
  720     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  721 
  722     if (cp == NULL)
  723         return;
  724     device_printf(dev, "dependent functions not supported\n");
  725 }
  726 
  727 /*
  728  * Resource-owning placeholders for IO and memory pseudo-devices.
  729  *
  730  * This code allocates system resources that will be used by ACPI
  731  * child devices.  The acpi parent manages these resources through a
  732  * private rman.
  733  */
  734 
  735 static int      acpi_sysres_rid = 100;
  736 
  737 static int      acpi_sysres_probe(device_t dev);
  738 static int      acpi_sysres_attach(device_t dev);
  739 
  740 static device_method_t acpi_sysres_methods[] = {
  741     /* Device interface */
  742     DEVMETHOD(device_probe,     acpi_sysres_probe),
  743     DEVMETHOD(device_attach,    acpi_sysres_attach),
  744 
  745     DEVMETHOD_END
  746 };
  747 
  748 static driver_t acpi_sysres_driver = {
  749     "acpi_sysresource",
  750     acpi_sysres_methods,
  751     0,
  752 };
  753 
  754 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, 0, 0);
  755 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
  756 
  757 static int
  758 acpi_sysres_probe(device_t dev)
  759 {
  760     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
  761     int rv;
  762 
  763     if (acpi_disabled("sysresource"))
  764         return (ENXIO);
  765     rv = ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids, NULL);
  766     if (rv > 0){
  767         return (rv);
  768     }
  769     device_set_desc(dev, "System Resource");
  770     device_quiet(dev);
  771     return (rv);
  772 }
  773 
  774 static int
  775 acpi_sysres_attach(device_t dev)
  776 {
  777     device_t bus;
  778     struct resource_list_entry *bus_rle, *dev_rle;
  779     struct resource_list *bus_rl, *dev_rl;
  780     int done, type;
  781     rman_res_t start, end, count;
  782 
  783     /*
  784      * Loop through all current resources to see if the new one overlaps
  785      * any existing ones.  If so, grow the old one up and/or down
  786      * accordingly.  Discard any that are wholly contained in the old.  If
  787      * the resource is unique, add it to the parent.  It will later go into
  788      * the rman pool.
  789      */
  790     bus = device_get_parent(dev);
  791     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
  792     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
  793     STAILQ_FOREACH(dev_rle, dev_rl, link) {
  794         if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
  795             continue;
  796 
  797         start = dev_rle->start;
  798         end = dev_rle->end;
  799         count = dev_rle->count;
  800         type = dev_rle->type;
  801         done = FALSE;
  802 
  803         STAILQ_FOREACH(bus_rle, bus_rl, link) {
  804             if (bus_rle->type != type)
  805                 continue;
  806 
  807             /* New resource wholly contained in old, discard. */
  808             if (start >= bus_rle->start && end <= bus_rle->end)
  809                 break;
  810 
  811             /* New tail overlaps old head, grow existing resource downward. */
  812             if (start < bus_rle->start && end >= bus_rle->start) {
  813                 bus_rle->count += bus_rle->start - start;
  814                 bus_rle->start = start;
  815                 done = TRUE;
  816             }
  817 
  818             /* New head overlaps old tail, grow existing resource upward. */
  819             if (start <= bus_rle->end && end > bus_rle->end) {
  820                 bus_rle->count += end - bus_rle->end;
  821                 bus_rle->end = end;
  822                 done = TRUE;
  823             }
  824 
  825             /* If we adjusted the old resource, we're finished. */
  826             if (done)
  827                 break;
  828         }
  829 
  830         /* If we didn't merge with anything, add this resource. */
  831         if (bus_rle == NULL)
  832             bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
  833     }
  834 
  835     /* After merging/moving resources to the parent, free the list. */
  836     resource_list_free(dev_rl);
  837 
  838     return (0);
  839 }

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.