mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-19 10:53:58 +00:00
Stage one of multipass suspend/resume
Summary: Add the beginnings of multipass suspend/resume, by introducing BUS_SUSPEND_CHILD/BUS_RESUME_CHILD, and move the PCI driver to this. Reviewers: jhb Reviewed By: jhb Differential Revision: https://reviews.freebsd.org/D590
This commit is contained in:
parent
5ed6ab5baa
commit
a1c1634858
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=272013
@ -131,7 +131,7 @@ static device_method_t pci_methods[] = {
|
||||
DEVMETHOD(device_detach, bus_generic_detach),
|
||||
#endif
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, pci_suspend),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, pci_resume),
|
||||
|
||||
/* Bus interface */
|
||||
@ -157,6 +157,8 @@ static device_method_t pci_methods[] = {
|
||||
DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method),
|
||||
DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
|
||||
DEVMETHOD(bus_remap_intr, pci_remap_intr_method),
|
||||
DEVMETHOD(bus_suspend_child, pci_suspend_child),
|
||||
DEVMETHOD(bus_resume_child, pci_resume_child),
|
||||
|
||||
/* PCI interface */
|
||||
DEVMETHOD(pci_read_config, pci_read_config_method),
|
||||
@ -3622,12 +3624,11 @@ pci_detach(device_t dev)
|
||||
#endif
|
||||
|
||||
static void
|
||||
pci_set_power_children(device_t dev, device_t *devlist, int numdevs,
|
||||
int state)
|
||||
pci_set_power_child(device_t dev, device_t child, int state)
|
||||
{
|
||||
device_t child, pcib;
|
||||
struct pci_devinfo *dinfo;
|
||||
int dstate, i;
|
||||
device_t pcib;
|
||||
int dstate;
|
||||
|
||||
/*
|
||||
* Set the device to the given state. If the firmware suggests
|
||||
@ -3637,45 +3638,54 @@ pci_set_power_children(device_t dev, device_t *devlist, int numdevs,
|
||||
* are handled separately.
|
||||
*/
|
||||
pcib = device_get_parent(dev);
|
||||
for (i = 0; i < numdevs; i++) {
|
||||
child = devlist[i];
|
||||
dinfo = device_get_ivars(child);
|
||||
dstate = state;
|
||||
if (device_is_attached(child) &&
|
||||
PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
|
||||
pci_set_powerstate(child, dstate);
|
||||
}
|
||||
dinfo = device_get_ivars(child);
|
||||
dstate = state;
|
||||
if (device_is_attached(child) &&
|
||||
PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
|
||||
pci_set_powerstate(child, dstate);
|
||||
}
|
||||
|
||||
int
|
||||
pci_suspend(device_t dev)
|
||||
pci_suspend_child(device_t dev, device_t child)
|
||||
{
|
||||
device_t child, *devlist;
|
||||
struct pci_devinfo *dinfo;
|
||||
int error, i, numdevs;
|
||||
int error;
|
||||
|
||||
dinfo = device_get_ivars(child);
|
||||
|
||||
/*
|
||||
* Save the PCI configuration space for each child and set the
|
||||
* Save the PCI configuration space for the child and set the
|
||||
* device in the appropriate power state for this sleep state.
|
||||
*/
|
||||
if ((error = device_get_children(dev, &devlist, &numdevs)) != 0)
|
||||
return (error);
|
||||
for (i = 0; i < numdevs; i++) {
|
||||
child = devlist[i];
|
||||
dinfo = device_get_ivars(child);
|
||||
pci_cfg_save(child, dinfo, 0);
|
||||
}
|
||||
pci_cfg_save(child, dinfo, 0);
|
||||
|
||||
/* Suspend devices before potentially powering them down. */
|
||||
error = bus_generic_suspend(dev);
|
||||
if (error) {
|
||||
free(devlist, M_TEMP);
|
||||
error = bus_generic_suspend_child(dev, child);
|
||||
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (pci_do_power_suspend)
|
||||
pci_set_power_children(dev, devlist, numdevs,
|
||||
PCI_POWERSTATE_D3);
|
||||
free(devlist, M_TEMP);
|
||||
pci_set_power_child(dev, child, PCI_POWERSTATE_D3);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pci_resume_child(device_t dev, device_t child)
|
||||
{
|
||||
struct pci_devinfo *dinfo;
|
||||
|
||||
if (pci_do_power_resume)
|
||||
pci_set_power_child(dev, child, PCI_POWERSTATE_D0);
|
||||
|
||||
dinfo = device_get_ivars(child);
|
||||
pci_cfg_restore(child, dinfo);
|
||||
if (!device_is_attached(child))
|
||||
pci_cfg_save(child, dinfo, 1);
|
||||
|
||||
bus_generic_resume_child(dev, child);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -3683,27 +3693,10 @@ int
|
||||
pci_resume(device_t dev)
|
||||
{
|
||||
device_t child, *devlist;
|
||||
struct pci_devinfo *dinfo;
|
||||
int error, i, numdevs;
|
||||
|
||||
/*
|
||||
* Set each child to D0 and restore its PCI configuration space.
|
||||
*/
|
||||
if ((error = device_get_children(dev, &devlist, &numdevs)) != 0)
|
||||
return (error);
|
||||
if (pci_do_power_resume)
|
||||
pci_set_power_children(dev, devlist, numdevs,
|
||||
PCI_POWERSTATE_D0);
|
||||
|
||||
/* Now the device is powered up, restore its config space. */
|
||||
for (i = 0; i < numdevs; i++) {
|
||||
child = devlist[i];
|
||||
dinfo = device_get_ivars(child);
|
||||
|
||||
pci_cfg_restore(child, dinfo);
|
||||
if (!device_is_attached(child))
|
||||
pci_cfg_save(child, dinfo, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Resume critical devices first, then everything else later.
|
||||
@ -3715,7 +3708,7 @@ pci_resume(device_t dev)
|
||||
case PCIC_MEMORY:
|
||||
case PCIC_BRIDGE:
|
||||
case PCIC_BASEPERIPH:
|
||||
DEVICE_RESUME(child);
|
||||
BUS_RESUME_CHILD(dev, child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3728,7 +3721,7 @@ pci_resume(device_t dev)
|
||||
case PCIC_BASEPERIPH:
|
||||
break;
|
||||
default:
|
||||
DEVICE_RESUME(child);
|
||||
BUS_RESUME_CHILD(dev, child);
|
||||
}
|
||||
}
|
||||
free(devlist, M_TEMP);
|
||||
|
@ -123,7 +123,8 @@ int pci_child_pnpinfo_str_method(device_t cbdev, device_t child,
|
||||
char *buf, size_t buflen);
|
||||
int pci_assign_interrupt_method(device_t dev, device_t child);
|
||||
int pci_resume(device_t dev);
|
||||
int pci_suspend(device_t dev);
|
||||
int pci_resume_child(device_t dev, device_t child);
|
||||
int pci_suspend_child(device_t dev, device_t child);
|
||||
bus_dma_tag_t pci_get_dma_tag(device_t bus, device_t dev);
|
||||
void pci_child_added_method(device_t dev, device_t child);
|
||||
|
||||
|
@ -670,3 +670,25 @@ METHOD int remap_intr {
|
||||
device_t _child;
|
||||
u_int _irq;
|
||||
} DEFAULT null_remap_intr;
|
||||
|
||||
/**
|
||||
* @brief Suspend a given child
|
||||
*
|
||||
* @param _dev the parent device of @p _child
|
||||
* @param _child the device to suspend
|
||||
*/
|
||||
METHOD int suspend_child {
|
||||
device_t _dev;
|
||||
device_t _child;
|
||||
} DEFAULT bus_generic_suspend_child;
|
||||
|
||||
/**
|
||||
* @brief Resume a given child
|
||||
*
|
||||
* @param _dev the parent device of @p _child
|
||||
* @param _child the device to resume
|
||||
*/
|
||||
METHOD int resume_child {
|
||||
device_t _dev;
|
||||
device_t _child;
|
||||
} DEFAULT bus_generic_resume_child;
|
||||
|
@ -135,6 +135,7 @@ struct device {
|
||||
#define DF_DONENOMATCH 0x20 /* don't execute DEVICE_NOMATCH again */
|
||||
#define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */
|
||||
#define DF_REBID 0x80 /* Can rebid after attach */
|
||||
#define DF_SUSPENDED 0x100 /* Device is suspended. */
|
||||
u_int order; /**< order from device_add_child_ordered() */
|
||||
void *ivars; /**< instance variables */
|
||||
void *softc; /**< current driver's variables */
|
||||
@ -3630,6 +3631,39 @@ bus_generic_shutdown(device_t dev)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default function for suspending a child device.
|
||||
*
|
||||
* This function is to be used by a bus's DEVICE_SUSPEND_CHILD().
|
||||
*/
|
||||
int
|
||||
bus_generic_suspend_child(device_t dev, device_t child)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = DEVICE_SUSPEND(child);
|
||||
|
||||
if (error == 0)
|
||||
dev->flags |= DF_SUSPENDED;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default function for resuming a child device.
|
||||
*
|
||||
* This function is to be used by a bus's DEVICE_RESUME_CHILD().
|
||||
*/
|
||||
int
|
||||
bus_generic_resume_child(device_t dev, device_t child)
|
||||
{
|
||||
|
||||
DEVICE_RESUME(child);
|
||||
dev->flags &= ~DF_SUSPENDED;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function for implementing DEVICE_SUSPEND()
|
||||
*
|
||||
@ -3646,12 +3680,12 @@ bus_generic_suspend(device_t dev)
|
||||
device_t child, child2;
|
||||
|
||||
TAILQ_FOREACH(child, &dev->children, link) {
|
||||
error = DEVICE_SUSPEND(child);
|
||||
error = BUS_SUSPEND_CHILD(dev, child);
|
||||
if (error) {
|
||||
for (child2 = TAILQ_FIRST(&dev->children);
|
||||
child2 && child2 != child;
|
||||
child2 = TAILQ_NEXT(child2, link))
|
||||
DEVICE_RESUME(child2);
|
||||
BUS_RESUME_CHILD(dev, child2);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
@ -3670,7 +3704,7 @@ bus_generic_resume(device_t dev)
|
||||
device_t child;
|
||||
|
||||
TAILQ_FOREACH(child, &dev->children, link) {
|
||||
DEVICE_RESUME(child);
|
||||
BUS_RESUME_CHILD(dev, child);
|
||||
/* if resume fails, there's nothing we can usefully do... */
|
||||
}
|
||||
return (0);
|
||||
|
@ -339,6 +339,7 @@ int bus_generic_read_ivar(device_t dev, device_t child, int which,
|
||||
int bus_generic_release_resource(device_t bus, device_t child,
|
||||
int type, int rid, struct resource *r);
|
||||
int bus_generic_resume(device_t dev);
|
||||
int bus_generic_resume_child(device_t dev, device_t child);
|
||||
int bus_generic_setup_intr(device_t dev, device_t child,
|
||||
struct resource *irq, int flags,
|
||||
driver_filter_t *filter, driver_intr_t *intr,
|
||||
@ -357,6 +358,7 @@ int bus_generic_rl_release_resource (device_t, device_t, int, int,
|
||||
|
||||
int bus_generic_shutdown(device_t dev);
|
||||
int bus_generic_suspend(device_t dev);
|
||||
int bus_generic_suspend_child(device_t dev, device_t child);
|
||||
int bus_generic_teardown_intr(device_t dev, device_t child,
|
||||
struct resource *irq, void *cookie);
|
||||
int bus_generic_write_ivar(device_t dev, device_t child, int which,
|
||||
|
Loading…
Reference in New Issue
Block a user