The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/acpica/acpi_resource.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 60df5cd69b939ce7e9b13ba1b75565c0


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