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

Cache object: 336fe9b58154401905a052b467d91a96


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