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_pcib.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2000 Michael Smith
    3  * Copyright (c) 2000 BSDi
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD: src/sys/dev/acpica/acpi_pcib.c,v 1.60.8.1 2009/04/15 03:14:26 kensmith Exp $
   28  */
   29 
   30 #include "opt_acpi.h"
   31 #include <sys/param.h>
   32 #include <sys/bus.h>
   33 #include <sys/malloc.h>
   34 #include <sys/kernel.h>
   35 #include <sys/machintr.h>
   36 #include <machine/smp.h>
   37 
   38 #include "acpi.h"
   39 #include <dev/acpica/acpivar.h>
   40 #include <dev/acpica/acpi_pcibvar.h>
   41 
   42 #include <bus/pci/pcivar.h>
   43 #include <bus/pci/pcireg.h>
   44 #include <bus/pci/pci_cfgreg.h>
   45 #include "pcib_if.h"
   46 
   47 /* Hooks for the ACPI CA debugging infrastructure. */
   48 #define _COMPONENT      ACPI_BUS
   49 ACPI_MODULE_NAME("PCI")
   50 
   51 ACPI_SERIAL_DECL(pcib, "ACPI PCI bus methods");
   52 
   53 /*
   54  * For locking, we assume the caller is not concurrent since this is
   55  * triggered by newbus methods.
   56  */
   57 
   58 struct prt_lookup_request {
   59     ACPI_PCI_ROUTING_TABLE *pr_entry;
   60     u_int       pr_pin;
   61     u_int       pr_slot;
   62 };
   63 
   64 typedef void prt_entry_handler(ACPI_PCI_ROUTING_TABLE *entry, void *arg);
   65 
   66 static void     prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg);
   67 static void     prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg);
   68 static void     prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler,
   69                     void *arg);
   70 
   71 static void
   72 prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, void *arg)
   73 {
   74     ACPI_PCI_ROUTING_TABLE *entry;
   75     char *prtptr;
   76 
   77     /* First check to see if there is a table to walk. */
   78     if (prt == NULL || prt->Pointer == NULL)
   79         return;
   80 
   81     /* Walk the table executing the handler function for each entry. */
   82     prtptr = prt->Pointer;
   83     entry = (ACPI_PCI_ROUTING_TABLE *)prtptr;
   84     while (entry->Length != 0) {
   85         handler(entry, arg);
   86         prtptr += entry->Length;
   87         entry = (ACPI_PCI_ROUTING_TABLE *)prtptr;
   88     }
   89 }
   90 
   91 static void
   92 prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg)
   93 {
   94     ACPI_HANDLE handle;
   95     device_t child, pcib;
   96     int error;
   97 
   98     /* We only care about entries that reference a link device. */
   99     if (entry->Source == NULL || entry->Source[0] == '\0')
  100         return;
  101 
  102     /*
  103      * In practice, we only see SourceIndex's of 0 out in the wild.
  104      * When indices != 0 have been found, they've been bugs in the ASL.
  105      */
  106     if (entry->SourceIndex != 0)
  107         return;
  108 
  109     /* Lookup the associated handle and device. */
  110     pcib = (device_t)arg;
  111     if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, entry->Source, &handle)))
  112         return;
  113     child = acpi_get_device(handle);
  114     if (child == NULL)
  115         return;
  116 
  117     /* If the device hasn't been probed yet, force it to do so. */
  118     error = device_probe_and_attach(child);
  119     if (error != 0) {
  120         device_printf(pcib, "failed to force attach of %s\n",
  121             acpi_name(handle));
  122         return;
  123     }
  124 
  125     /* Add a reference for a specific bus/device/pin tuple. */
  126     acpi_pci_link_add_reference(child, entry->SourceIndex, pcib,
  127         ACPI_ADR_PCI_SLOT(entry->Address), entry->Pin);
  128 }
  129 
  130 int
  131 acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno)
  132 {
  133     device_t                    child;
  134     ACPI_STATUS                 status;
  135 
  136     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  137 
  138     if (!acpi_DeviceIsPresent(dev)) {
  139         /* Caller should already have checked it */
  140         panic("%s device is not present", __func__);
  141     }
  142 
  143     ACPI_SERIAL_INIT(pcib);
  144 
  145     /*
  146      * Get the PCI interrupt routing table for this bus.  If we can't
  147      * get it, this is not an error but may reduce functionality.  There
  148      * are several valid bridges in the field that do not have a _PRT, so
  149      * only warn about missing tables if bootverbose is set.
  150      */
  151     prt->Length = ACPI_ALLOCATE_BUFFER;
  152     status = AcpiGetIrqRoutingTable(acpi_get_handle(dev), prt);
  153     if (ACPI_FAILURE(status) && (bootverbose || status != AE_NOT_FOUND))
  154         device_printf(dev,
  155             "could not get PCI interrupt routing table for %s - %s\n",
  156             acpi_name(acpi_get_handle(dev)), AcpiFormatException(status));
  157 
  158     /*
  159      * Attach the PCI bus proper.
  160      */
  161     if ((child = device_add_child(dev, "pci", busno)) == NULL) {
  162         device_printf(device_get_parent(dev), "couldn't attach pci bus\n");
  163         return_VALUE(ENXIO);
  164     }
  165 
  166     /*
  167      * Now go scan the bus.
  168      */
  169     prt_walk_table(prt, prt_attach_devices, dev);
  170 
  171     return_VALUE (bus_generic_attach(dev));
  172 }
  173 
  174 int
  175 acpi_pcib_resume(device_t dev)
  176 {
  177 
  178     return (bus_generic_resume(dev));
  179 }
  180 
  181 static void
  182 prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg)
  183 {
  184     struct prt_lookup_request *pr;
  185 
  186     pr = (struct prt_lookup_request *)arg;
  187     if (pr->pr_entry != NULL)
  188         return;
  189 
  190     /*
  191      * Compare the slot number (high word of Address) and pin number
  192      * (note that ACPI uses 0 for INTA) to check for a match.
  193      *
  194      * Note that the low word of the Address field (function number)
  195      * is required by the specification to be 0xffff.  We don't risk
  196      * checking it here.
  197      */
  198     if (ACPI_ADR_PCI_SLOT(entry->Address) == pr->pr_slot &&
  199         entry->Pin == pr->pr_pin)
  200             pr->pr_entry = entry;
  201 }
  202 
  203 /*
  204  * Route an interrupt for a child of the bridge.
  205  */
  206 int
  207 acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
  208     ACPI_BUFFER *prtbuf)
  209 {
  210     ACPI_PCI_ROUTING_TABLE *prt;
  211     struct prt_lookup_request pr;
  212     ACPI_HANDLE lnkdev;
  213     int interrupt;
  214 
  215     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  216 
  217     interrupt = PCI_INVALID_IRQ;
  218 
  219     /* ACPI numbers pins 0-3, not 1-4 like the BIOS. */
  220     pin--;
  221 
  222     ACPI_SERIAL_BEGIN(pcib);
  223 
  224     /* Search for a matching entry in the routing table. */
  225     pr.pr_entry = NULL;
  226     pr.pr_pin = pin;
  227     pr.pr_slot = pci_get_slot(dev);
  228     prt_walk_table(prtbuf, prt_lookup_device, &pr);
  229     if (pr.pr_entry == NULL) {
  230         device_printf(pcib, "no PRT entry for %d.%d.INT%c\n", pci_get_bus(dev),
  231             pci_get_slot(dev), 'A' + pin);
  232         goto out;
  233     }
  234     prt = pr.pr_entry;
  235 
  236     if (bootverbose) {
  237         device_printf(pcib, "matched entry for %d.%d.INT%c",
  238             pci_get_bus(dev), pci_get_slot(dev), 'A' + pin);
  239         if (prt->Source != NULL && prt->Source[0] != '\0')
  240                 kprintf(" (src %s:%u)", prt->Source, prt->SourceIndex);
  241         kprintf("\n");
  242     }
  243 
  244     /*
  245      * If source is empty/NULL, the source index is a GSI and it's hardwired
  246      * so we're done.
  247      *
  248      * XXX: If the source index is non-zero, ignore the source device and
  249      * assume that this is a hardwired entry.
  250      */
  251     if (prt->Source == NULL || prt->Source[0] == '\0' ||
  252         prt->SourceIndex != 0) {
  253         if (prt->SourceIndex) {
  254             interrupt = machintr_legacy_intr_find_bygsi(prt->SourceIndex,
  255                 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
  256             if (interrupt < 0) {
  257                 device_printf(pcib, "slot %d INT%c hardwired to "
  258                     "invalid GSI %d\n", pci_get_slot(dev), 'A' + pin,
  259                     prt->SourceIndex);
  260                 interrupt = PCI_INVALID_IRQ;
  261                 goto out;
  262             }
  263             if (bootverbose) {
  264                 device_printf(pcib, "slot %d INT%c hardwired to "
  265                     "GSI %d, IRQ %d\n", pci_get_slot(dev), 'A' + pin,
  266                     prt->SourceIndex, interrupt);
  267             }
  268 
  269             BUS_CONFIG_INTR(device_get_parent(dev), dev, interrupt,
  270                 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
  271         } else {
  272             device_printf(pcib, "invalid hardwired GSI 0\n");
  273         }
  274         goto out;
  275     }
  276 
  277     /*
  278      * We have to find the source device (PCI interrupt link device).
  279      */
  280     if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) {
  281         device_printf(pcib, "couldn't find PCI interrupt link device %s\n",
  282             prt->Source);
  283         goto out;
  284     }
  285     interrupt = acpi_pci_link_route_interrupt(acpi_get_device(lnkdev),
  286         prt->SourceIndex);
  287 
  288     if (bootverbose && PCI_INTERRUPT_VALID(interrupt)) {
  289         device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n",
  290             pci_get_slot(dev), 'A' + pin, interrupt, acpi_name(lnkdev));
  291     }
  292 
  293 out:
  294     ACPI_SERIAL_END(pcib);
  295 
  296     return_VALUE (interrupt);
  297 }
  298 
  299 int
  300 acpi_pcib_probe(device_t dev)
  301 {
  302     /*
  303      * Don't attach if we're not really there.
  304      *
  305      * XXX: This isn't entirely correct since we may be a PCI bus
  306      * on a hot-plug docking station, etc.
  307      */
  308     if (!acpi_DeviceIsPresent(dev))
  309         return ENXIO;
  310 
  311     if (pci_cfgregopen() == 0)
  312         return ENXIO;
  313 
  314     return 0;
  315 }

Cache object: 3d9860638d58f97ae530d5e27006b8e4


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