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_pci_link.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) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/5.4/sys/dev/acpica/acpi_pci_link.c 137351 2004-11-07 20:24:06Z njl $");
   29 
   30 #include "opt_acpi.h"
   31 #include <sys/param.h>
   32 #include <sys/kernel.h>
   33 #include <sys/bus.h>
   34 
   35 #include "acpi.h"
   36 #include <dev/acpica/acpivar.h>
   37 #include <dev/acpica/acpi_pcibvar.h>
   38 
   39 #include <dev/pci/pcivar.h>
   40 #include "pcib_if.h"
   41 
   42 /* Hooks for the ACPI CA debugging infrastructure. */
   43 #define _COMPONENT      ACPI_BUS
   44 ACPI_MODULE_NAME("PCI_LINK")
   45 
   46 TAILQ_HEAD(acpi_pci_link_entries, acpi_pci_link_entry);
   47 static struct acpi_pci_link_entries acpi_pci_link_entries;
   48 ACPI_SERIAL_DECL(pci_link, "ACPI PCI link");
   49 
   50 TAILQ_HEAD(acpi_prt_entries, acpi_prt_entry);
   51 static struct acpi_prt_entries acpi_prt_entries;
   52 
   53 static int      irq_penalty[MAX_ACPI_INTERRUPTS];
   54 
   55 static int      acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link,
   56                     UINT8 irq);
   57 static void     acpi_pci_link_update_irq_penalty(device_t dev, int busno);
   58 static void     acpi_pci_link_set_bootdisabled_priority(void);
   59 static void     acpi_pci_link_fixup_bootdisabled_link(void);
   60 
   61 /*
   62  * PCI link object management
   63  */
   64 
   65 static void
   66 acpi_pci_link_dump_polarity(UINT32 ActiveHighLow)
   67 {
   68 
   69         switch (ActiveHighLow) {
   70         case ACPI_ACTIVE_HIGH:
   71                 printf("high,");
   72                 break;
   73         case ACPI_ACTIVE_LOW:
   74                 printf("low,");
   75                 break;
   76         default:
   77                 printf("unknown,");
   78                 break;
   79         }
   80 }
   81 
   82 static void
   83 acpi_pci_link_dump_trigger(UINT32 EdgeLevel)
   84 {
   85 
   86         switch (EdgeLevel) {
   87         case ACPI_EDGE_SENSITIVE:
   88                 printf("edge,");
   89                 break;
   90         case ACPI_LEVEL_SENSITIVE:
   91                 printf("level,");
   92                 break;
   93         default:
   94                 printf("unknown,");
   95                 break;
   96         }
   97 }
   98 
   99 static void
  100 acpi_pci_link_dump_sharemode(UINT32 SharedExclusive)
  101 {
  102 
  103         switch (SharedExclusive) {
  104         case ACPI_EXCLUSIVE:
  105                 printf("exclusive");
  106                 break;
  107         case ACPI_SHARED:
  108                 printf("sharable");
  109                 break;
  110         default:
  111                 printf("unknown");
  112                 break;
  113         }
  114 }
  115 
  116 static void
  117 acpi_pci_link_entry_dump(struct acpi_prt_entry *entry)
  118 {
  119         UINT8                   i;
  120         ACPI_RESOURCE_IRQ       *Irq;
  121         ACPI_RESOURCE_EXT_IRQ   *ExtIrq;
  122         struct acpi_pci_link_entry *link;
  123 
  124         if (entry == NULL || entry->pci_link == NULL)
  125                 return;
  126         link = entry->pci_link;
  127 
  128         printf("%s irq%c%2d: ", acpi_name(link->handle),
  129             (link->flags & ACPI_LINK_ROUTED) ? '*' : ' ', link->current_irq);
  130 
  131         printf("[");
  132         if (link->number_of_interrupts)
  133                 printf("%2d", link->interrupts[0]);
  134         for (i = 1; i < link->number_of_interrupts; i++)
  135                 printf("%3d", link->interrupts[i]);
  136         printf("] %2d+ ", link->initial_irq);
  137 
  138         switch (link->possible_resources.Id) {
  139         case ACPI_RSTYPE_IRQ:
  140                 Irq = &link->possible_resources.Data.Irq;
  141                 acpi_pci_link_dump_polarity(Irq->ActiveHighLow);
  142                 acpi_pci_link_dump_trigger(Irq->EdgeLevel);
  143                 acpi_pci_link_dump_sharemode(Irq->SharedExclusive);
  144                 break;
  145         case ACPI_RSTYPE_EXT_IRQ:
  146                 ExtIrq = &link->possible_resources.Data.ExtendedIrq;
  147                 acpi_pci_link_dump_polarity(ExtIrq->ActiveHighLow);
  148                 acpi_pci_link_dump_trigger(ExtIrq->EdgeLevel);
  149                 acpi_pci_link_dump_sharemode(ExtIrq->SharedExclusive);
  150                 break;
  151         }
  152 
  153         printf(" %d.%d.%d\n", entry->busno,
  154             (int)(ACPI_ADR_PCI_SLOT(entry->prt.Address)),
  155             (int)entry->prt.Pin);
  156 }
  157 
  158 static ACPI_STATUS
  159 acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta)
  160 {
  161         ACPI_DEVICE_INFO        *devinfo;
  162         ACPI_BUFFER             buf;
  163         ACPI_STATUS             error;
  164 
  165         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  166 
  167         if (handle == NULL || sta == NULL) {
  168                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
  169                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  170         }
  171 
  172         buf.Pointer = NULL;
  173         buf.Length = ACPI_ALLOCATE_BUFFER;
  174         error = AcpiGetObjectInfo(handle, &buf);
  175         if (ACPI_FAILURE(error)) {
  176                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  177                     "couldn't get object info %s - %s\n",
  178                     acpi_name(handle), AcpiFormatException(error)));
  179                 return_ACPI_STATUS (error);
  180         }
  181 
  182         devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
  183         if ((devinfo->Valid & ACPI_VALID_HID) == 0 ||
  184             strcmp(devinfo->HardwareId.Value, "PNP0C0F") != 0) {
  185                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid hardware ID - %s\n",
  186                     acpi_name(handle)));
  187                 AcpiOsFree(buf.Pointer);
  188                 return_ACPI_STATUS (AE_TYPE);
  189         }
  190 
  191         if ((devinfo->Valid & ACPI_VALID_STA) != 0) {
  192                 *sta = devinfo->CurrentStatus;
  193         } else {
  194                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid status - %s\n",
  195                     acpi_name(handle)));
  196                 *sta = 0;
  197         }
  198 
  199         AcpiOsFree(buf.Pointer);
  200         return_ACPI_STATUS (AE_OK);
  201 }
  202 
  203 static ACPI_STATUS
  204 acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources,
  205     UINT8 *number_of_interrupts, UINT8 interrupts[])
  206 {
  207         UINT8                   count;
  208         UINT8                   i;
  209         UINT32                  NumberOfInterrupts;
  210         UINT32                  *Interrupts;
  211 
  212         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  213 
  214         if (resources == NULL || number_of_interrupts == NULL) {
  215                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
  216                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  217         }
  218 
  219         *number_of_interrupts = 0;
  220         NumberOfInterrupts = 0;
  221         Interrupts = NULL;
  222 
  223         if (resources->Id == ACPI_RSTYPE_START_DPF)
  224                 resources = ACPI_NEXT_RESOURCE(resources);
  225 
  226         if (resources->Id != ACPI_RSTYPE_IRQ &&
  227             resources->Id != ACPI_RSTYPE_EXT_IRQ) {
  228                 printf("acpi link get: resource %d is not an IRQ\n",
  229                     resources->Id);
  230                 return_ACPI_STATUS (AE_TYPE);
  231         }
  232 
  233         switch (resources->Id) {
  234         case ACPI_RSTYPE_IRQ:
  235                 NumberOfInterrupts = resources->Data.Irq.NumberOfInterrupts;
  236                 Interrupts = resources->Data.Irq.Interrupts;
  237                 break;
  238         case ACPI_RSTYPE_EXT_IRQ:
  239                 NumberOfInterrupts =
  240                     resources->Data.ExtendedIrq.NumberOfInterrupts;
  241                 Interrupts = resources->Data.ExtendedIrq.Interrupts;
  242                 break;
  243         }
  244 
  245         if (NumberOfInterrupts == 0)
  246                 return_ACPI_STATUS (AE_NULL_ENTRY);
  247 
  248         count = 0;
  249         for (i = 0; i < NumberOfInterrupts; i++) {
  250                 if (i >= MAX_POSSIBLE_INTERRUPTS) {
  251                         ACPI_DEBUG_PRINT((ACPI_DB_WARN, "too many IRQs (%d)\n",
  252                             i));
  253                         break;
  254                 }
  255                 if (Interrupts[i] == 0) {
  256                         ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid IRQ %d\n",
  257                             Interrupts[i]));
  258                         continue;
  259                 }
  260                 interrupts[count] = Interrupts[i];
  261                 count++;
  262         }
  263         *number_of_interrupts = count;
  264 
  265         return_ACPI_STATUS (AE_OK);
  266 }
  267 
  268 static ACPI_STATUS
  269 acpi_pci_link_get_current_irq(struct acpi_pci_link_entry *link, UINT8 *irq)
  270 {
  271         ACPI_STATUS             error;
  272         ACPI_BUFFER             buf;
  273         ACPI_RESOURCE           *resources;
  274         UINT8                   number_of_interrupts;
  275         UINT8                   interrupts[MAX_POSSIBLE_INTERRUPTS];;
  276 
  277         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  278 
  279         if (link == NULL || irq == NULL) {
  280                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
  281                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  282         }
  283 
  284         *irq = 0;
  285         buf.Pointer = NULL;
  286         buf.Length = ACPI_ALLOCATE_BUFFER;
  287         error = AcpiGetCurrentResources(link->handle, &buf);
  288         if (ACPI_FAILURE(error)) {
  289                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  290                     "couldn't get PCI interrupt link device _CRS %s - %s\n",
  291                     acpi_name(link->handle), AcpiFormatException(error)));
  292                 return_ACPI_STATUS (error);
  293         }
  294         if (buf.Pointer == NULL) {
  295                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  296                     "couldn't allocate memory - %s\n",
  297                     acpi_name(link->handle)));
  298                 return_ACPI_STATUS (AE_NO_MEMORY);
  299         }
  300 
  301         resources = (ACPI_RESOURCE *) buf.Pointer;
  302         number_of_interrupts = 0;
  303         bzero(interrupts, sizeof(interrupts));
  304         error = acpi_pci_link_get_irq_resources(resources,
  305                     &number_of_interrupts, interrupts);
  306         AcpiOsFree(buf.Pointer);
  307 
  308         if (ACPI_FAILURE(error)) {
  309                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  310                     "couldn't get current IRQ from interrupt link %s - %s\n",
  311                     acpi_name(link->handle), AcpiFormatException(error)));
  312                 return_ACPI_STATUS (error);
  313         }
  314 
  315         if (number_of_interrupts == 0) {
  316                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  317                     "PCI interrupt link device _CRS data is corrupted - %s\n",
  318                     acpi_name(link->handle)));
  319                 return_ACPI_STATUS (AE_NULL_ENTRY);
  320         }
  321 
  322         *irq = interrupts[0];
  323 
  324         return_ACPI_STATUS (AE_OK);
  325 }
  326 
  327 static ACPI_STATUS
  328 acpi_pci_link_add_link(ACPI_HANDLE handle, struct acpi_prt_entry *entry)
  329 {
  330         ACPI_STATUS             error;
  331         ACPI_BUFFER             buf;
  332         ACPI_RESOURCE           *resources;
  333         struct acpi_pci_link_entry *link;
  334 
  335         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  336         ACPI_SERIAL_ASSERT(pci_link);
  337 
  338         entry->pci_link = NULL;
  339         TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
  340                 if (link->handle == handle) {
  341                         entry->pci_link = link;
  342                         link->references++;
  343                         return_ACPI_STATUS (AE_OK);
  344                 }
  345         }
  346 
  347         link = AcpiOsAllocate(sizeof(struct acpi_pci_link_entry));
  348         if (link == NULL) {
  349                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  350                     "couldn't allocate memory - %s\n", acpi_name(handle)));
  351                 return_ACPI_STATUS (AE_NO_MEMORY);
  352         }
  353 
  354         buf.Pointer = NULL;
  355         buf.Length = ACPI_ALLOCATE_BUFFER;
  356 
  357         bzero(link, sizeof(struct acpi_pci_link_entry));
  358         link->handle = handle;
  359 
  360         /*
  361          * Get the IRQ configured at boot-time.  If successful, set this
  362          * as the initial IRQ.
  363          */
  364         error = acpi_pci_link_get_current_irq(link, &link->current_irq);
  365         if (ACPI_SUCCESS(error)) {
  366                 link->initial_irq = link->current_irq;
  367         } else {
  368                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  369                     "couldn't get current IRQ from interrupt link %s - %s\n",
  370                     acpi_name(handle), AcpiFormatException(error)));
  371                 link->initial_irq = 0;
  372         }
  373 
  374         error = AcpiGetPossibleResources(handle, &buf);
  375         if (ACPI_FAILURE(error)) {
  376                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  377                     "couldn't get interrupt link device _PRS data %s - %s\n",
  378                     acpi_name(handle), AcpiFormatException(error)));
  379                 goto out;
  380         }
  381         if (buf.Pointer == NULL) {
  382                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  383                     "_PRS buffer is empty - %s\n", acpi_name(handle)));
  384                 error = AE_NO_MEMORY;
  385                 goto out;
  386         }
  387 
  388         /* Skip any DPF descriptors.  XXX We should centralize this code. */
  389         resources = (ACPI_RESOURCE *) buf.Pointer;
  390         if (resources->Id == ACPI_RSTYPE_START_DPF)
  391                 resources = ACPI_NEXT_RESOURCE(resources);
  392 
  393         /* XXX This only handles one resource, ignoring SourceIndex. */
  394         bcopy(resources, &link->possible_resources,
  395             sizeof(link->possible_resources));
  396 
  397         error = acpi_pci_link_get_irq_resources(resources,
  398             &link->number_of_interrupts, link->interrupts);
  399         if (ACPI_FAILURE(error)) {
  400                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  401                     "couldn't get possible IRQs from interrupt link %s - %s\n",
  402                     acpi_name(handle), AcpiFormatException(error)));
  403                 goto out;
  404         }
  405 
  406         if (link->number_of_interrupts == 0) {
  407                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  408                     "interrupt link device _PRS data is corrupted - %s\n",
  409                     acpi_name(handle)));
  410                 error = AE_NULL_ENTRY;
  411                 goto out;
  412         }
  413 
  414         /*
  415          * Try to disable this link.  If successful, set the current IRQ to
  416          * zero and flags to indicate this link is not routed.  If we can't
  417          * run _DIS (i.e., the method doesn't exist), assume the initial
  418          * IRQ was routed by the BIOS.
  419          *
  420          * XXX Since we detect link devices via _PRT entries but run long
  421          * after APIC mode has been enabled, we don't get a chance to
  422          * disable links that will be unused (especially in APIC mode).
  423          * Leaving them enabled can cause duplicate interrupts for some
  424          * devices.  The right fix is to probe links via their PNPID, so we
  425          * see them no matter what the _PRT says.
  426          */
  427         if (ACPI_SUCCESS(AcpiEvaluateObject(handle, "_DIS", NULL, NULL))) {
  428                 link->current_irq = 0;
  429                 link->flags = ACPI_LINK_NONE;
  430         } else
  431                 link->flags = ACPI_LINK_ROUTED;
  432 
  433         /*
  434          * If the initial IRQ is invalid (not in _PRS), set it to 0 and
  435          * mark this link as not routed.  We won't use it as the preferred
  436          * interrupt later when we route.
  437          */
  438         if (!acpi_pci_link_is_valid_irq(link, link->initial_irq) &&
  439             link->initial_irq != 0) {
  440                 printf("ACPI link %s has invalid initial irq %d, ignoring\n",
  441                     acpi_name(handle), link->initial_irq);
  442                 link->initial_irq = 0;
  443                 link->flags = ACPI_LINK_NONE;
  444         }
  445 
  446         link->references++;
  447 
  448         TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
  449         entry->pci_link = link;
  450 
  451         error = AE_OK;
  452 out:
  453         if (buf.Pointer != NULL)
  454                 AcpiOsFree(buf.Pointer);
  455         if (error != AE_OK && link != NULL)
  456                 AcpiOsFree(link);
  457 
  458         return_ACPI_STATUS (error);
  459 }
  460 
  461 static ACPI_STATUS
  462 acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno)
  463 {
  464         ACPI_HANDLE             handle;
  465         ACPI_STATUS             error;
  466         UINT32                  sta;
  467         struct acpi_prt_entry   *entry;
  468 
  469         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  470         ACPI_SERIAL_ASSERT(pci_link);
  471 
  472         if (prt == NULL) {
  473                 device_printf(pcidev, "NULL PRT entry\n");
  474                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  475         }
  476 
  477         /* Bail out if attempting to add a duplicate PRT entry. */
  478         TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
  479                 if (entry->busno == busno &&
  480                     entry->prt.Address == prt->Address &&
  481                     entry->prt.Pin == prt->Pin) {
  482                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  483                             "PRT entry already exists\n"));
  484                         return_ACPI_STATUS (AE_ALREADY_EXISTS);
  485                 }
  486         }
  487 
  488         /* Allocate and initialize our new PRT entry. */
  489         entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry));
  490         if (entry == NULL) {
  491                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "can't allocate memory\n"));
  492                 return_ACPI_STATUS (AE_NO_MEMORY);
  493         }
  494         bzero(entry, sizeof(struct acpi_prt_entry));
  495 
  496         /*
  497          * If the source link is NULL, then this IRQ is hardwired so skip
  498          * initializing the link but still add it to the list.
  499          */
  500         if (prt->Source[0] != '\0') {
  501                 /* Get a handle for the link source. */
  502                 error = AcpiGetHandle(acpi_get_handle(pcidev), prt->Source,
  503                     &handle);
  504                 if (ACPI_FAILURE(error)) {
  505                         device_printf(pcidev, "get handle for %s - %s\n",
  506                             prt->Source, AcpiFormatException(error));
  507                         goto out;
  508                 }
  509 
  510                 error = acpi_pci_link_get_object_status(handle, &sta);
  511                 if (ACPI_FAILURE(error)) {
  512                         device_printf(pcidev, "can't get status for %s - %s\n",
  513                             acpi_name(handle), AcpiFormatException(error));
  514                         goto out;
  515                 }
  516 
  517                 /* Probe/initialize the link. */
  518                 error = acpi_pci_link_add_link(handle, entry);
  519                 if (ACPI_FAILURE(error)) {
  520                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  521                             "couldn't add _PRT entry to link %s - %s\n",
  522                             acpi_name(handle), AcpiFormatException(error)));
  523                         goto out;
  524                 }
  525         }
  526 
  527         entry->pcidev = pcidev;
  528         entry->busno = busno;
  529         bcopy(prt, &entry->prt, sizeof(entry->prt));
  530 
  531         /*
  532          * Make sure the Source value is null-terminated.  It is really a
  533          * variable-length string (with a fixed size in the struct) so when
  534          * we copy the entire struct, we truncate the string.  Instead of
  535          * trying to make a variable-sized PRT object to handle the string,
  536          * we store its handle in prt_source.  Callers should use that to
  537          * look up the link object.
  538          */
  539         entry->prt.Source[sizeof(prt->Source) - 1] = '\0';
  540         entry->prt_source = handle;
  541 
  542         TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links);
  543         error = AE_OK;
  544 
  545 out:
  546         if (error != AE_OK && entry != NULL)
  547                 AcpiOsFree(entry);
  548 
  549         return_ACPI_STATUS (error);
  550 }
  551 
  552 /*
  553  * Look up the given interrupt in the list of possible settings for
  554  * this link.  We don't special-case the initial link setting.  Some
  555  * systems return current settings that are outside the list of valid
  556  * settings so only allow choices explicitly specified in _PRS.
  557  */
  558 static int
  559 acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq)
  560 {
  561         UINT8                   i;
  562 
  563         if (irq == 0)
  564                 return (FALSE);
  565 
  566         /*
  567          * Some systems have the initial irq set to the SCI but don't list
  568          * it in the valid IRQs.  Add a special case to allow routing to the
  569          * SCI if the system really wants to.  This is similar to how
  570          * Windows often stacks all PCI IRQs on the SCI (and this is vital
  571          * on some systems.)
  572          */
  573         if (irq == AcpiGbl_FADT->SciInt)
  574                 return (TRUE);
  575 
  576         for (i = 0; i < link->number_of_interrupts; i++) {
  577                 if (link->interrupts[i] == irq)
  578                         return (TRUE);
  579         }
  580 
  581         return (FALSE);
  582 }
  583 
  584 static ACPI_STATUS
  585 acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq)
  586 {
  587         ACPI_STATUS             error;
  588         ACPI_RESOURCE           resbuf;
  589         ACPI_BUFFER             crsbuf;
  590 
  591         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  592         ACPI_SERIAL_ASSERT(pci_link);
  593 
  594         /* Make sure the new IRQ is valid before routing. */
  595         if (!acpi_pci_link_is_valid_irq(link, irq)) {
  596                 printf("acpi link set: invalid IRQ %d on %s\n",
  597                     irq, acpi_name(link->handle));
  598                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  599         }
  600 
  601         /* If this this link has already been routed, just return. */
  602         if (link->flags & ACPI_LINK_ROUTED) {
  603                 printf("acpi link set: %s already routed to %d\n",
  604                     acpi_name(link->handle), link->current_irq);
  605                 return_ACPI_STATUS (AE_OK);
  606         }
  607 
  608         /* Set up the IRQ resource for _SRS. */
  609         bzero(&resbuf, sizeof(resbuf));
  610         crsbuf.Pointer = NULL;
  611 
  612         switch (link->possible_resources.Id) {
  613         case ACPI_RSTYPE_IRQ:
  614                 resbuf.Id = ACPI_RSTYPE_IRQ;
  615                 resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
  616 
  617                 /* structure copy other fields */
  618                 resbuf.Data.Irq = link->possible_resources.Data.Irq;
  619                 resbuf.Data.Irq.NumberOfInterrupts = 1;
  620                 resbuf.Data.Irq.Interrupts[0] = irq;
  621                 break;
  622         case ACPI_RSTYPE_EXT_IRQ:
  623                 resbuf.Id = ACPI_RSTYPE_EXT_IRQ;
  624                 resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_EXT_IRQ);
  625 
  626                 /* structure copy other fields */
  627                 resbuf.Data.ExtendedIrq =
  628                     link->possible_resources.Data.ExtendedIrq;
  629                 resbuf.Data.ExtendedIrq.NumberOfInterrupts = 1;
  630                 resbuf.Data.ExtendedIrq.Interrupts[0] = irq;
  631                 break;
  632         default:
  633                 printf("acpi link set: %s resource is not an IRQ (%d)\n",
  634                     acpi_name(link->handle), link->possible_resources.Id);
  635                 return_ACPI_STATUS (AE_TYPE);
  636         }
  637 
  638         error = acpi_AppendBufferResource(&crsbuf, &resbuf);
  639         if (ACPI_FAILURE(error)) {
  640                 printf("acpi link set: AppendBuffer failed for %s\n",
  641                     acpi_name(link->handle));
  642                 return_ACPI_STATUS (error);
  643         }
  644         if (crsbuf.Pointer == NULL) {
  645                 printf("acpi link set: AppendBuffer returned empty for %s\n",
  646                     acpi_name(link->handle));
  647                 return_ACPI_STATUS (AE_NO_MEMORY);
  648         }
  649 
  650         /* Make the new IRQ active via the link's _SRS method. */
  651         error = AcpiSetCurrentResources(link->handle, &crsbuf);
  652         if (ACPI_FAILURE(error)) {
  653                 printf("acpi link set: _SRS failed for link %s - %s\n",
  654                     acpi_name(link->handle), AcpiFormatException(error));
  655                 goto out;
  656         }
  657         link->flags |= ACPI_LINK_ROUTED;
  658         link->current_irq = 0;
  659 
  660         /*
  661          * Many systems always return invalid values for current settings
  662          * (_CRS).  Since we can't trust the value returned, we have to
  663          * assume we were successful.
  664          */
  665         error = acpi_pci_link_get_current_irq(link, &link->current_irq);
  666         if (ACPI_FAILURE(error)) {
  667                 if (bootverbose)
  668                         printf("acpi link set: _CRS failed for link %s - %s\n",
  669                             acpi_name(link->handle),
  670                             AcpiFormatException(error));
  671                 error = AE_OK;
  672         }
  673         if (link->current_irq != irq) {
  674                 if (bootverbose)
  675                         printf("acpi link set: curr irq %d != %d for %s\n",
  676                             link->current_irq, irq, acpi_name(link->handle));
  677                 link->current_irq = irq;
  678         }
  679 
  680 out:
  681         if (crsbuf.Pointer)
  682                 AcpiOsFree(crsbuf.Pointer);
  683         return_ACPI_STATUS (error);
  684 }
  685 
  686 /*
  687  * Auto arbitration for boot-disabled devices
  688  */
  689 
  690 static void
  691 acpi_pci_link_bootdisabled_dump(void)
  692 {
  693         int                     i;
  694         int                     irq;
  695         struct acpi_pci_link_entry *link;
  696 
  697         ACPI_SERIAL_ASSERT(pci_link);
  698         TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
  699                 /* boot-disabled link only. */
  700                 if (link->current_irq != 0)
  701                         continue;
  702 
  703                 printf("%s (references %d, priority %d):\n",
  704                     acpi_name(link->handle), link->references, link->priority);
  705                 printf("\tinterrupts:\t");
  706                 for (i = 0; i < link->number_of_interrupts; i++) {
  707                         irq = link->sorted_irq[i];
  708                         printf("%6d", irq);
  709                 }
  710                 printf("\n");
  711                 printf("\tpenalty:\t");
  712                 for (i = 0; i < link->number_of_interrupts; i++) {
  713                         irq = link->sorted_irq[i];
  714                         printf("%6d", irq_penalty[irq]);
  715                 }
  716                 printf("\n");
  717         }
  718 }
  719 
  720 /*
  721  * Heuristics for choosing IRQs.  We start with some static penalties,
  722  * update them based on what IRQs are currently in use, then sort the
  723  * result.  This works ok but is not perfect.
  724  *
  725  * The PCI BIOS $PIR table offers "preferred PCI interrupts", but ACPI
  726  * doesn't seem to offer a similar mechanism, so picking a good
  727  * interrupt here is a difficult task.
  728  */
  729 static void
  730 acpi_pci_link_init_irq_penalty(void)
  731 {
  732 
  733         bzero(irq_penalty, sizeof(irq_penalty));
  734 
  735         /* 0, 1, 2, 8:  timer, keyboard, cascade, RTC */
  736         irq_penalty[0] = 100000;
  737         irq_penalty[1] = 100000;
  738         irq_penalty[2] = 100000;
  739         irq_penalty[8] = 100000;
  740 
  741         /* 13, 14, 15:  npx, ATA controllers */
  742         irq_penalty[13] = 50000;
  743         irq_penalty[14] = 50000;
  744         irq_penalty[15] = 50000;
  745 
  746         /* 3, 4, 6, 7, 12:  typically used by legacy hardware */
  747         irq_penalty[3] =   5000;
  748         irq_penalty[4] =   5000;
  749         irq_penalty[6] =   5000;
  750         irq_penalty[7] =   5000;
  751         irq_penalty[12] =  5000;
  752 
  753         /* 5:  sometimes legacy sound cards */
  754         irq_penalty[5] =     50;
  755 }
  756 
  757 static int
  758 link_exclusive(ACPI_RESOURCE *res)
  759 {
  760 
  761         if (res == NULL ||
  762             (res->Id != ACPI_RSTYPE_IRQ &&
  763             res->Id != ACPI_RSTYPE_EXT_IRQ))
  764                 return (FALSE);
  765 
  766         if ((res->Id == ACPI_RSTYPE_IRQ &&
  767             res->Data.Irq.SharedExclusive == ACPI_EXCLUSIVE) ||
  768             (res->Id == ACPI_RSTYPE_EXT_IRQ &&
  769             res->Data.ExtendedIrq.SharedExclusive == ACPI_EXCLUSIVE))
  770                 return (TRUE);
  771 
  772         return (FALSE);
  773 }
  774 
  775 static void
  776 acpi_pci_link_update_irq_penalty(device_t dev, int busno)
  777 {
  778         int                     i;
  779         int                     irq;
  780         int                     rid;
  781         struct resource         *res;
  782         struct acpi_prt_entry   *entry;
  783         struct acpi_pci_link_entry *link;
  784 
  785         ACPI_SERIAL_ASSERT(pci_link);
  786         TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
  787                 if (entry->busno != busno)
  788                         continue;
  789 
  790                 /* Impossible? */
  791                 link = entry->pci_link;
  792                 if (link == NULL)
  793                         continue;
  794 
  795                 /* Update penalties for all possible settings of this link. */
  796                 for (i = 0; i < link->number_of_interrupts; i++) {
  797                         /* give 10 for each possible IRQs. */
  798                         irq = link->interrupts[i];
  799                         irq_penalty[irq] += 10;
  800 
  801                         /* higher penalty if exclusive. */
  802                         if (link_exclusive(&link->possible_resources))
  803                                 irq_penalty[irq] += 100;
  804 
  805                         /* XXX try to get this IRQ in non-sharable mode. */
  806                         rid = 0;
  807                         res = bus_alloc_resource(dev, SYS_RES_IRQ,
  808                                                  &rid, irq, irq, 1, 0);
  809                         if (res != NULL) {
  810                                 bus_release_resource(dev, SYS_RES_IRQ,
  811                                     rid, res);
  812                         } else {
  813                                 /* this is in use, give 10. */
  814                                 irq_penalty[irq] += 10;
  815                         }
  816                 }
  817 
  818                 /* initialize `sorted' possible IRQs. */
  819                 bcopy(link->interrupts, link->sorted_irq,
  820                     sizeof(link->sorted_irq));
  821         }
  822 }
  823 
  824 static void
  825 acpi_pci_link_set_bootdisabled_priority(void)
  826 {
  827         int                     sum_penalty;
  828         int                     i;
  829         int                     irq;
  830         struct acpi_pci_link_entry *link, *link_pri;
  831         TAILQ_HEAD(, acpi_pci_link_entry) sorted_list;
  832 
  833         ACPI_SERIAL_ASSERT(pci_link);
  834 
  835         /* reset priority for all links. */
  836         TAILQ_FOREACH(link, &acpi_pci_link_entries, links)
  837                 link->priority = 0;
  838 
  839         TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
  840                 /* If already routed, don't include in arbitration. */
  841                 if (link->flags & ACPI_LINK_ROUTED) {
  842                         link->priority = 0;
  843                         continue;
  844                 }
  845 
  846                 /*
  847                  * Calculate the priority for each boot-disabled links.
  848                  * o IRQ penalty indicates difficulty to use. 
  849                  * o #references for devices indicates importance of the link.
  850                  * o #interrupts indicates flexibility of the link.
  851                  */
  852                 sum_penalty = 0;
  853                 for (i = 0; i < link->number_of_interrupts; i++) {
  854                         irq = link->interrupts[i];
  855                         sum_penalty += irq_penalty[irq];
  856                 }
  857 
  858                 link->priority = (sum_penalty * link->references) /
  859                     link->number_of_interrupts;
  860         }
  861 
  862         /*
  863          * Sort PCI links based on the priority.
  864          * XXX Any other better ways rather than using work list?
  865          */
  866         TAILQ_INIT(&sorted_list);
  867         while (!TAILQ_EMPTY(&acpi_pci_link_entries)) {
  868                 link = TAILQ_FIRST(&acpi_pci_link_entries);
  869                 /* find an entry which has the highest priority. */
  870                 TAILQ_FOREACH(link_pri, &acpi_pci_link_entries, links)
  871                         if (link->priority < link_pri->priority)
  872                                 link = link_pri;
  873 
  874                 /* move to work list. */
  875                 TAILQ_REMOVE(&acpi_pci_link_entries, link, links);
  876                 TAILQ_INSERT_TAIL(&sorted_list, link, links);
  877         }
  878 
  879         while (!TAILQ_EMPTY(&sorted_list)) {
  880                 /* move them back to the list, one by one... */
  881                 link = TAILQ_FIRST(&sorted_list);
  882                 TAILQ_REMOVE(&sorted_list, link, links);
  883                 TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
  884         }
  885 }
  886 
  887 static void
  888 acpi_pci_link_fixup_bootdisabled_link(void)
  889 {
  890         int                     i, j;
  891         int                     irq1, irq2;
  892         struct acpi_pci_link_entry *link;
  893 
  894         ACPI_SERIAL_ASSERT(pci_link);
  895 
  896         TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
  897                 /* Ignore links that have been routed already. */
  898                 if (link->flags & ACPI_LINK_ROUTED)
  899                         continue;
  900 
  901                 /* sort IRQs based on their penalty descending. */
  902                 for (i = 0; i < link->number_of_interrupts; i++) {
  903                         irq1 = link->sorted_irq[i];
  904                         for (j = i + 1; j < link->number_of_interrupts; j++) {
  905                                 irq2 = link->sorted_irq[j];
  906                                 if (irq_penalty[irq1] < irq_penalty[irq2]) {
  907                                         continue;
  908                                 }
  909                                 link->sorted_irq[i] = irq2;
  910                                 link->sorted_irq[j] = irq1;
  911                                 irq1 = irq2;
  912                         }
  913                 }
  914         }
  915 
  916         if (bootverbose) {
  917                 printf("ACPI PCI link arbitrated settings:\n");
  918                 acpi_pci_link_bootdisabled_dump();
  919         }
  920 }
  921 
  922 /*
  923  * Public interface
  924  */
  925 
  926 int
  927 acpi_pci_link_config(device_t dev, ACPI_BUFFER *prtbuf, int busno)
  928 {
  929         struct acpi_prt_entry   *entry;
  930         ACPI_PCI_ROUTING_TABLE  *prt;
  931         u_int8_t                *prtp;
  932         ACPI_STATUS             error;
  933         int                     ret;
  934         static int              first_time = 1;
  935 
  936         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  937 
  938         if (acpi_disabled("pci_link"))
  939                 return (0);
  940 
  941         ret = -1;
  942         ACPI_SERIAL_BEGIN(pci_link);
  943         if (first_time) {
  944                 TAILQ_INIT(&acpi_prt_entries);
  945                 TAILQ_INIT(&acpi_pci_link_entries);
  946                 acpi_pci_link_init_irq_penalty();
  947                 first_time = 0;
  948         }
  949 
  950         if (prtbuf == NULL)
  951                 goto out;
  952 
  953         prtp = prtbuf->Pointer;
  954         if (prtp == NULL)               /* didn't get routing table */
  955                 goto out;
  956 
  957         /* scan the PCI Routing Table */
  958         for (;;) {
  959                 prt = (ACPI_PCI_ROUTING_TABLE *)prtp;
  960 
  961                 if (prt->Length == 0)   /* end of table */
  962                     break;
  963 
  964                 error = acpi_pci_link_add_prt(dev, prt, busno);
  965                 if (ACPI_FAILURE(error)) {
  966                         ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  967                             "couldn't add PCI interrupt link entry - %s\n",
  968                             AcpiFormatException(error)));
  969                 }
  970 
  971                 /* skip to next entry */
  972                 prtp += prt->Length;
  973         }
  974 
  975         if (bootverbose) {
  976                 printf("ACPI PCI link initial configuration:\n");
  977                 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
  978                         if (entry->busno != busno)
  979                                 continue;
  980                         acpi_pci_link_entry_dump(entry);
  981                 }
  982         }
  983 
  984         /* manual configuration. */
  985         TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
  986                 int                     irq;
  987                 char                    prthint[32];
  988 
  989                 if (entry->busno != busno)
  990                         continue;
  991 
  992                 snprintf(prthint, sizeof(prthint),
  993                     "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno,
  994                     (int)(ACPI_ADR_PCI_SLOT(entry->prt.Address)),
  995                     (int)entry->prt.Pin);
  996 
  997                 if (getenv_int(prthint, &irq) == 0)
  998                         continue;
  999 
 1000                 if (acpi_pci_link_is_valid_irq(entry->pci_link, irq)) {
 1001                         error = acpi_pci_link_set_irq(entry->pci_link, irq);
 1002                         if (ACPI_FAILURE(error)) {
 1003                                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
 1004                                     "couldn't set IRQ to link entry %s - %s\n",
 1005                                     acpi_name(entry->pci_link->handle),
 1006                                     AcpiFormatException(error)));
 1007                         }
 1008                         continue;
 1009                 }
 1010 
 1011                 /*
 1012                  * Do auto arbitration for this device's PCI link
 1013                  * if hint value 0 is specified.
 1014                  */
 1015                 if (irq == 0)
 1016                         entry->pci_link->current_irq = 0;
 1017         }
 1018         ret = 0;
 1019 
 1020 out:
 1021         ACPI_SERIAL_END(pci_link);
 1022         return (ret);
 1023 }
 1024 
 1025 int
 1026 acpi_pci_link_resume(device_t dev)
 1027 {
 1028         struct acpi_prt_entry   *entry;
 1029         struct acpi_pci_link_entry *link;
 1030         ACPI_STATUS             error;
 1031 
 1032         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 1033 
 1034         if (acpi_disabled("pci_link"))
 1035                 return (0);
 1036 
 1037         /* Walk through all PRT entries for this PCI bridge. */
 1038         ACPI_SERIAL_BEGIN(pci_link);
 1039         TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
 1040                 if (entry->pcidev != dev || entry->pci_link == NULL)
 1041                         continue;
 1042                 link = entry->pci_link;
 1043 
 1044                 /* If it's not routed, skip re-programming. */
 1045                 if ((link->flags & ACPI_LINK_ROUTED) == 0)
 1046                         continue;
 1047                 link->flags &= ~ACPI_LINK_ROUTED;
 1048 
 1049                 /* Program it to the same setting as before suspend. */
 1050                 error = acpi_pci_link_set_irq(link, link->current_irq);
 1051                 if (ACPI_FAILURE(error)) {
 1052                         ACPI_DEBUG_PRINT((ACPI_DB_WARN,
 1053                             "couldn't set IRQ to link entry %s - %s\n",
 1054                             acpi_name(link->handle),
 1055                             AcpiFormatException(error)));
 1056                 }
 1057         }
 1058         ACPI_SERIAL_END(pci_link);
 1059 
 1060         return (0);
 1061 }
 1062 
 1063 /*
 1064  * Look up a PRT entry for the given device.  We match based on the slot
 1065  * number (high word of Address) and pin number (note that ACPI uses 0
 1066  * for INTA).
 1067  *
 1068  * Note that the low word of the Address field (function number) is
 1069  * required by the specification to be 0xffff.  We don't risk checking
 1070  * it here.
 1071  */
 1072 struct acpi_prt_entry *
 1073 acpi_pci_find_prt(device_t pcibdev, device_t dev, int pin)
 1074 {
 1075         struct acpi_prt_entry *entry;
 1076         ACPI_PCI_ROUTING_TABLE *prt;
 1077 
 1078         ACPI_SERIAL_BEGIN(pci_link);
 1079         TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
 1080                 prt = &entry->prt;
 1081                 if (entry->busno == pci_get_bus(dev) &&
 1082                     ACPI_ADR_PCI_SLOT(prt->Address) == pci_get_slot(dev) &&
 1083                     prt->Pin == pin)
 1084                         break;
 1085         }
 1086         ACPI_SERIAL_END(pci_link);
 1087         return (entry);
 1088 }
 1089 
 1090 /*
 1091  * Perform the actual programming for this link.  We attempt to route an
 1092  * IRQ, first the one set by the BIOS, and then a priority-sorted list.
 1093  * Only do the programming once per link.
 1094  */
 1095 int
 1096 acpi_pci_link_route(device_t dev, struct acpi_prt_entry *prt)
 1097 {
 1098         struct acpi_pci_link_entry *link;
 1099         int busno, i, irq;
 1100         ACPI_RESOURCE crsres;
 1101         ACPI_STATUS status;
 1102 
 1103         busno = pci_get_bus(dev);
 1104         link = prt->pci_link;
 1105         irq = PCI_INVALID_IRQ;
 1106         ACPI_SERIAL_BEGIN(pci_link);
 1107         if (link == NULL || link->number_of_interrupts == 0)
 1108                 goto out;
 1109 
 1110         /* If already routed, just return the current setting. */
 1111         if (link->flags & ACPI_LINK_ROUTED) {
 1112                 irq = link->current_irq;
 1113                 goto out;
 1114         }
 1115 
 1116         /* Update all IRQ weights to determine our priority list. */
 1117         acpi_pci_link_update_irq_penalty(prt->pcidev, busno);
 1118         acpi_pci_link_set_bootdisabled_priority();
 1119         acpi_pci_link_fixup_bootdisabled_link();
 1120 
 1121         /*
 1122          * First, attempt to route the initial IRQ, if valid, since it was
 1123          * the one set up by the BIOS.  If this fails, route according to
 1124          * our priority-sorted list of IRQs.
 1125          */
 1126         status = AE_NOT_FOUND;
 1127         irq = link->initial_irq;
 1128         if (irq)
 1129                 status = acpi_pci_link_set_irq(link, irq);
 1130         for (i = 0; ACPI_FAILURE(status) && i < link->number_of_interrupts;
 1131             i++) {
 1132                 irq = link->sorted_irq[i];
 1133                 status = acpi_pci_link_set_irq(link, irq);
 1134                 if (ACPI_FAILURE(status)) {
 1135                         device_printf(dev, "_SRS failed, irq %d via %s\n",
 1136                             irq, acpi_name(link->handle));
 1137                 }
 1138         }
 1139         if (ACPI_FAILURE(status)) {
 1140                 irq = PCI_INVALID_IRQ;
 1141                 goto out;
 1142         }
 1143 
 1144         /* Update the penalty now that there's another user for this IRQ. */
 1145         irq_penalty[irq] += 10 * link->references;
 1146 
 1147         /* Configure trigger/polarity for the new IRQ. */
 1148         bcopy(&link->possible_resources, &crsres, sizeof(crsres));
 1149         if (crsres.Id == ACPI_RSTYPE_IRQ) {
 1150                 crsres.Data.Irq.NumberOfInterrupts = 1;
 1151                 crsres.Data.Irq.Interrupts[0] = irq;
 1152         } else {
 1153                 crsres.Data.ExtendedIrq.NumberOfInterrupts = 1;
 1154                 crsres.Data.ExtendedIrq.Interrupts[0] = irq;
 1155         }
 1156         acpi_config_intr(dev, &crsres);
 1157 
 1158 out:
 1159         ACPI_SERIAL_END(pci_link);
 1160         return (irq);
 1161 }

Cache object: 88a0da09f6da0d77cb3cef172f6b97fe


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