Commit 05d3794a authored by Linus Torvalds's avatar Linus Torvalds
parents 30121624 0b405a0f
...@@ -7,7 +7,6 @@ that support it. For example, a given bus might look like this: ...@@ -7,7 +7,6 @@ that support it. For example, a given bus might look like this:
|-- 0000:17:00.0 |-- 0000:17:00.0
| |-- class | |-- class
| |-- config | |-- config
| |-- detach_state
| |-- device | |-- device
| |-- irq | |-- irq
| |-- local_cpus | |-- local_cpus
...@@ -19,7 +18,7 @@ that support it. For example, a given bus might look like this: ...@@ -19,7 +18,7 @@ that support it. For example, a given bus might look like this:
| |-- subsystem_device | |-- subsystem_device
| |-- subsystem_vendor | |-- subsystem_vendor
| `-- vendor | `-- vendor
`-- detach_state `-- ...
The topmost element describes the PCI domain and bus number. In this case, The topmost element describes the PCI domain and bus number. In this case,
the domain number is 0000 and the bus number is 17 (both values are in hex). the domain number is 0000 and the bus number is 17 (both values are in hex).
...@@ -31,7 +30,6 @@ files, each with their own function. ...@@ -31,7 +30,6 @@ files, each with their own function.
---- -------- ---- --------
class PCI class (ascii, ro) class PCI class (ascii, ro)
config PCI config space (binary, rw) config PCI config space (binary, rw)
detach_state connection status (bool, rw)
device PCI device (ascii, ro) device PCI device (ascii, ro)
irq IRQ number (ascii, ro) irq IRQ number (ascii, ro)
local_cpus nearby CPU mask (cpumask, ro) local_cpus nearby CPU mask (cpumask, ro)
...@@ -85,4 +83,4 @@ useful return codes should be provided. ...@@ -85,4 +83,4 @@ useful return codes should be provided.
Legacy resources are protected by the HAVE_PCI_LEGACY define. Platforms Legacy resources are protected by the HAVE_PCI_LEGACY define. Platforms
wishing to support legacy functionality should define it and provide wishing to support legacy functionality should define it and provide
pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions. pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions.
\ No newline at end of file
...@@ -207,27 +207,6 @@ SYSTEM_SHUTDOWN, I do not understand this one too much. probably event ...@@ -207,27 +207,6 @@ SYSTEM_SHUTDOWN, I do not understand this one too much. probably event
#READY_AFTER_RESUME #READY_AFTER_RESUME
# #
Driver Detach Power Management
The kernel now supports the ability to place a device in a low-power
state when it is detached from its driver, which happens when its
module is removed.
Each device contains a 'detach_state' file in its sysfs directory
which can be used to control this state. Reading from this file
displays what the current detach state is set to. This is 0 (On) by
default. A user may write a positive integer value to this file in the
range of 1-4 inclusive.
A value of 1-3 will indicate the device should be placed in that
low-power state, which will cause ->suspend() to be called for that
device. A value of 4 indicates that the device should be shutdown, so
->shutdown() will be called for that device.
The driver is responsible for reinitializing the device when the
module is re-inserted during it's ->probe() (or equivalent) method.
The driver core will not call any extra functions when binding the
device to the driver.
pm_message_t meaning pm_message_t meaning
......
...@@ -347,8 +347,8 @@ address that is created by firmware. An example vty-server sysfs entry ...@@ -347,8 +347,8 @@ address that is created by firmware. An example vty-server sysfs entry
looks like the following: looks like the following:
Pow5:/sys/bus/vio/drivers/hvcs/30000004 # ls Pow5:/sys/bus/vio/drivers/hvcs/30000004 # ls
. current_vty devspec name partner_vtys . current_vty devspec name partner_vtys
.. detach_state index partner_clcs vterm_state .. index partner_clcs vterm_state
Each entry is provided, by default with a "name" attribute. Reading the Each entry is provided, by default with a "name" attribute. Reading the
"name" attribute will reveal the device type as shown in the following "name" attribute will reveal the device type as shown in the following
......
# Makefile for the Linux device tree # Makefile for the Linux device tree
obj-y := core.o sys.o interface.o bus.o \ obj-y := core.o sys.o bus.o \
driver.o class.o class_simple.o platform.o \ driver.o class.o class_simple.o platform.o \
cpu.o firmware.o init.o map.o dmapool.o \ cpu.o firmware.o init.o map.o dmapool.o \
attribute_container.o transport_class.o attribute_container.o transport_class.o
......
...@@ -390,7 +390,6 @@ void device_release_driver(struct device * dev) ...@@ -390,7 +390,6 @@ void device_release_driver(struct device * dev)
sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
sysfs_remove_link(&dev->kobj, "driver"); sysfs_remove_link(&dev->kobj, "driver");
list_del_init(&dev->driver_list); list_del_init(&dev->driver_list);
device_detach_shutdown(dev);
if (drv->remove) if (drv->remove)
drv->remove(dev); drv->remove(dev);
dev->driver = NULL; dev->driver = NULL;
......
...@@ -31,8 +31,6 @@ int (*platform_notify_remove)(struct device * dev) = NULL; ...@@ -31,8 +31,6 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
#define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev(obj) container_of(obj, struct device, kobj)
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
extern struct attribute * dev_default_attrs[];
static ssize_t static ssize_t
dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{ {
...@@ -89,7 +87,6 @@ static void device_release(struct kobject * kobj) ...@@ -89,7 +87,6 @@ static void device_release(struct kobject * kobj)
static struct kobj_type ktype_device = { static struct kobj_type ktype_device = {
.release = device_release, .release = device_release,
.sysfs_ops = &dev_sysfs_ops, .sysfs_ops = &dev_sysfs_ops,
.default_attrs = dev_default_attrs,
}; };
......
/*
* drivers/base/interface.c - common driverfs interface that's exported to
* the world for all devices.
*
* Copyright (c) 2002-3 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs
*
* This file is released under the GPLv2
*
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/stat.h>
#include <linux/string.h>
/**
* detach_state - control the default power state for the device.
*
* This is the state the device enters when it's driver module is
* unloaded. The value is an unsigned integer, in the range of 0-4.
* '0' indicates 'On', so no action will be taken when the driver is
* unloaded. This is the default behavior.
* '4' indicates 'Off', meaning the driver core will call the driver's
* shutdown method to quiesce the device.
* 1-3 indicate a low-power state for the device to enter via the
* driver's suspend method.
*/
static ssize_t detach_show(struct device * dev, char * buf)
{
return sprintf(buf, "%u\n", dev->detach_state);
}
static ssize_t detach_store(struct device * dev, const char * buf, size_t n)
{
u32 state;
state = simple_strtoul(buf, NULL, 10);
if (state > 4)
return -EINVAL;
dev->detach_state = state;
return n;
}
static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store);
struct attribute * dev_default_attrs[] = {
&dev_attr_detach_state.attr,
NULL,
};
enum {
DEVICE_PM_ON,
DEVICE_PM1,
DEVICE_PM2,
DEVICE_PM3,
DEVICE_PM_OFF,
};
/* /*
* shutdown.c * shutdown.c
*/ */
extern int device_detach_shutdown(struct device *);
extern void device_shutdown(void); extern void device_shutdown(void);
......
...@@ -22,8 +22,17 @@ extern int sysdev_resume(void); ...@@ -22,8 +22,17 @@ extern int sysdev_resume(void);
int resume_device(struct device * dev) int resume_device(struct device * dev)
{ {
if (dev->bus && dev->bus->resume) if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state) {
dev_err(dev, "PM: resume from %d, parent %s still %d\n",
dev->power.power_state,
dev->power.pm_parent->bus_id,
dev->power.pm_parent->power.power_state);
}
if (dev->bus && dev->bus->resume) {
dev_dbg(dev,"resuming\n");
return dev->bus->resume(dev); return dev->bus->resume(dev);
}
return 0; return 0;
} }
......
...@@ -19,20 +19,6 @@ ...@@ -19,20 +19,6 @@
extern struct subsystem devices_subsys; extern struct subsystem devices_subsys;
int device_detach_shutdown(struct device * dev)
{
if (!dev->detach_state)
return 0;
if (dev->detach_state == DEVICE_PM_OFF) {
if (dev->driver && dev->driver->shutdown)
dev->driver->shutdown(dev);
return 0;
}
return dpm_runtime_suspend(dev, dev->detach_state);
}
/** /**
* We handle system devices differently - we suspend and shut them * We handle system devices differently - we suspend and shut them
* down last and resume them first. That way, we don't do anything stupid like * down last and resume them first. That way, we don't do anything stupid like
...@@ -52,13 +38,12 @@ void device_shutdown(void) ...@@ -52,13 +38,12 @@ void device_shutdown(void)
struct device * dev; struct device * dev;
down_write(&devices_subsys.rwsem); down_write(&devices_subsys.rwsem);
list_for_each_entry_reverse(dev, &devices_subsys.kset.list, kobj.entry) { list_for_each_entry_reverse(dev, &devices_subsys.kset.list,
pr_debug("shutting down %s: ", dev->bus_id); kobj.entry) {
if (dev->driver && dev->driver->shutdown) { if (dev->driver && dev->driver->shutdown) {
pr_debug("Ok\n"); dev_dbg(dev, "shutdown\n");
dev->driver->shutdown(dev); dev->driver->shutdown(dev);
} else }
pr_debug("Ignored.\n");
} }
up_write(&devices_subsys.rwsem); up_write(&devices_subsys.rwsem);
......
...@@ -39,12 +39,25 @@ int suspend_device(struct device * dev, pm_message_t state) ...@@ -39,12 +39,25 @@ int suspend_device(struct device * dev, pm_message_t state)
{ {
int error = 0; int error = 0;
dev_dbg(dev, "suspending\n"); if (dev->power.power_state) {
dev_dbg(dev, "PM: suspend %d-->%d\n",
dev->power.power_state, state);
}
if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state) {
dev_err(dev,
"PM: suspend %d->%d, parent %s already %d\n",
dev->power.power_state, state,
dev->power.pm_parent->bus_id,
dev->power.pm_parent->power.power_state);
}
dev->power.prev_state = dev->power.power_state; dev->power.prev_state = dev->power.power_state;
if (dev->bus && dev->bus->suspend && !dev->power.power_state) if (dev->bus && dev->bus->suspend && !dev->power.power_state) {
dev_dbg(dev, "suspending\n");
error = dev->bus->suspend(dev, state); error = dev->bus->suspend(dev, state);
}
return error; return error;
} }
......
...@@ -273,9 +273,6 @@ struct device { ...@@ -273,9 +273,6 @@ struct device {
BIOS data relevant to device) */ BIOS data relevant to device) */
struct dev_pm_info power; struct dev_pm_info power;
u32 detach_state; /* State to enter when device is
detached from its driver. */
u64 *dma_mask; /* dma mask (if dma'able device) */ u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as alloc_coherent mappings as
......
...@@ -156,14 +156,14 @@ static int enter_state(suspend_state_t state) ...@@ -156,14 +156,14 @@ static int enter_state(suspend_state_t state)
goto Unlock; goto Unlock;
} }
pr_debug("PM: Preparing system for suspend\n"); pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
if ((error = suspend_prepare(state))) if ((error = suspend_prepare(state)))
goto Unlock; goto Unlock;
pr_debug("PM: Entering state.\n"); pr_debug("PM: Entering %s sleep\n", pm_states[state]);
error = suspend_enter(state); error = suspend_enter(state);
pr_debug("PM: Finishing up.\n"); pr_debug("PM: Finishing wakeup.\n");
suspend_finish(state); suspend_finish(state);
Unlock: Unlock:
up(&pm_sem); up(&pm_sem);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment