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.2/sys/dev/acpica/acpi_pci_link.c 123654 2003-12-19 00:03:02Z 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 
   37 #include <dev/acpica/acpivar.h>
   38 #include <dev/acpica/acpi_pcibvar.h>
   39 
   40 /*
   41  * Hooks for the ACPI CA debugging infrastructure
   42  */
   43 #define _COMPONENT      ACPI_BUS
   44 ACPI_MODULE_NAME("PCI_LINK")
   45 
   46 #define MAX_POSSIBLE_INTERRUPTS 16
   47 #define MAX_ISA_INTERRUPTS      16
   48 #define MAX_ACPI_INTERRUPTS     255
   49 
   50 struct acpi_pci_link_entry {
   51         TAILQ_ENTRY(acpi_pci_link_entry) links;
   52         ACPI_HANDLE     handle;
   53         UINT8           current_irq;
   54         UINT8           initial_irq;
   55         ACPI_RESOURCE   possible_resources;
   56         UINT8           number_of_interrupts;
   57         UINT8           interrupts[MAX_POSSIBLE_INTERRUPTS];
   58 
   59         UINT8           sorted_irq[MAX_POSSIBLE_INTERRUPTS];
   60         int             references;
   61         int             priority;
   62 };
   63 
   64 TAILQ_HEAD(acpi_pci_link_entries, acpi_pci_link_entry);
   65 static struct acpi_pci_link_entries acpi_pci_link_entries;
   66 
   67 struct acpi_prt_entry {
   68         TAILQ_ENTRY(acpi_prt_entry) links;
   69         device_t        pcidev;
   70         int             busno;
   71         ACPI_PCI_ROUTING_TABLE prt;
   72         struct acpi_pci_link_entry *pci_link;
   73 };
   74 
   75 TAILQ_HEAD(acpi_prt_entries, acpi_prt_entry);
   76 static struct acpi_prt_entries acpi_prt_entries;
   77 
   78 static int      irq_penalty[MAX_ACPI_INTERRUPTS];
   79 
   80 #define ACPI_STA_PRESENT        0x00000001
   81 #define ACPI_STA_ENABLE         0x00000002
   82 #define ACPI_STA_SHOWINUI       0x00000004
   83 #define ACPI_STA_FUNCTIONAL     0x00000008
   84 
   85 /*
   86  * PCI link object management
   87  */
   88 
   89 static void
   90 acpi_pci_link_dump_polarity(UINT32 ActiveHighLow)
   91 {
   92 
   93         switch (ActiveHighLow) {
   94         case ACPI_ACTIVE_HIGH:
   95                 printf("high,");
   96                 break;
   97 
   98         case ACPI_ACTIVE_LOW:
   99                 printf("low,");
  100                 break;
  101 
  102         default:
  103                 printf("unknown,");
  104                 break;
  105         }
  106 }
  107 
  108 static void
  109 acpi_pci_link_dump_trigger(UINT32 EdgeLevel)
  110 {
  111 
  112         switch (EdgeLevel) {
  113         case ACPI_EDGE_SENSITIVE:
  114                 printf("edge,");
  115                 break;
  116 
  117         case ACPI_LEVEL_SENSITIVE:
  118                 printf("level,");
  119                 break;
  120 
  121         default:
  122                 printf("unknown,");
  123                 break;
  124         }
  125 }
  126 
  127 static void
  128 acpi_pci_link_dump_sharemode(UINT32 SharedExclusive)
  129 {
  130 
  131         switch (SharedExclusive) {
  132         case ACPI_EXCLUSIVE:
  133                 printf("exclusive");
  134                 break;
  135 
  136         case ACPI_SHARED:
  137                 printf("sharable");
  138                 break;
  139 
  140         default:
  141                 printf("unknown");
  142                 break;
  143         }
  144 }
  145 
  146 static void
  147 acpi_pci_link_entry_dump(struct acpi_prt_entry *entry)
  148 {
  149         UINT8                   i;
  150         ACPI_RESOURCE_IRQ       *Irq;
  151         ACPI_RESOURCE_EXT_IRQ   *ExtIrq;
  152 
  153         if (entry == NULL || entry->pci_link == NULL) {
  154                 return;
  155         }
  156 
  157         printf("%s irq %3d: ", acpi_name(entry->pci_link->handle),
  158             entry->pci_link->current_irq);
  159 
  160         printf("[");
  161         for (i = 0; i < entry->pci_link->number_of_interrupts; i++) {
  162                 printf("%3d", entry->pci_link->interrupts[i]);
  163         }
  164         printf("] ");
  165 
  166         switch (entry->pci_link->possible_resources.Id) {
  167         case ACPI_RSTYPE_IRQ:
  168                 Irq = &entry->pci_link->possible_resources.Data.Irq;
  169 
  170                 acpi_pci_link_dump_polarity(Irq->ActiveHighLow);
  171                 acpi_pci_link_dump_trigger(Irq->EdgeLevel);
  172                 acpi_pci_link_dump_sharemode(Irq->SharedExclusive);
  173                 break;
  174 
  175         case ACPI_RSTYPE_EXT_IRQ:
  176                 ExtIrq = &entry->pci_link->possible_resources.Data.ExtendedIrq;
  177 
  178                 acpi_pci_link_dump_polarity(ExtIrq->ActiveHighLow);
  179                 acpi_pci_link_dump_trigger(ExtIrq->EdgeLevel);
  180                 acpi_pci_link_dump_sharemode(ExtIrq->SharedExclusive);
  181                 break;
  182         }
  183 
  184         printf(" %d.%d.%d", entry->busno,
  185             (int)((entry->prt.Address & 0xffff0000) >> 16),
  186             (int)entry->prt.Pin);
  187 
  188         printf("\n");
  189 }
  190 
  191 static ACPI_STATUS
  192 acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta)
  193 {
  194         ACPI_DEVICE_INFO        *devinfo;
  195         ACPI_BUFFER             buf;
  196         ACPI_STATUS             error;
  197 
  198         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  199 
  200         if (handle == NULL || sta == NULL) {
  201                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  202                     "invalid argument\n"));
  203                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  204         }
  205 
  206         buf.Pointer = NULL;
  207         buf.Length = ACPI_ALLOCATE_BUFFER;
  208         error = AcpiGetObjectInfo(handle, &buf);
  209         if (ACPI_FAILURE(error)) {
  210                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  211                     "couldn't get object info %s - %s\n",
  212                     acpi_name(handle), AcpiFormatException(error)));
  213                 return_ACPI_STATUS (error);
  214         }
  215         devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
  216 
  217         if ((devinfo->Valid & ACPI_VALID_HID) == 0 ||
  218             strcmp(devinfo->HardwareId.Value, "PNP0C0F") != 0) {
  219                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid hardware ID - %s\n",
  220                     acpi_name(handle)));
  221                 AcpiOsFree(buf.Pointer);
  222                 return_ACPI_STATUS (AE_TYPE);
  223         }
  224 
  225         if ((devinfo->Valid & ACPI_VALID_STA) != 0) {
  226                 *sta = devinfo->CurrentStatus;
  227         } else {
  228                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid status - %s\n",
  229                     acpi_name(handle)));
  230                 *sta = 0;
  231         }
  232 
  233         AcpiOsFree(buf.Pointer);
  234         return_ACPI_STATUS (AE_OK);
  235 }
  236 
  237 static ACPI_STATUS
  238 acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources,
  239     UINT8 *number_of_interrupts, UINT8 interrupts[])
  240 {
  241         UINT8                   count;
  242         UINT8                   i;
  243         UINT32                  NumberOfInterrupts;
  244         UINT32                  *Interrupts;
  245 
  246         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  247 
  248         if (resources == NULL || number_of_interrupts == NULL) {
  249                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
  250                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  251         }
  252 
  253         *number_of_interrupts = 0;
  254         NumberOfInterrupts = 0;
  255         Interrupts = NULL;
  256 
  257         if (resources->Id == ACPI_RSTYPE_START_DPF)
  258                 resources = ACPI_NEXT_RESOURCE(resources);
  259 
  260         if (resources->Id != ACPI_RSTYPE_IRQ &&
  261             resources->Id != ACPI_RSTYPE_EXT_IRQ) {
  262                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  263                     "Resource is not an IRQ entry - %d\n", resources->Id));
  264                 return_ACPI_STATUS (AE_TYPE);
  265         }
  266 
  267         switch (resources->Id) {
  268         case ACPI_RSTYPE_IRQ:
  269                 NumberOfInterrupts = resources->Data.Irq.NumberOfInterrupts;
  270                 Interrupts = resources->Data.Irq.Interrupts;
  271                 break;
  272 
  273         case ACPI_RSTYPE_EXT_IRQ:
  274                 NumberOfInterrupts = resources->Data.ExtendedIrq.NumberOfInterrupts;
  275                 Interrupts = resources->Data.ExtendedIrq.Interrupts;
  276                 break;
  277         }
  278         
  279         if (NumberOfInterrupts == 0) {
  280                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n"));
  281                 return_ACPI_STATUS (AE_NULL_ENTRY);
  282         }
  283 
  284         count = 0;
  285         for (i = 0; i < NumberOfInterrupts; i++) {
  286                 if (i >= MAX_POSSIBLE_INTERRUPTS) {
  287                         ACPI_DEBUG_PRINT((ACPI_DB_WARN, "too many IRQs %d\n", i));
  288                         break;
  289                 }
  290 
  291                 if (Interrupts[i] == NULL) {
  292                         ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n",
  293                             Interrupts[i]));
  294                         continue;
  295                 }
  296                 interrupts[count] = Interrupts[i];
  297                 count++;
  298         }
  299         *number_of_interrupts = count;
  300 
  301         return_ACPI_STATUS (AE_OK);
  302 }
  303 
  304 static ACPI_STATUS
  305 acpi_pci_link_get_current_irq(struct acpi_pci_link_entry *link, UINT8 *irq)
  306 {
  307         ACPI_STATUS             error;
  308         ACPI_BUFFER             buf;
  309         ACPI_RESOURCE           *resources;
  310         UINT8                   number_of_interrupts;
  311         UINT8                   interrupts[MAX_POSSIBLE_INTERRUPTS];;
  312 
  313         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  314 
  315         if (link == NULL || irq == NULL) {
  316                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
  317                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  318         }
  319 
  320         *irq = 0;
  321         buf.Pointer = NULL;
  322         buf.Length = ACPI_ALLOCATE_BUFFER;
  323         error = AcpiGetCurrentResources(link->handle, &buf);
  324         if (ACPI_FAILURE(error)) {
  325                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  326                     "couldn't get PCI interrupt link device _CRS %s - %s\n",
  327                     acpi_name(link->handle), AcpiFormatException(error)));
  328                 return_ACPI_STATUS (error);
  329         }
  330         if (buf.Pointer == NULL) {
  331                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  332                     "couldn't allocate memory - %s\n",
  333                     acpi_name(link->handle)));
  334                 return_ACPI_STATUS (AE_NO_MEMORY);
  335         }
  336 
  337         resources = (ACPI_RESOURCE *) buf.Pointer;
  338 
  339         number_of_interrupts = 0;
  340         bzero(interrupts, sizeof(interrupts));
  341         error = acpi_pci_link_get_irq_resources(resources,
  342                     &number_of_interrupts, interrupts);
  343         AcpiOsFree(buf.Pointer);
  344 
  345         if (ACPI_FAILURE(error)) {
  346                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  347                     "couldn't get current IRQ from PCI interrupt link %s - %s\n",
  348                     acpi_name(link->handle), AcpiFormatException(error)));
  349                 return_ACPI_STATUS (error);
  350         }
  351 
  352         if (number_of_interrupts == 0) {
  353                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  354                     "PCI interrupt link device _CRS data is corrupted - %s\n",
  355                     acpi_name(link->handle)));
  356                 return_ACPI_STATUS (AE_NULL_ENTRY);
  357         }
  358 
  359         *irq = interrupts[0];
  360 
  361         return_ACPI_STATUS (AE_OK);
  362 }
  363 
  364 static ACPI_STATUS
  365 acpi_pci_link_add_link(ACPI_HANDLE handle, struct acpi_prt_entry *entry)
  366 {
  367         ACPI_STATUS             error;
  368         ACPI_BUFFER             buf;
  369         ACPI_RESOURCE           *resources;
  370         struct acpi_pci_link_entry *link;
  371 
  372         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  373 
  374         entry->pci_link = NULL;
  375         TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
  376                 if (link->handle == handle) {
  377                         entry->pci_link = link;
  378                         link->references++;
  379                         return_ACPI_STATUS (AE_OK);
  380                 }
  381         }
  382 
  383         link = AcpiOsAllocate(sizeof(struct acpi_pci_link_entry));
  384         if (link == NULL) {
  385                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  386                     "couldn't allocate memory - %s\n", acpi_name(handle)));
  387                 return_ACPI_STATUS (AE_NO_MEMORY);
  388         }
  389 
  390         buf.Pointer = NULL;
  391         buf.Length = ACPI_ALLOCATE_BUFFER;
  392 
  393         bzero(link, sizeof(struct acpi_pci_link_entry));
  394 
  395         link->handle = handle;
  396 
  397         error = acpi_pci_link_get_current_irq(link, &link->current_irq);
  398         if (ACPI_FAILURE(error)) {
  399                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  400                     "couldn't get current IRQ from PCI interrupt link %s - %s\n",
  401                     acpi_name(handle), AcpiFormatException(error)));
  402         }
  403 
  404         link->initial_irq = link->current_irq;
  405 
  406         error = AcpiGetPossibleResources(handle, &buf);
  407         if (ACPI_FAILURE(error)) {
  408                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  409                     "couldn't get PCI interrupt link device _PRS data %s - %s\n",
  410                     acpi_name(handle), AcpiFormatException(error)));
  411                 goto out;
  412         }
  413 
  414         if (buf.Pointer == NULL) {
  415                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  416                     "_PRS nuffer is empty - %s\n", acpi_name(handle)));
  417                 error = AE_NO_MEMORY;
  418                 goto out;
  419         }
  420 
  421         resources = (ACPI_RESOURCE *) buf.Pointer;
  422         bcopy(resources, &link->possible_resources,
  423             sizeof(link->possible_resources));
  424 
  425         error = acpi_pci_link_get_irq_resources(resources,
  426             &link->number_of_interrupts, link->interrupts);
  427         if (ACPI_FAILURE(error)) {
  428                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  429                     "couldn't get possible IRQs from PCI interrupt link %s - %s\n",
  430                     acpi_name(handle), AcpiFormatException(error)));
  431                 goto out;
  432         }
  433 
  434         if (link->number_of_interrupts == 0) {
  435                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  436                     "PCI interrupt link device _PRS data is corrupted - %s\n",
  437                     acpi_name(handle)));
  438                 error = AE_NULL_ENTRY;
  439                 goto out;
  440         }
  441 
  442         link->references++;
  443 
  444         TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
  445         entry->pci_link = link;
  446 
  447         error = AE_OK;
  448 out:
  449         if (buf.Pointer != NULL) {
  450                 AcpiOsFree(buf.Pointer);
  451         }
  452 
  453         if (error != AE_OK && link != NULL) {
  454                 AcpiOsFree(link);
  455         }
  456 
  457         return_ACPI_STATUS (error);
  458 }
  459 
  460 static ACPI_STATUS
  461 acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno)
  462 {
  463         ACPI_HANDLE             handle;
  464         ACPI_STATUS             error;
  465         UINT32                  sta;
  466         struct acpi_prt_entry   *entry;
  467 
  468         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  469 
  470         if ((prt == NULL) || (prt->Source == NULL) || (prt->Source[0] == '\0')) {
  471                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  472                     "couldn't handle this routing table - hardwired\n"));
  473                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  474         }
  475 
  476         error = AcpiGetHandle(acpi_get_handle(pcidev), prt->Source, &handle);
  477         if (ACPI_FAILURE(error)) {
  478                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  479                     "couldn't get acpi handle - %s\n",
  480                     AcpiFormatException(error)));
  481                 return_ACPI_STATUS (error);
  482         }
  483 
  484         error = acpi_pci_link_get_object_status(handle, &sta);
  485         if (ACPI_FAILURE(error)) {
  486                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  487                     "couldn't get object status %s - %s\n",
  488                     acpi_name(handle), AcpiFormatException(error)));
  489                 return_ACPI_STATUS (error);
  490         }
  491 
  492         if (!(sta & (ACPI_STA_PRESENT | ACPI_STA_FUNCTIONAL))) {
  493                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  494                     "PCI interrupt link is not functional - %s\n",
  495                     acpi_name(handle)));
  496                 return_ACPI_STATUS (AE_ERROR);
  497         }
  498 
  499         TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
  500                 if (entry->busno == busno &&
  501                     entry->prt.Address == prt->Address &&
  502                     entry->prt.Pin == prt->Pin) {
  503                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  504                             "PCI interrupt link entry already exists - %s\n",
  505                             acpi_name(handle)));
  506                         return_ACPI_STATUS (AE_ALREADY_EXISTS);
  507                 }
  508         }
  509 
  510         entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry));
  511         if (entry == NULL) {
  512                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  513                     "couldn't allocate memory - %s\n", acpi_name(handle)));
  514                 return_ACPI_STATUS (AE_NO_MEMORY);
  515         }
  516 
  517         bzero(entry, sizeof(struct acpi_prt_entry));
  518 
  519         entry->pcidev = pcidev;
  520         entry->busno = busno;
  521         bcopy(prt, &entry->prt, sizeof(entry->prt));
  522 
  523         error = acpi_pci_link_add_link(handle, entry);
  524         if (ACPI_FAILURE(error)) {
  525                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  526                     "couldn't add prt entry to pci link %s - %s\n",
  527                     acpi_name(handle), AcpiFormatException(error)));
  528                 goto out;
  529         }
  530 
  531         TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links);
  532         error = AE_OK;
  533 
  534 out:
  535         if (error != AE_OK && entry != NULL) {
  536                 AcpiOsFree(entry);
  537         }
  538 
  539         return_ACPI_STATUS (error);
  540 }
  541 
  542 static int
  543 acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq)
  544 {
  545         UINT8                   i;
  546 
  547         if (irq == 0) {
  548                 return (0);
  549         }
  550 
  551         for (i = 0; i < link->number_of_interrupts; i++) {
  552                 if (link->interrupts[i] == irq) {
  553                         return (1);
  554                 }
  555         }
  556 
  557         /* allow initial IRQ as valid one. */
  558         if (link->initial_irq == irq) {
  559                 return (1);
  560         }
  561 
  562         return (0);
  563 }
  564 
  565 static ACPI_STATUS
  566 acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq)
  567 {
  568         ACPI_STATUS             error;
  569         ACPI_RESOURCE           resbuf;
  570         ACPI_BUFFER             crsbuf;
  571         UINT32                  sta;
  572 
  573         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  574 
  575         if (!acpi_pci_link_is_valid_irq(link, irq)) {
  576                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  577                     "couldn't set invalid IRQ %d - %s\n", irq,
  578                     acpi_name(link->handle)));
  579                 return_ACPI_STATUS (AE_BAD_PARAMETER);
  580         }
  581 
  582         error = acpi_pci_link_get_current_irq(link, &link->current_irq);
  583         if (ACPI_FAILURE(error)) {
  584                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  585                     "couldn't get current IRQ from PCI interrupt link %s - %s\n",
  586                     acpi_name(link->handle), AcpiFormatException(error)));
  587         }
  588 
  589         if (link->current_irq == irq) {
  590                 return_ACPI_STATUS (AE_OK);
  591         }
  592 
  593         bzero(&resbuf, sizeof(resbuf));
  594         crsbuf.Pointer = NULL;
  595 
  596         switch (link->possible_resources.Id) {
  597         default:
  598                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  599                     "Resource is not an IRQ entry %s - %d\n",
  600                     acpi_name(link->handle), link->possible_resources.Id));
  601                 return_ACPI_STATUS (AE_TYPE);
  602 
  603         case ACPI_RSTYPE_IRQ:
  604                 resbuf.Id = ACPI_RSTYPE_IRQ;
  605                 resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
  606 
  607                 /* structure copy other fields */
  608                 resbuf.Data.Irq = link->possible_resources.Data.Irq;
  609                 resbuf.Data.Irq.NumberOfInterrupts = 1;
  610                 resbuf.Data.Irq.Interrupts[0] = irq;
  611                 break;
  612 
  613         case ACPI_RSTYPE_EXT_IRQ:
  614                 resbuf.Id = ACPI_RSTYPE_EXT_IRQ;
  615                 resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_EXT_IRQ);
  616 
  617                 /* structure copy other fields */
  618                 resbuf.Data.ExtendedIrq = link->possible_resources.Data.ExtendedIrq;
  619                 resbuf.Data.ExtendedIrq.NumberOfInterrupts = 1;
  620                 resbuf.Data.ExtendedIrq.Interrupts[0] = irq;
  621                 break;
  622         }
  623 
  624         error = acpi_AppendBufferResource(&crsbuf, &resbuf);
  625         if (ACPI_FAILURE(error)) {
  626                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  627                     "couldn't setup buffer by acpi_AppendBufferResource - %s\n",
  628                     acpi_name(link->handle)));
  629                 return_ACPI_STATUS (error);
  630         }
  631 
  632         if (crsbuf.Pointer == NULL) {
  633                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
  634                     "buffer setup by acpi_AppendBufferResource is corrupted - %s\n",
  635                     acpi_name(link->handle)));
  636                 return_ACPI_STATUS (AE_NO_MEMORY);
  637         }
  638 
  639         error = AcpiSetCurrentResources(link->handle, &crsbuf);
  640         if (ACPI_FAILURE(error)) {
  641                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  642                     "couldn't set PCI interrupt link device _SRS %s - %s\n",
  643                     acpi_name(link->handle), AcpiFormatException(error)));
  644                 return_ACPI_STATUS (error);
  645         }
  646 
  647         AcpiOsFree(crsbuf.Pointer);
  648         link->current_irq = 0;
  649 
  650         error = acpi_pci_link_get_object_status(link->handle, &sta);
  651         if (ACPI_FAILURE(error)) {
  652                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  653                     "couldn't get object status %s - %s\n",
  654                     acpi_name(link->handle), AcpiFormatException(error)));
  655                 return_ACPI_STATUS (error);
  656         }
  657 
  658         if (!(sta & ACPI_STA_ENABLE)) {
  659                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  660                     "PCI interrupt link is disabled - %s\n",
  661                     acpi_name(link->handle)));
  662                 return_ACPI_STATUS (AE_ERROR);
  663         }
  664 
  665         error = acpi_pci_link_get_current_irq(link, &link->current_irq);
  666         if (ACPI_FAILURE(error)) {
  667                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  668                     "couldn't get current IRQ from PCI interrupt link %s - %s\n",
  669                     acpi_name(link->handle), AcpiFormatException(error)));
  670                 return_ACPI_STATUS (error);
  671         }
  672 
  673         if (link->current_irq == irq) {
  674                 error = AE_OK;
  675         } else {
  676                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  677                     "couldn't set IRQ %d to PCI interrupt link %d - %s\n",
  678                     irq, link->current_irq, acpi_name(link->handle)));
  679 
  680                 link->current_irq = 0;
  681                 error = AE_ERROR;
  682         }
  683 
  684         return_ACPI_STATUS (error);
  685 }
  686 
  687 /*
  688  * Auto arbitration for boot-disabled devices
  689  */
  690 
  691 static void
  692 acpi_pci_link_bootdisabled_dump(void)
  693 
  694 {
  695         int                     i;
  696         int                     irq;
  697         struct acpi_pci_link_entry *link;
  698 
  699         TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
  700                 /* boot-disabled link only. */
  701                 if (link->current_irq != 0) {
  702                         continue;
  703                 }
  704 
  705                 printf("%s:\n", acpi_name(link->handle));
  706                 printf("        interrupts:     ");
  707                 for (i = 0; i < link->number_of_interrupts; i++) {
  708                         irq = link->sorted_irq[i];
  709                         printf("%6d", irq);
  710                 }
  711                 printf("\n");
  712                 printf("        penalty:        ");
  713                 for (i = 0; i < link->number_of_interrupts; i++) {
  714                         irq = link->sorted_irq[i];
  715                         printf("%6d", irq_penalty[irq]);
  716                 }
  717                 printf("\n");
  718                 printf("        references:     %d\n", link->references);
  719                 printf("        priority:       %d\n", link->priority);
  720         }
  721 }
  722 
  723 static void
  724 acpi_pci_link_init_irq_penalty(void)
  725 {
  726         int                     irq;
  727 
  728         bzero(irq_penalty, sizeof(irq_penalty));
  729         for (irq = 0; irq < MAX_ISA_INTERRUPTS; irq++) {
  730                 /* 0, 1, 2, 8:  timer, keyboard, cascade */
  731                 if (irq == 0 || irq == 1 || irq == 2 || irq == 8) {
  732                         irq_penalty[irq] = 100000;
  733                         continue;
  734                 }
  735 
  736                 /* 13, 14, 15:  npx, ATA controllers */
  737                 if (irq == 13 || irq == 14 || irq == 15) {
  738                         irq_penalty[irq] = 10000;
  739                         continue;
  740                 }
  741 
  742                 /* 3,4,6,7,12:  typicially used by legacy hardware */
  743                 if (irq == 3 || irq == 4 || irq == 6 || irq == 7 || irq == 12) {
  744                         irq_penalty[irq] = 1000;
  745                         continue;
  746                 }
  747         }
  748 }
  749 
  750 static int
  751 acpi_pci_link_is_irq_exclusive(ACPI_RESOURCE *res)
  752 {
  753         if (res == NULL) {
  754                 return (0);
  755         }
  756 
  757         if (res->Id != ACPI_RSTYPE_IRQ &&
  758             res->Id != ACPI_RSTYPE_EXT_IRQ) {
  759                 return (0);
  760         }
  761 
  762         if (res->Id == ACPI_RSTYPE_IRQ &&
  763             res->Data.Irq.SharedExclusive == ACPI_EXCLUSIVE) {
  764                 return (1);
  765         }
  766 
  767         if (res->Id == ACPI_RSTYPE_EXT_IRQ &&
  768             res->Data.ExtendedIrq.SharedExclusive == ACPI_EXCLUSIVE) {
  769                 return (1);
  770         }
  771 
  772         return (0);
  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         TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
  786                 if (entry->busno != busno) {
  787                         continue;
  788                 }
  789 
  790                 link = entry->pci_link;
  791                 if (link == NULL) {
  792                         continue;       /* impossible... */
  793                 }
  794 
  795                 if (link->current_irq != 0) {
  796                         /* not boot-disabled link, we will use this IRQ. */
  797                         irq_penalty[link->current_irq] += 100;
  798                         continue;
  799                 }
  800 
  801                 /* boot-disabled link */
  802                 for (i = 0; i < link->number_of_interrupts; i++) {
  803                         /* give 10 for each possible IRQs. */
  804                         irq = link->interrupts[i];
  805                         irq_penalty[irq] += 10;
  806 
  807                         /* higher penalty if exclusive. */
  808                         if (acpi_pci_link_is_irq_exclusive(&link->possible_resources)) {
  809                                 irq_penalty[irq] += 100;
  810                         }
  811 
  812                         /* XXX try to get this IRQ in non-sharable mode. */
  813                         rid = 0;
  814                         res = bus_alloc_resource(dev, SYS_RES_IRQ,
  815                                                  &rid, irq, irq, 1, 0);
  816                         if (res != NULL) {
  817                                 bus_release_resource(dev, SYS_RES_IRQ,
  818                                     rid, res);
  819                         } else {
  820                                 /* this is in use, give 100. */
  821                                 irq_penalty[irq] += 100;
  822                         }
  823                 }
  824 
  825                 /* initialize `sorted' possible IRQs. */
  826                 bcopy(link->interrupts, link->sorted_irq,
  827                     sizeof(link->sorted_irq));
  828         }
  829 }
  830 
  831 static void
  832 acpi_pci_link_set_bootdisabled_priority(void)
  833 {
  834         int                     sum_penalty;
  835         int                     i;
  836         int                     irq;
  837         struct acpi_pci_link_entry *link, *link_pri;
  838         TAILQ_HEAD(, acpi_pci_link_entry) sorted_list;
  839 
  840         if (bootverbose) {
  841                 printf("---- before setting priority for links ------------\n");
  842                 acpi_pci_link_bootdisabled_dump();
  843         }
  844 
  845         /* reset priority for all links. */
  846         TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
  847                 link->priority = 0;
  848         }
  849 
  850         TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
  851                 /* not boot-disabled link, give no chance to be arbitrated. */
  852                 if (link->current_irq != 0) {
  853                         link->priority = 0;
  854                         continue;
  855                 }
  856 
  857                 /*
  858                  * Calculate the priority for each boot-disabled links.
  859                  * o IRQ penalty indicates difficulty to use. 
  860                  * o #references for devices indicates importance of the link.
  861                  * o #interrupts indicates flexibility of the link.
  862                  */
  863                 sum_penalty = 0;
  864                 for (i = 0; i < link->number_of_interrupts; i++) {
  865                         irq = link->interrupts[i];
  866                         sum_penalty += irq_penalty[irq];
  867                 }
  868 
  869                 link->priority = (sum_penalty * link->references) / link->number_of_interrupts;
  870         }
  871 
  872         /*
  873          * Sort PCI links based on the priority.
  874          * XXX Any other better ways rather than using work list?
  875          */
  876         TAILQ_INIT(&sorted_list);
  877         while (!TAILQ_EMPTY(&acpi_pci_link_entries)) {
  878                 link = TAILQ_FIRST(&acpi_pci_link_entries);
  879                 /* find an entry which has the highest priority. */
  880                 TAILQ_FOREACH(link_pri, &acpi_pci_link_entries, links) {
  881                         if (link->priority < link_pri->priority) {
  882                                 link = link_pri;
  883                         }
  884                 }
  885                 /* move to work list. */
  886                 TAILQ_REMOVE(&acpi_pci_link_entries, link, links);
  887                 TAILQ_INSERT_TAIL(&sorted_list, link, links);
  888         }
  889 
  890         while (!TAILQ_EMPTY(&sorted_list)) {
  891                 /* move them back to the list, one by one... */
  892                 link = TAILQ_FIRST(&sorted_list);
  893                 TAILQ_REMOVE(&sorted_list, link, links);
  894                 TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
  895         }
  896 }
  897 
  898 static void
  899 acpi_pci_link_fixup_bootdisabled_link(void)
  900 {
  901         int                     i, j;
  902         int                     irq1, irq2;
  903         struct acpi_pci_link_entry *link;
  904         ACPI_STATUS             error;
  905 
  906         if (bootverbose) {
  907                 printf("---- before fixup boot-disabled links -------------\n");
  908                 acpi_pci_link_bootdisabled_dump();
  909         }
  910 
  911         TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
  912                 /* ignore non boot-disabled links. */
  913                 if (link->current_irq != 0) {
  914                         continue;
  915                 }
  916 
  917                 /* sort IRQs based on their penalty descending. */
  918                 for (i = 0; i < link->number_of_interrupts; i++) {
  919                         irq1 = link->sorted_irq[i];
  920                         for (j = i + 1; j < link->number_of_interrupts; j++) {
  921                                 irq2 = link->sorted_irq[j];
  922                                 if (irq_penalty[irq1] < irq_penalty[irq2]) {
  923                                         continue;
  924                                 }
  925                                 link->sorted_irq[i] = irq2;
  926                                 link->sorted_irq[j] = irq1;
  927                                 irq1 = irq2;
  928                         }
  929                 }
  930 
  931                 /* try with lower penalty IRQ. */
  932                 for (i = 0; i < link->number_of_interrupts; i++) {
  933                         irq1 = link->sorted_irq[i];
  934                         error = acpi_pci_link_set_irq(link, irq1);
  935                         if (error == AE_OK) {
  936                                 /* OK, we use this.  give another penalty. */
  937                                 irq_penalty[irq1] += 100 * link->references;
  938                                 break;
  939                         }
  940                         /* NG, try next IRQ... */
  941                 }
  942         }
  943 
  944         if (bootverbose) {
  945                 printf("---- after fixup boot-disabled links --------------\n");
  946                 acpi_pci_link_bootdisabled_dump();
  947         }
  948 }
  949 
  950 /*
  951  * Public interface
  952  */
  953 
  954 int
  955 acpi_pci_link_config(device_t dev, ACPI_BUFFER *prtbuf, int busno)
  956 {
  957         struct acpi_prt_entry   *entry;
  958         ACPI_PCI_ROUTING_TABLE  *prt;
  959         u_int8_t                *prtp;
  960         ACPI_STATUS             error;
  961         static int              first_time =1;
  962 
  963         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  964 
  965         if (acpi_disabled("pci_link")) {
  966                 return (0);
  967         }
  968 
  969         if (first_time) {
  970                 TAILQ_INIT(&acpi_prt_entries);
  971                 TAILQ_INIT(&acpi_pci_link_entries);
  972                 acpi_pci_link_init_irq_penalty();
  973                 first_time = 0;
  974         }
  975 
  976         if (prtbuf == NULL) {
  977                 return (-1);
  978         }
  979 
  980         prtp = prtbuf->Pointer;
  981         if (prtp == NULL) {             /* didn't get routing table */
  982                 return (-1);
  983         }
  984 
  985         /* scan the PCI Routing Table */
  986         for (;;) {
  987                 prt = (ACPI_PCI_ROUTING_TABLE *)prtp;
  988 
  989                 if (prt->Length == 0)   /* end of table */
  990                     break;
  991 
  992                 error = acpi_pci_link_add_prt(dev, prt, busno);
  993                 if (ACPI_FAILURE(error)) {
  994                         ACPI_DEBUG_PRINT((ACPI_DB_WARN,
  995                             "couldn't add PCI interrupt link entry - %s\n",
  996                             AcpiFormatException(error)));
  997                 }
  998 
  999                 /* skip to next entry */
 1000                 prtp += prt->Length;
 1001         }
 1002 
 1003         if (bootverbose) {
 1004                 printf("---- initial configuration ------------------------\n");
 1005                 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
 1006                         if (entry->busno != busno) {
 1007                                 continue;
 1008                         }
 1009 
 1010                         acpi_pci_link_entry_dump(entry);
 1011                 }
 1012         }
 1013 
 1014         /* manual configuration. */
 1015         TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
 1016                 UINT8                   irq;
 1017                 char                    *irqstr, *op;
 1018                 char                    prthint[32];
 1019 
 1020                 if (entry->busno != busno) {
 1021                         continue;
 1022                 }
 1023 
 1024                 snprintf(prthint, sizeof(prthint),
 1025                     "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno,
 1026                     (int)((entry->prt.Address & 0xffff0000) >> 16),
 1027                     (int)entry->prt.Pin);
 1028 
 1029                 irqstr = getenv(prthint);
 1030                 if (irqstr == NULL) {
 1031                         continue;
 1032                 }
 1033 
 1034                 irq = strtoul(irqstr, &op, 0);
 1035                 if (*op != '\0') {
 1036                         continue;
 1037                 }
 1038 
 1039                 if (acpi_pci_link_is_valid_irq(entry->pci_link, irq)) {
 1040                         error = acpi_pci_link_set_irq(entry->pci_link, irq);
 1041                         if (ACPI_FAILURE(error)) {
 1042                                 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
 1043                                     "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
 1044                                     acpi_name(entry->pci_link->handle),
 1045                                     AcpiFormatException(error)));
 1046                         }
 1047                         continue;
 1048                 }
 1049 
 1050                 /*
 1051                  * Do auto arbitration for this device's PCI link
 1052                  * if hint value 0 is specified.
 1053                  */
 1054                 if (irq == 0) {
 1055                         entry->pci_link->current_irq = 0;
 1056                 }
 1057         }
 1058 
 1059         /* auto arbitration */
 1060         acpi_pci_link_update_irq_penalty(dev, busno);
 1061         acpi_pci_link_set_bootdisabled_priority();
 1062         acpi_pci_link_fixup_bootdisabled_link();
 1063 
 1064         if (bootverbose) {
 1065                 printf("---- arbitrated configuration ---------------------\n");
 1066                 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
 1067                         if (entry->busno != busno) {
 1068                                 continue;
 1069                         }
 1070 
 1071                         acpi_pci_link_entry_dump(entry);
 1072                 }
 1073         }
 1074 
 1075         return (0);
 1076 }
 1077 
 1078 int
 1079 acpi_pci_link_resume(device_t dev, ACPI_BUFFER *prtbuf, int busno)
 1080 {
 1081         struct acpi_prt_entry   *entry;
 1082         ACPI_STATUS             error;
 1083 
 1084         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 1085 
 1086         if (acpi_disabled("pci_link")) {
 1087                 return (0);
 1088         }
 1089 
 1090         TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
 1091                 if (entry->pcidev != dev) {
 1092                         continue;
 1093                 }
 1094 
 1095                 error = acpi_pci_link_set_irq(entry->pci_link,
 1096                             entry->pci_link->current_irq);
 1097                 if (ACPI_FAILURE(error)) {
 1098                         ACPI_DEBUG_PRINT((ACPI_DB_WARN,
 1099                             "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
 1100                             acpi_name(entry->pci_link->handle),
 1101                             AcpiFormatException(error)));
 1102                 }
 1103         }
 1104 
 1105         return (0);
 1106 }
 1107 

Cache object: c27fe6290611e15cbbbe09573d8f2d7f


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