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.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) 1997, Stefan Esser <se@freebsd.org>
    3  * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
    4  * Copyright (c) 2000, BSDi
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice unmodified, this list of conditions, and the following
   12  *    disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include "opt_acpi.h"
   33 #include "opt_iommu.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/bus.h>
   38 #include <sys/kernel.h>
   39 #include <sys/malloc.h>
   40 #include <sys/module.h>
   41 #include <sys/sbuf.h>
   42 #include <sys/taskqueue.h>
   43 #include <sys/tree.h>
   44 
   45 #include <contrib/dev/acpica/include/acpi.h>
   46 #include <contrib/dev/acpica/include/accommon.h>
   47 
   48 #include <dev/acpica/acpivar.h>
   49 #include <dev/acpica/acpi_pcivar.h>
   50 
   51 #include <sys/pciio.h>
   52 #include <dev/pci/pcireg.h>
   53 #include <dev/pci/pcivar.h>
   54 #include <dev/pci/pci_private.h>
   55 
   56 #include <dev/iommu/iommu.h>
   57 
   58 #include "pcib_if.h"
   59 #include "pci_if.h"
   60 
   61 /* Hooks for the ACPI CA debugging infrastructure. */
   62 #define _COMPONENT      ACPI_BUS
   63 ACPI_MODULE_NAME("PCI")
   64 
   65 struct acpi_pci_devinfo {
   66         struct pci_devinfo      ap_dinfo;
   67         ACPI_HANDLE             ap_handle;
   68         int                     ap_flags;
   69 };
   70 
   71 ACPI_SERIAL_DECL(pci_powerstate, "ACPI PCI power methods");
   72 
   73 /* Be sure that ACPI and PCI power states are equivalent. */
   74 CTASSERT(ACPI_STATE_D0 == PCI_POWERSTATE_D0);
   75 CTASSERT(ACPI_STATE_D1 == PCI_POWERSTATE_D1);
   76 CTASSERT(ACPI_STATE_D2 == PCI_POWERSTATE_D2);
   77 CTASSERT(ACPI_STATE_D3 == PCI_POWERSTATE_D3);
   78 
   79 static struct pci_devinfo *acpi_pci_alloc_devinfo(device_t dev);
   80 static int      acpi_pci_attach(device_t dev);
   81 static void     acpi_pci_child_deleted(device_t dev, device_t child);
   82 static int      acpi_pci_child_location_method(device_t cbdev,
   83                     device_t child, struct sbuf *sb);
   84 static int      acpi_pci_get_device_path(device_t cbdev,
   85                     device_t child, const char *locator, struct sbuf *sb);
   86 static int      acpi_pci_detach(device_t dev);
   87 static int      acpi_pci_probe(device_t dev);
   88 static int      acpi_pci_read_ivar(device_t dev, device_t child, int which,
   89                     uintptr_t *result);
   90 static int      acpi_pci_write_ivar(device_t dev, device_t child, int which,
   91                     uintptr_t value);
   92 static ACPI_STATUS acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level,
   93                     void *context, void **status);
   94 static int      acpi_pci_set_powerstate_method(device_t dev, device_t child,
   95                     int state);
   96 static void     acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child);
   97 static bus_dma_tag_t acpi_pci_get_dma_tag(device_t bus, device_t child);
   98 
   99 static device_method_t acpi_pci_methods[] = {
  100         /* Device interface */
  101         DEVMETHOD(device_probe,         acpi_pci_probe),
  102         DEVMETHOD(device_attach,        acpi_pci_attach),
  103         DEVMETHOD(device_detach,        acpi_pci_detach),
  104 
  105         /* Bus interface */
  106         DEVMETHOD(bus_read_ivar,        acpi_pci_read_ivar),
  107         DEVMETHOD(bus_write_ivar,       acpi_pci_write_ivar),
  108         DEVMETHOD(bus_child_deleted,    acpi_pci_child_deleted),
  109         DEVMETHOD(bus_child_location,   acpi_pci_child_location_method),
  110         DEVMETHOD(bus_get_device_path,  acpi_pci_get_device_path),
  111         DEVMETHOD(bus_get_cpus,         acpi_get_cpus),
  112         DEVMETHOD(bus_get_dma_tag,      acpi_pci_get_dma_tag),
  113         DEVMETHOD(bus_get_domain,       acpi_get_domain),
  114 
  115         /* PCI interface */
  116         DEVMETHOD(pci_alloc_devinfo,    acpi_pci_alloc_devinfo),
  117         DEVMETHOD(pci_child_added,      acpi_pci_child_added),
  118         DEVMETHOD(pci_set_powerstate,   acpi_pci_set_powerstate_method),
  119 
  120         DEVMETHOD_END
  121 };
  122 
  123 DEFINE_CLASS_1(pci, acpi_pci_driver, acpi_pci_methods, sizeof(struct pci_softc),
  124     pci_driver);
  125 DRIVER_MODULE(acpi_pci, pcib, acpi_pci_driver, 0, 0);
  126 MODULE_DEPEND(acpi_pci, acpi, 1, 1, 1);
  127 MODULE_DEPEND(acpi_pci, pci, 1, 1, 1);
  128 MODULE_VERSION(acpi_pci, 1);
  129 
  130 static struct pci_devinfo *
  131 acpi_pci_alloc_devinfo(device_t dev)
  132 {
  133         struct acpi_pci_devinfo *dinfo;
  134 
  135         dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
  136         return (&dinfo->ap_dinfo);
  137 }
  138 
  139 static int
  140 acpi_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
  141 {
  142     struct acpi_pci_devinfo *dinfo;
  143 
  144     dinfo = device_get_ivars(child);
  145     switch (which) {
  146     case ACPI_IVAR_HANDLE:
  147         *result = (uintptr_t)dinfo->ap_handle;
  148         return (0);
  149     case ACPI_IVAR_FLAGS:
  150         *result = (uintptr_t)dinfo->ap_flags;
  151         return (0);
  152     }
  153     return (pci_read_ivar(dev, child, which, result));
  154 }
  155 
  156 static int
  157 acpi_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
  158 {
  159     struct acpi_pci_devinfo *dinfo;
  160 
  161     dinfo = device_get_ivars(child);
  162     switch (which) {
  163     case ACPI_IVAR_HANDLE:
  164         dinfo->ap_handle = (ACPI_HANDLE)value;
  165         return (0);
  166     case ACPI_IVAR_FLAGS:
  167         dinfo->ap_flags = (int)value;
  168         return (0);
  169     }
  170     return (pci_write_ivar(dev, child, which, value));
  171 }
  172 
  173 static void
  174 acpi_pci_child_deleted(device_t dev, device_t child)
  175 {
  176         struct acpi_pci_devinfo *dinfo = device_get_ivars(child);
  177 
  178         if (acpi_get_device(dinfo->ap_handle) == child)
  179                 AcpiDetachData(dinfo->ap_handle, acpi_fake_objhandler);
  180         pci_child_deleted(dev, child);
  181 }
  182 
  183 static int
  184 acpi_pci_child_location_method(device_t cbdev, device_t child, struct sbuf *sb)
  185 {
  186         struct acpi_pci_devinfo *dinfo = device_get_ivars(child);
  187         int pxm;
  188 
  189         pci_child_location_method(cbdev, child, sb);
  190 
  191         if (dinfo->ap_handle) {
  192                 sbuf_printf(sb, " handle=%s", acpi_name(dinfo->ap_handle));
  193                 if (ACPI_SUCCESS(acpi_GetInteger(dinfo->ap_handle, "_PXM", &pxm))) {
  194                         sbuf_printf(sb, " _PXM=%d", pxm);
  195                 }
  196         }
  197         return (0);
  198 }
  199 
  200 static int
  201 acpi_pci_get_device_path(device_t bus, device_t child, const char *locator, struct sbuf *sb)
  202 {
  203 
  204         if (strcmp(locator, BUS_LOCATOR_ACPI) == 0)
  205                 return (acpi_get_acpi_device_path(bus, child, locator, sb));
  206 
  207         /* Otherwise follow base class' actions */
  208         return  (pci_get_device_path_method(bus, child, locator, sb));
  209 }
  210 
  211 /*
  212  * PCI power manangement
  213  */
  214 static int
  215 acpi_pci_set_powerstate_method(device_t dev, device_t child, int state)
  216 {
  217         ACPI_HANDLE h;
  218         ACPI_STATUS status;
  219         int old_state, error;
  220 
  221         error = 0;
  222         if (state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
  223                 return (EINVAL);
  224 
  225         /*
  226          * We set the state using PCI Power Management outside of setting
  227          * the ACPI state.  This means that when powering down a device, we
  228          * first shut it down using PCI, and then using ACPI, which lets ACPI
  229          * try to power down any Power Resources that are now no longer used.
  230          * When powering up a device, we let ACPI set the state first so that
  231          * it can enable any needed Power Resources before changing the PCI
  232          * power state.
  233          */
  234         ACPI_SERIAL_BEGIN(pci_powerstate);
  235         old_state = pci_get_powerstate(child);
  236         if (old_state < state && pci_do_power_suspend) {
  237                 error = pci_set_powerstate_method(dev, child, state);
  238                 if (error)
  239                         goto out;
  240         }
  241         h = acpi_get_handle(child);
  242         status = acpi_pwr_switch_consumer(h, state);
  243         if (ACPI_SUCCESS(status)) {
  244                 if (bootverbose)
  245                         device_printf(dev, "set ACPI power state D%d on %s\n",
  246                             state, acpi_name(h));
  247         } else if (status != AE_NOT_FOUND)
  248                 device_printf(dev,
  249                     "failed to set ACPI power state D%d on %s: %s\n",
  250                     state, acpi_name(h), AcpiFormatException(status));
  251         if (old_state > state && pci_do_power_resume)
  252                 error = pci_set_powerstate_method(dev, child, state);
  253 
  254 out:
  255         ACPI_SERIAL_END(pci_powerstate);
  256         return (error);
  257 }
  258 
  259 static void
  260 acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child)
  261 {
  262         ACPI_STATUS status;
  263         device_t child;
  264 
  265         /*
  266          * Occasionally a PCI device may show up as an ACPI device
  267          * with a _HID.  (For example, the TabletPC TC1000 has a
  268          * second PCI-ISA bridge that has a _HID for an
  269          * acpi_sysresource device.)  In that case, leave ACPI-CA's
  270          * device data pointing at the ACPI-enumerated device.
  271          */
  272         child = acpi_get_device(handle);
  273         if (child != NULL) {
  274                 KASSERT(device_get_parent(child) ==
  275                     devclass_get_device(devclass_find("acpi"), 0),
  276                     ("%s: child (%s)'s parent is not acpi0", __func__,
  277                     acpi_name(handle)));
  278                 return;
  279         }
  280 
  281         /*
  282          * Update ACPI-CA to use the PCI enumerated device_t for this handle.
  283          */
  284         status = AcpiAttachData(handle, acpi_fake_objhandler, pci_child);
  285         if (ACPI_FAILURE(status))
  286                 printf("WARNING: Unable to attach object data to %s - %s\n",
  287                     acpi_name(handle), AcpiFormatException(status));
  288 }
  289 
  290 static ACPI_STATUS
  291 acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level, void *context,
  292     void **status)
  293 {
  294         struct acpi_pci_devinfo *dinfo;
  295         device_t child;
  296         int func, slot;
  297         UINT32 address;
  298 
  299         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  300 
  301         child = context;
  302         if (ACPI_FAILURE(acpi_GetInteger(handle, "_ADR", &address)))
  303                 return_ACPI_STATUS (AE_OK);
  304         slot = ACPI_ADR_PCI_SLOT(address);
  305         func = ACPI_ADR_PCI_FUNC(address);
  306         dinfo = device_get_ivars(child);
  307         if (dinfo->ap_dinfo.cfg.func == func &&
  308             dinfo->ap_dinfo.cfg.slot == slot) {
  309                 dinfo->ap_handle = handle;
  310                 acpi_pci_update_device(handle, child);
  311                 return_ACPI_STATUS (AE_CTRL_TERMINATE);
  312         }
  313         return_ACPI_STATUS (AE_OK);
  314 }
  315 
  316 void
  317 acpi_pci_child_added(device_t dev, device_t child)
  318 {
  319 
  320         /*
  321          * PCI devices are added via the bus scan in the normal PCI
  322          * bus driver.  As each device is added, the
  323          * acpi_pci_child_added() callback walks the ACPI namespace
  324          * under the bridge driver to save ACPI handles to all the
  325          * devices that appear in the ACPI namespace as immediate
  326          * descendants of the bridge.
  327          *
  328          * XXX: Sometimes PCI devices show up in the ACPI namespace that
  329          * pci_add_children() doesn't find.  We currently just ignore
  330          * these devices.
  331          */
  332         AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
  333             acpi_pci_save_handle, NULL, child, NULL);
  334 }
  335 
  336 static int
  337 acpi_pci_probe(device_t dev)
  338 {
  339 
  340         if (acpi_get_handle(dev) == NULL)
  341                 return (ENXIO);
  342         device_set_desc(dev, "ACPI PCI bus");
  343         return (BUS_PROBE_DEFAULT);
  344 }
  345 
  346 static void
  347 acpi_pci_bus_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
  348 {
  349         device_t dev;
  350 
  351         dev = context;
  352 
  353         switch (notify) {
  354         case ACPI_NOTIFY_BUS_CHECK:
  355                 bus_topo_lock();
  356                 BUS_RESCAN(dev);
  357                 bus_topo_unlock();
  358                 break;
  359         default:
  360                 device_printf(dev, "unknown notify %#x\n", notify);
  361                 break;
  362         }
  363 }
  364 
  365 static void
  366 acpi_pci_device_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
  367 {
  368         device_t child, dev;
  369         ACPI_STATUS status;
  370         int error;
  371 
  372         dev = context;
  373 
  374         switch (notify) {
  375         case ACPI_NOTIFY_DEVICE_CHECK:
  376                 bus_topo_lock();
  377                 BUS_RESCAN(dev);
  378                 bus_topo_unlock();
  379                 break;
  380         case ACPI_NOTIFY_EJECT_REQUEST:
  381                 child = acpi_get_device(h);
  382                 if (child == NULL) {
  383                         device_printf(dev, "no device to eject for %s\n",
  384                             acpi_name(h));
  385                         return;
  386                 }
  387                 bus_topo_lock();
  388                 error = device_detach(child);
  389                 if (error) {
  390                         bus_topo_unlock();
  391                         device_printf(dev, "failed to detach %s: %d\n",
  392                             device_get_nameunit(child), error);
  393                         return;
  394                 }
  395                 status = acpi_SetInteger(h, "_EJ0", 1);
  396                 if (ACPI_FAILURE(status)) {
  397                         bus_topo_unlock();
  398                         device_printf(dev, "failed to eject %s: %s\n",
  399                             acpi_name(h), AcpiFormatException(status));
  400                         return;
  401                 }
  402                 BUS_RESCAN(dev);
  403                 bus_topo_unlock();
  404                 break;
  405         default:
  406                 device_printf(dev, "unknown notify %#x for %s\n", notify,
  407                     acpi_name(h));
  408                 break;
  409         }
  410 }
  411 
  412 static ACPI_STATUS
  413 acpi_pci_install_device_notify_handler(ACPI_HANDLE handle, UINT32 level,
  414     void *context, void **status)
  415 {
  416         ACPI_HANDLE h;
  417 
  418         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  419 
  420         if (ACPI_FAILURE(AcpiGetHandle(handle, "_EJ0", &h)))
  421                 return_ACPI_STATUS (AE_OK);
  422 
  423         AcpiInstallNotifyHandler(handle, ACPI_SYSTEM_NOTIFY,
  424             acpi_pci_device_notify_handler, context);
  425         return_ACPI_STATUS (AE_OK);
  426 }
  427 
  428 static int
  429 acpi_pci_attach(device_t dev)
  430 {
  431         int error;
  432 
  433         error = pci_attach(dev);
  434         if (error)
  435                 return (error);
  436         AcpiInstallNotifyHandler(acpi_get_handle(dev), ACPI_SYSTEM_NOTIFY,
  437             acpi_pci_bus_notify_handler, dev);
  438         AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
  439             acpi_pci_install_device_notify_handler, NULL, dev, NULL);
  440 
  441         return (0);
  442 }
  443 
  444 static ACPI_STATUS
  445 acpi_pci_remove_notify_handler(ACPI_HANDLE handle, UINT32 level, void *context,
  446     void **status)
  447 {
  448         ACPI_HANDLE h;
  449 
  450         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  451 
  452         if (ACPI_FAILURE(AcpiGetHandle(handle, "_EJ0", &h)))
  453                 return_ACPI_STATUS (AE_OK);
  454 
  455         AcpiRemoveNotifyHandler(handle, ACPI_SYSTEM_NOTIFY,
  456             acpi_pci_device_notify_handler);
  457         return_ACPI_STATUS (AE_OK);
  458 }
  459 
  460 static int
  461 acpi_pci_detach(device_t dev)
  462 {
  463 
  464         AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
  465             acpi_pci_remove_notify_handler, NULL, dev, NULL);
  466         AcpiRemoveNotifyHandler(acpi_get_handle(dev), ACPI_SYSTEM_NOTIFY,
  467             acpi_pci_bus_notify_handler);
  468         return (pci_detach(dev));
  469 }
  470 
  471 #ifdef IOMMU
  472 static bus_dma_tag_t
  473 acpi_pci_get_dma_tag(device_t bus, device_t child)
  474 {
  475         bus_dma_tag_t tag;
  476 
  477         if (device_get_parent(child) == bus) {
  478                 /* try iommu and return if it works */
  479                 tag = iommu_get_dma_tag(bus, child);
  480         } else
  481                 tag = NULL;
  482         if (tag == NULL)
  483                 tag = pci_get_dma_tag(bus, child);
  484         return (tag);
  485 }
  486 #else
  487 static bus_dma_tag_t
  488 acpi_pci_get_dma_tag(device_t bus, device_t child)
  489 {
  490 
  491         return (pci_get_dma_tag(bus, child));
  492 }
  493 #endif

Cache object: 8f5755bed1f2675c56e15ca521bb8954


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