1
0
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:
Justin Hibbits 2014-09-23 02:56:40 +00:00
parent 5ed6ab5baa
commit a1c1634858
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=272013
5 changed files with 106 additions and 54 deletions

View File

@ -131,7 +131,7 @@ static device_method_t pci_methods[] = {
DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_detach, bus_generic_detach),
#endif #endif
DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, pci_suspend), DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, pci_resume), DEVMETHOD(device_resume, pci_resume),
/* Bus interface */ /* 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_pnpinfo_str, pci_child_pnpinfo_str_method),
DEVMETHOD(bus_child_location_str, pci_child_location_str_method), DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
DEVMETHOD(bus_remap_intr, pci_remap_intr_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 */ /* PCI interface */
DEVMETHOD(pci_read_config, pci_read_config_method), DEVMETHOD(pci_read_config, pci_read_config_method),
@ -3622,12 +3624,11 @@ pci_detach(device_t dev)
#endif #endif
static void static void
pci_set_power_children(device_t dev, device_t *devlist, int numdevs, pci_set_power_child(device_t dev, device_t child, int state)
int state)
{ {
device_t child, pcib;
struct pci_devinfo *dinfo; struct pci_devinfo *dinfo;
int dstate, i; device_t pcib;
int dstate;
/* /*
* Set the device to the given state. If the firmware suggests * 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. * are handled separately.
*/ */
pcib = device_get_parent(dev); pcib = device_get_parent(dev);
for (i = 0; i < numdevs; i++) { dinfo = device_get_ivars(child);
child = devlist[i]; dstate = state;
dinfo = device_get_ivars(child); if (device_is_attached(child) &&
dstate = state; PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
if (device_is_attached(child) && pci_set_powerstate(child, dstate);
PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
pci_set_powerstate(child, dstate);
}
} }
int int
pci_suspend(device_t dev) pci_suspend_child(device_t dev, device_t child)
{ {
device_t child, *devlist;
struct pci_devinfo *dinfo; 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. * device in the appropriate power state for this sleep state.
*/ */
if ((error = device_get_children(dev, &devlist, &numdevs)) != 0) pci_cfg_save(child, dinfo, 0);
return (error);
for (i = 0; i < numdevs; i++) {
child = devlist[i];
dinfo = device_get_ivars(child);
pci_cfg_save(child, dinfo, 0);
}
/* Suspend devices before potentially powering them down. */ /* Suspend devices before potentially powering them down. */
error = bus_generic_suspend(dev); error = bus_generic_suspend_child(dev, child);
if (error) {
free(devlist, M_TEMP); if (error)
return (error); return (error);
}
if (pci_do_power_suspend) if (pci_do_power_suspend)
pci_set_power_children(dev, devlist, numdevs, pci_set_power_child(dev, child, PCI_POWERSTATE_D3);
PCI_POWERSTATE_D3);
free(devlist, M_TEMP); 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); return (0);
} }
@ -3683,27 +3693,10 @@ int
pci_resume(device_t dev) pci_resume(device_t dev)
{ {
device_t child, *devlist; device_t child, *devlist;
struct pci_devinfo *dinfo;
int error, i, numdevs; int error, i, numdevs;
/*
* Set each child to D0 and restore its PCI configuration space.
*/
if ((error = device_get_children(dev, &devlist, &numdevs)) != 0) if ((error = device_get_children(dev, &devlist, &numdevs)) != 0)
return (error); 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. * Resume critical devices first, then everything else later.
@ -3715,7 +3708,7 @@ pci_resume(device_t dev)
case PCIC_MEMORY: case PCIC_MEMORY:
case PCIC_BRIDGE: case PCIC_BRIDGE:
case PCIC_BASEPERIPH: case PCIC_BASEPERIPH:
DEVICE_RESUME(child); BUS_RESUME_CHILD(dev, child);
break; break;
} }
} }
@ -3728,7 +3721,7 @@ pci_resume(device_t dev)
case PCIC_BASEPERIPH: case PCIC_BASEPERIPH:
break; break;
default: default:
DEVICE_RESUME(child); BUS_RESUME_CHILD(dev, child);
} }
} }
free(devlist, M_TEMP); free(devlist, M_TEMP);

View File

@ -123,7 +123,8 @@ int pci_child_pnpinfo_str_method(device_t cbdev, device_t child,
char *buf, size_t buflen); char *buf, size_t buflen);
int pci_assign_interrupt_method(device_t dev, device_t child); int pci_assign_interrupt_method(device_t dev, device_t child);
int pci_resume(device_t dev); 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); 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); void pci_child_added_method(device_t dev, device_t child);

View File

@ -670,3 +670,25 @@ METHOD int remap_intr {
device_t _child; device_t _child;
u_int _irq; u_int _irq;
} DEFAULT null_remap_intr; } 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;

View File

@ -135,6 +135,7 @@ struct device {
#define DF_DONENOMATCH 0x20 /* don't execute DEVICE_NOMATCH again */ #define DF_DONENOMATCH 0x20 /* don't execute DEVICE_NOMATCH again */
#define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */ #define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */
#define DF_REBID 0x80 /* Can rebid after attach */ #define DF_REBID 0x80 /* Can rebid after attach */
#define DF_SUSPENDED 0x100 /* Device is suspended. */
u_int order; /**< order from device_add_child_ordered() */ u_int order; /**< order from device_add_child_ordered() */
void *ivars; /**< instance variables */ void *ivars; /**< instance variables */
void *softc; /**< current driver's variables */ void *softc; /**< current driver's variables */
@ -3630,6 +3631,39 @@ bus_generic_shutdown(device_t dev)
return (0); 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() * @brief Helper function for implementing DEVICE_SUSPEND()
* *
@ -3646,12 +3680,12 @@ bus_generic_suspend(device_t dev)
device_t child, child2; device_t child, child2;
TAILQ_FOREACH(child, &dev->children, link) { TAILQ_FOREACH(child, &dev->children, link) {
error = DEVICE_SUSPEND(child); error = BUS_SUSPEND_CHILD(dev, child);
if (error) { if (error) {
for (child2 = TAILQ_FIRST(&dev->children); for (child2 = TAILQ_FIRST(&dev->children);
child2 && child2 != child; child2 && child2 != child;
child2 = TAILQ_NEXT(child2, link)) child2 = TAILQ_NEXT(child2, link))
DEVICE_RESUME(child2); BUS_RESUME_CHILD(dev, child2);
return (error); return (error);
} }
} }
@ -3670,7 +3704,7 @@ bus_generic_resume(device_t dev)
device_t child; device_t child;
TAILQ_FOREACH(child, &dev->children, link) { TAILQ_FOREACH(child, &dev->children, link) {
DEVICE_RESUME(child); BUS_RESUME_CHILD(dev, child);
/* if resume fails, there's nothing we can usefully do... */ /* if resume fails, there's nothing we can usefully do... */
} }
return (0); return (0);

View File

@ -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 bus_generic_release_resource(device_t bus, device_t child,
int type, int rid, struct resource *r); int type, int rid, struct resource *r);
int bus_generic_resume(device_t dev); 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, int bus_generic_setup_intr(device_t dev, device_t child,
struct resource *irq, int flags, struct resource *irq, int flags,
driver_filter_t *filter, driver_intr_t *intr, 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_shutdown(device_t dev);
int bus_generic_suspend(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, int bus_generic_teardown_intr(device_t dev, device_t child,
struct resource *irq, void *cookie); struct resource *irq, void *cookie);
int bus_generic_write_ivar(device_t dev, device_t child, int which, int bus_generic_write_ivar(device_t dev, device_t child, int which,