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

Cache object: beb26c4f697425b338724d4336d6bb4f


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