mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-20 11:11:24 +00:00
Add a new method to the PCI bridge interface, PCIB_POWER_FOR_SLEEP(). This
method is used by the PCI bus driver to query the power management system to determine the proper device state to be used for a device during suspend and resume. For the ACPI PCI bridge drivers this calls acpi_device_pwr_for_sleep(). This removes ACPI-specific knowledge from the PCI and PCI-PCI bridge drivers. Reviewed by: jkim
This commit is contained in:
parent
efdcc3d8d8
commit
62508c531e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=211430
@ -129,8 +129,6 @@ static char *acpi_device_id_probe(device_t bus, device_t dev, char **ids);
|
||||
static ACPI_STATUS acpi_device_eval_obj(device_t bus, device_t dev,
|
||||
ACPI_STRING pathname, ACPI_OBJECT_LIST *parameters,
|
||||
ACPI_BUFFER *ret);
|
||||
static int acpi_device_pwr_for_sleep(device_t bus, device_t dev,
|
||||
int *dstate);
|
||||
static ACPI_STATUS acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level,
|
||||
void *context, void **retval);
|
||||
static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev,
|
||||
@ -1415,7 +1413,7 @@ acpi_device_eval_obj(device_t bus, device_t dev, ACPI_STRING pathname,
|
||||
return (AcpiEvaluateObject(h, pathname, parameters, ret));
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate)
|
||||
{
|
||||
struct acpi_softc *sc;
|
||||
|
@ -275,3 +275,14 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
|
||||
|
||||
return_VALUE (interrupt);
|
||||
}
|
||||
|
||||
int
|
||||
acpi_pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate)
|
||||
{
|
||||
device_t acpi_dev;
|
||||
|
||||
acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
|
||||
acpi_device_pwr_for_sleep(acpi_dev, dev, pstate);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -116,6 +116,7 @@ static device_method_t acpi_pcib_acpi_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msix, acpi_pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
DEVMETHOD(pcib_map_msi, acpi_pcib_map_msi),
|
||||
DEVMETHOD(pcib_power_for_sleep, acpi_pcib_power_for_sleep),
|
||||
|
||||
{0, 0}
|
||||
};
|
||||
|
@ -80,6 +80,7 @@ static device_method_t acpi_pcib_pci_methods[] = {
|
||||
|
||||
/* pcib interface */
|
||||
DEVMETHOD(pcib_route_interrupt, acpi_pcib_pci_route_interrupt),
|
||||
DEVMETHOD(pcib_power_for_sleep, acpi_pcib_power_for_sleep),
|
||||
|
||||
{0, 0}
|
||||
};
|
||||
|
@ -38,6 +38,8 @@ int acpi_pci_link_route_interrupt(device_t dev, int index);
|
||||
int acpi_pcib_attach(device_t bus, ACPI_BUFFER *prt, int busno);
|
||||
int acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
|
||||
ACPI_BUFFER *prtbuf);
|
||||
int acpi_pcib_power_for_sleep(device_t pcib, device_t dev,
|
||||
int *pstate);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
|
@ -393,6 +393,8 @@ EVENTHANDLER_DECLARE(acpi_wakeup_event, acpi_event_handler_t);
|
||||
/* Device power control. */
|
||||
ACPI_STATUS acpi_pwr_wake_enable(ACPI_HANDLE consumer, int enable);
|
||||
ACPI_STATUS acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state);
|
||||
int acpi_device_pwr_for_sleep(device_t bus, device_t dev,
|
||||
int *dstate);
|
||||
|
||||
/* Misc. */
|
||||
static __inline struct acpi_softc *
|
||||
|
@ -69,13 +69,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include "pcib_if.h"
|
||||
#include "pci_if.h"
|
||||
|
||||
#ifdef __HAVE_ACPI
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include "acpi_if.h"
|
||||
#else
|
||||
#define ACPI_PWR_FOR_SLEEP(x, y, z)
|
||||
#endif
|
||||
|
||||
static pci_addr_t pci_mapbase(uint64_t mapreg);
|
||||
static const char *pci_maptype(uint64_t mapreg);
|
||||
static int pci_mapsize(uint64_t testval);
|
||||
@ -2914,16 +2907,13 @@ int
|
||||
pci_suspend(device_t dev)
|
||||
{
|
||||
int dstate, error, i, numdevs;
|
||||
device_t acpi_dev, child, *devlist;
|
||||
device_t child, *devlist, pcib;
|
||||
struct pci_devinfo *dinfo;
|
||||
|
||||
/*
|
||||
* Save the PCI configuration space for each child and set the
|
||||
* device in the appropriate power state for this sleep state.
|
||||
*/
|
||||
acpi_dev = NULL;
|
||||
if (pci_do_power_resume)
|
||||
acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
|
||||
if ((error = device_get_children(dev, &devlist, &numdevs)) != 0)
|
||||
return (error);
|
||||
for (i = 0; i < numdevs; i++) {
|
||||
@ -2940,22 +2930,23 @@ pci_suspend(device_t dev)
|
||||
}
|
||||
|
||||
/*
|
||||
* Always set the device to D3. If ACPI suggests a different
|
||||
* power state, use it instead. If ACPI is not present, the
|
||||
* firmware is responsible for managing device power. Skip
|
||||
* children who aren't attached since they are powered down
|
||||
* separately. Only manage type 0 devices for now.
|
||||
* Always set the device to D3. If the firmware suggests a
|
||||
* different power state, use it instead. If power management
|
||||
* is not present, the firmware is responsible for managing
|
||||
* device power. Skip children who aren't attached since they
|
||||
* are powered down separately. Only manage type 0 devices
|
||||
* for now.
|
||||
*/
|
||||
for (i = 0; acpi_dev && i < numdevs; i++) {
|
||||
pcib = device_get_parent(dev);
|
||||
for (i = 0; pci_do_power_resume && i < numdevs; i++) {
|
||||
child = devlist[i];
|
||||
dinfo = (struct pci_devinfo *) device_get_ivars(child);
|
||||
dstate = PCI_POWERSTATE_D3;
|
||||
if (device_is_attached(child) &&
|
||||
(dinfo->cfg.hdrtype & PCIM_HDRTYPE) ==
|
||||
PCIM_HDRTYPE_NORMAL) {
|
||||
dstate = PCI_POWERSTATE_D3;
|
||||
ACPI_PWR_FOR_SLEEP(acpi_dev, child, &dstate);
|
||||
PCIM_HDRTYPE_NORMAL &&
|
||||
PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
|
||||
pci_set_powerstate(child, dstate);
|
||||
}
|
||||
}
|
||||
free(devlist, M_TEMP);
|
||||
return (0);
|
||||
@ -2965,31 +2956,29 @@ int
|
||||
pci_resume(device_t dev)
|
||||
{
|
||||
int i, numdevs, error;
|
||||
device_t acpi_dev, child, *devlist;
|
||||
device_t child, *devlist, pcib;
|
||||
struct pci_devinfo *dinfo;
|
||||
|
||||
/*
|
||||
* Set each child to D0 and restore its PCI configuration space.
|
||||
*/
|
||||
acpi_dev = NULL;
|
||||
if (pci_do_power_resume)
|
||||
acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
|
||||
if ((error = device_get_children(dev, &devlist, &numdevs)) != 0)
|
||||
return (error);
|
||||
pcib = device_get_parent(dev);
|
||||
for (i = 0; i < numdevs; i++) {
|
||||
/*
|
||||
* Notify ACPI we're going to D0 but ignore the result. If
|
||||
* ACPI is not present, the firmware is responsible for
|
||||
* managing device power. Only manage type 0 devices for now.
|
||||
* Notify power managment we're going to D0 but ignore
|
||||
* the result. If power management is not present,
|
||||
* the firmware is responsible for managing device
|
||||
* power. Only manage type 0 devices for now.
|
||||
*/
|
||||
child = devlist[i];
|
||||
dinfo = (struct pci_devinfo *) device_get_ivars(child);
|
||||
if (acpi_dev && device_is_attached(child) &&
|
||||
if (device_is_attached(child) &&
|
||||
(dinfo->cfg.hdrtype & PCIM_HDRTYPE) ==
|
||||
PCIM_HDRTYPE_NORMAL) {
|
||||
ACPI_PWR_FOR_SLEEP(acpi_dev, child, NULL);
|
||||
PCIM_HDRTYPE_NORMAL &&
|
||||
PCIB_POWER_FOR_SLEEP(pcib, dev, NULL) == 0)
|
||||
pci_set_powerstate(child, PCI_POWERSTATE_D0);
|
||||
}
|
||||
|
||||
/* Now the device is powered up, restore its config space. */
|
||||
pci_cfg_restore(child, dinfo);
|
||||
|
@ -48,22 +48,16 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pci_private.h>
|
||||
#include <dev/pci/pcib_private.h>
|
||||
|
||||
#include "pcib_if.h"
|
||||
|
||||
#ifdef __HAVE_ACPI
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include "acpi_if.h"
|
||||
#else
|
||||
#define ACPI_PWR_FOR_SLEEP(x, y, z)
|
||||
#endif
|
||||
|
||||
extern int pci_do_power_resume;
|
||||
|
||||
static int pcib_probe(device_t dev);
|
||||
static int pcib_suspend(device_t dev);
|
||||
static int pcib_resume(device_t dev);
|
||||
static int pcib_power_for_sleep(device_t pcib, device_t dev,
|
||||
int *pstate);
|
||||
|
||||
static device_method_t pcib_methods[] = {
|
||||
/* Device interface */
|
||||
@ -95,6 +89,7 @@ static device_method_t pcib_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
DEVMETHOD(pcib_map_msi, pcib_map_msi),
|
||||
DEVMETHOD(pcib_power_for_sleep, pcib_power_for_sleep),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
@ -447,18 +442,16 @@ pcib_attach(device_t dev)
|
||||
int
|
||||
pcib_suspend(device_t dev)
|
||||
{
|
||||
device_t acpi_dev;
|
||||
device_t pcib;
|
||||
int dstate, error;
|
||||
|
||||
pcib_cfg_save(device_get_softc(dev));
|
||||
error = bus_generic_suspend(dev);
|
||||
if (error == 0 && pci_do_power_resume) {
|
||||
acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
|
||||
if (acpi_dev != NULL) {
|
||||
dstate = PCI_POWERSTATE_D3;
|
||||
ACPI_PWR_FOR_SLEEP(acpi_dev, dev, &dstate);
|
||||
dstate = PCI_POWERSTATE_D3;
|
||||
pcib = device_get_parent(device_get_parent(dev));
|
||||
if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
|
||||
pci_set_powerstate(dev, dstate);
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
@ -466,14 +459,12 @@ pcib_suspend(device_t dev)
|
||||
int
|
||||
pcib_resume(device_t dev)
|
||||
{
|
||||
device_t acpi_dev;
|
||||
device_t pcib;
|
||||
|
||||
if (pci_do_power_resume) {
|
||||
acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
|
||||
if (acpi_dev != NULL) {
|
||||
ACPI_PWR_FOR_SLEEP(acpi_dev, dev, NULL);
|
||||
pcib = device_get_parent(device_get_parent(dev));
|
||||
if (PCIB_POWER_FOR_SLEEP(pcib, dev, NULL) == 0)
|
||||
pci_set_powerstate(dev, PCI_POWERSTATE_D0);
|
||||
}
|
||||
}
|
||||
pcib_cfg_restore(device_get_softc(dev));
|
||||
return (bus_generic_resume(dev));
|
||||
@ -790,6 +781,16 @@ pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Pass request for device power state up to parent bridge. */
|
||||
int
|
||||
pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate)
|
||||
{
|
||||
device_t bus;
|
||||
|
||||
bus = device_get_parent(pcib);
|
||||
return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate));
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to read the bus number of a host-PCI bridge using appropriate config
|
||||
* registers.
|
||||
|
@ -38,6 +38,8 @@
|
||||
*/
|
||||
DECLARE_CLASS(pci_driver);
|
||||
|
||||
extern int pci_do_power_resume;
|
||||
|
||||
void pci_add_children(device_t dev, int domain, int busno,
|
||||
size_t dinfo_size);
|
||||
void pci_add_child(device_t bus, struct pci_devinfo *dinfo);
|
||||
|
@ -144,3 +144,13 @@ METHOD int map_msi {
|
||||
uint64_t *addr;
|
||||
uint32_t *data;
|
||||
};
|
||||
|
||||
#
|
||||
# Return the device power state to be used during a system sleep state
|
||||
# transition such as suspend and resume.
|
||||
#
|
||||
METHOD int power_for_sleep {
|
||||
device_t pcib;
|
||||
device_t dev;
|
||||
int *pstate;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user