svn commit: r272013 - in head/sys: dev/pci kern sys
Justin Hibbits
jhibbits at FreeBSD.org
Tue Sep 23 02:56:42 UTC 2014
Author: jhibbits
Date: Tue Sep 23 02:56:40 2014
New Revision: 272013
URL: http://svnweb.freebsd.org/changeset/base/272013
Log:
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
Modified:
head/sys/dev/pci/pci.c
head/sys/dev/pci/pci_private.h
head/sys/kern/bus_if.m
head/sys/kern/subr_bus.c
head/sys/sys/bus.h
Modified: head/sys/dev/pci/pci.c
==============================================================================
--- head/sys/dev/pci/pci.c Tue Sep 23 01:18:18 2014 (r272012)
+++ head/sys/dev/pci/pci.c Tue Sep 23 02:56:40 2014 (r272013)
@@ -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, dev
* 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);
Modified: head/sys/dev/pci/pci_private.h
==============================================================================
--- head/sys/dev/pci/pci_private.h Tue Sep 23 01:18:18 2014 (r272012)
+++ head/sys/dev/pci/pci_private.h Tue Sep 23 02:56:40 2014 (r272013)
@@ -123,7 +123,8 @@ int pci_child_pnpinfo_str_method(device
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);
Modified: head/sys/kern/bus_if.m
==============================================================================
--- head/sys/kern/bus_if.m Tue Sep 23 01:18:18 2014 (r272012)
+++ head/sys/kern/bus_if.m Tue Sep 23 02:56:40 2014 (r272013)
@@ -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;
Modified: head/sys/kern/subr_bus.c
==============================================================================
--- head/sys/kern/subr_bus.c Tue Sep 23 01:18:18 2014 (r272012)
+++ head/sys/kern/subr_bus.c Tue Sep 23 02:56:40 2014 (r272013)
@@ -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 */
@@ -3631,6 +3632,39 @@ bus_generic_shutdown(device_t dev)
}
/**
+ * @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()
*
* This function can be used to help implement the 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);
Modified: head/sys/sys/bus.h
==============================================================================
--- head/sys/sys/bus.h Tue Sep 23 01:18:18 2014 (r272012)
+++ head/sys/sys/bus.h Tue Sep 23 02:56:40 2014 (r272013)
@@ -339,6 +339,7 @@ int bus_generic_read_ivar(device_t dev,
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 (dev
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,
More information about the svn-src-all
mailing list