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/5.3/sys/dev/acpica/acpi_resource.c 134567 2004-08-31 05:26:37Z njl $");
   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             /* XXX special handling? */
  443             set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts,
  444                 res->Data.ExtendedIrq.NumberOfInterrupts,
  445                 res->Data.ExtendedIrq.EdgeLevel,
  446                 res->Data.ExtendedIrq.ActiveHighLow);
  447             break;
  448         case ACPI_RSTYPE_VENDOR:
  449             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
  450                              "unimplemented VendorSpecific resource\n"));
  451             break;
  452         default:
  453             break;
  454         }
  455     }    
  456 
  457     AcpiOsFree(buf.Pointer);
  458     set->set_done(dev, context);
  459     return_ACPI_STATUS (AE_OK);
  460 }
  461 
  462 /*
  463  * Resource-set vectors used to attach _CRS-derived resources 
  464  * to an ACPI device.
  465  */
  466 static void     acpi_res_set_init(device_t dev, void *arg, void **context);
  467 static void     acpi_res_set_done(device_t dev, void *context);
  468 static void     acpi_res_set_ioport(device_t dev, void *context,
  469                                     u_int32_t base, u_int32_t length);
  470 static void     acpi_res_set_iorange(device_t dev, void *context,
  471                                      u_int32_t low, u_int32_t high, 
  472                                      u_int32_t length, u_int32_t align);
  473 static void     acpi_res_set_memory(device_t dev, void *context,
  474                                     u_int32_t base, u_int32_t length);
  475 static void     acpi_res_set_memoryrange(device_t dev, void *context,
  476                                          u_int32_t low, u_int32_t high, 
  477                                          u_int32_t length, u_int32_t align);
  478 static void     acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq,
  479                                  int count, int trig, int pol);
  480 static void     acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq,
  481                                  int count);
  482 static void     acpi_res_set_start_dependant(device_t dev, void *context,
  483                                              int preference);
  484 static void     acpi_res_set_end_dependant(device_t dev, void *context);
  485 
  486 struct acpi_parse_resource_set acpi_res_parse_set = {
  487     acpi_res_set_init,
  488     acpi_res_set_done,
  489     acpi_res_set_ioport,
  490     acpi_res_set_iorange,
  491     acpi_res_set_memory,
  492     acpi_res_set_memoryrange,
  493     acpi_res_set_irq,
  494     acpi_res_set_drq,
  495     acpi_res_set_start_dependant,
  496     acpi_res_set_end_dependant
  497 };
  498 
  499 struct acpi_res_context {
  500     int         ar_nio;
  501     int         ar_nmem;
  502     int         ar_nirq;
  503     int         ar_ndrq;
  504     void        *ar_parent;
  505 };
  506 
  507 static void
  508 acpi_res_set_init(device_t dev, void *arg, void **context)
  509 {
  510     struct acpi_res_context     *cp;
  511 
  512     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
  513         bzero(cp, sizeof(*cp));
  514         cp->ar_parent = arg;
  515         *context = cp;
  516     }
  517 }
  518 
  519 static void
  520 acpi_res_set_done(device_t dev, void *context)
  521 {
  522     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  523 
  524     if (cp == NULL)
  525         return;
  526     AcpiOsFree(cp);
  527 }
  528 
  529 static void
  530 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
  531                     u_int32_t length)
  532 {
  533     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  534 
  535     if (cp == NULL)
  536         return;
  537     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
  538 }
  539 
  540 static void
  541 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low,
  542                      u_int32_t high, u_int32_t length, u_int32_t align)
  543 {
  544     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  545 
  546     if (cp == NULL)
  547         return;
  548     device_printf(dev, "I/O range not supported\n");
  549 }
  550 
  551 static void
  552 acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
  553                     u_int32_t length)
  554 {
  555     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  556 
  557     if (cp == NULL)
  558         return;
  559 
  560     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
  561 }
  562 
  563 static void
  564 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low,
  565                          u_int32_t high, u_int32_t length, u_int32_t align)
  566 {
  567     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  568 
  569     if (cp == NULL)
  570         return;
  571     device_printf(dev, "memory range not supported\n");
  572 }
  573 
  574 static void
  575 acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count,
  576     int trig, int pol)
  577 {
  578     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  579 
  580     if (cp == NULL || irq == NULL)
  581         return;
  582 
  583     /* This implements no resource relocation. */
  584     if (count != 1)
  585         return;
  586 
  587     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
  588 }
  589 
  590 static void
  591 acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
  592 {
  593     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  594 
  595     if (cp == NULL || drq == NULL)
  596         return;
  597     
  598     /* This implements no resource relocation. */
  599     if (count != 1)
  600         return;
  601 
  602     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
  603 }
  604 
  605 static void
  606 acpi_res_set_start_dependant(device_t dev, void *context, int preference)
  607 {
  608     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  609 
  610     if (cp == NULL)
  611         return;
  612     device_printf(dev, "dependant functions not supported\n");
  613 }
  614 
  615 static void
  616 acpi_res_set_end_dependant(device_t dev, void *context)
  617 {
  618     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
  619 
  620     if (cp == NULL)
  621         return;
  622     device_printf(dev, "dependant functions not supported\n");
  623 }
  624 
  625 /*
  626  * Resource-owning placeholders for IO and memory pseudo-devices.
  627  *
  628  * This code allocates system resources that will be used by ACPI
  629  * child devices.  The acpi parent manages these resources through a
  630  * private rman.
  631  */
  632 
  633 static int      acpi_sysres_rid = 100;
  634 
  635 static int      acpi_sysres_probe(device_t dev);
  636 static int      acpi_sysres_attach(device_t dev);
  637 
  638 static device_method_t acpi_sysres_methods[] = {
  639     /* Device interface */
  640     DEVMETHOD(device_probe,     acpi_sysres_probe),
  641     DEVMETHOD(device_attach,    acpi_sysres_attach),
  642 
  643     {0, 0}
  644 };
  645 
  646 static driver_t acpi_sysres_driver = {
  647     "acpi_sysresource",
  648     acpi_sysres_methods,
  649     0,
  650 };
  651 
  652 static devclass_t acpi_sysres_devclass;
  653 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
  654     0, 0);
  655 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
  656 
  657 static int
  658 acpi_sysres_probe(device_t dev)
  659 {
  660     static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
  661 
  662     if (acpi_disabled("sysresource") ||
  663         ACPI_ID_PROBE(device_get_parent(dev), dev, sysres_ids) == NULL)
  664         return (ENXIO);
  665 
  666     device_set_desc(dev, "System Resource");
  667     device_quiet(dev);
  668     return (-100);
  669 }
  670 
  671 static int
  672 acpi_sysres_attach(device_t dev)
  673 {
  674     device_t bus;
  675     struct resource_list_entry *bus_rle, *dev_rle;
  676     struct resource_list *bus_rl, *dev_rl;
  677     int done, type;
  678     u_long start, end, count;
  679 
  680     /*
  681      * Loop through all current resources to see if the new one overlaps
  682      * any existing ones.  If so, grow the old one up and/or down
  683      * accordingly.  Discard any that are wholly contained in the old.  If
  684      * the resource is unique, add it to the parent.  It will later go into
  685      * the rman pool.
  686      */
  687     bus = device_get_parent(dev);
  688     dev_rl = BUS_GET_RESOURCE_LIST(bus, dev);
  689     bus_rl = BUS_GET_RESOURCE_LIST(device_get_parent(bus), bus);
  690     SLIST_FOREACH(dev_rle, dev_rl, link) {
  691         if (dev_rle->type != SYS_RES_IOPORT && dev_rle->type != SYS_RES_MEMORY)
  692             continue;
  693 
  694         start = dev_rle->start;
  695         end = dev_rle->end;
  696         count = dev_rle->count;
  697         type = dev_rle->type;
  698         done = FALSE;
  699 
  700         SLIST_FOREACH(bus_rle, bus_rl, link) {
  701             if (bus_rle->type != type)
  702                 continue;
  703 
  704             /* New resource wholly contained in old, discard. */
  705             if (start >= bus_rle->start && end <= bus_rle->end)
  706                 break;
  707 
  708             /* New tail overlaps old head, grow existing resource downward. */
  709             if (start < bus_rle->start && end >= bus_rle->start) {
  710                 bus_rle->count += bus_rle->start - start;
  711                 bus_rle->start = start;
  712                 done = TRUE;
  713             }
  714 
  715             /* New head overlaps old tail, grow existing resource upward. */
  716             if (start <= bus_rle->end && end > bus_rle->end) {
  717                 bus_rle->count += end - bus_rle->end;
  718                 bus_rle->end = end;
  719                 done = TRUE;
  720             }
  721 
  722             /* If we adjusted the old resource, we're finished. */
  723             if (done)
  724                 break;
  725         }
  726 
  727         /* If we didn't merge with anything, add this resource. */
  728         if (bus_rle == NULL)
  729             bus_set_resource(bus, type, acpi_sysres_rid++, start, count);
  730     }
  731 
  732     /* After merging/moving resources to the parent, free the list. */
  733     resource_list_free(dev_rl);
  734 
  735     return (0);
  736 }

Cache object: 04fca5208b2a15b9c6f2b9a976b7f098


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