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

Cache object: 0aea423adc4c88f3884b341eeea7383b


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