[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <200801021433.47651.rjw@sisk.pl>
Date: Wed, 2 Jan 2008 14:33:46 +0100
From: "Rafael J. Wysocki" <rjw@...k.pl>
To: pm list <linux-pm@...ts.linux-foundation.org>
Cc: ACPI Devel Maling List <linux-acpi@...r.kernel.org>,
Alan Stern <stern@...land.harvard.edu>,
Andrew Morton <akpm@...ux-foundation.org>,
Len Brown <lenb@...nel.org>,
LKML <linux-kernel@...r.kernel.org>,
Pavel Machek <pavel@...e.cz>, Ingo Molnar <mingo@...e.hu>,
Greg KH <gregkh@...e.de>
Subject: Re: [PATCH 1/4] PM: Introduce destroy_suspended_device()
On Wednesday, 2 of January 2008, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@...k.pl>
>
> It sometimes is necessary to destroy a device object during a suspend or
> hibernation, but the PM core is supposed to control all device objects in that
> cases. For this reason, it is necessary to introduce a mechanism allowing one
> to ask the PM core to remove a device object corresponding to a suspended
> device on one's behalf.
>
> Define function destroy_suspended_device() that will schedule the removal of
> a device object corresponding to a suspended device by the PM core during the
> subsequent resume.
>
> Signed-off-by: Rafael J. Wysocki <rjw@...k.pl>
Sorry, a small fix is needed for this patch. Namely, dpm_sysfs_remove(dev)
should not be called by device_pm_schedule_removal(), because it will be called
anyway from device_pm_remove() when the device object is finally unregistered
(we're talking here about unlikely error paths only, but still).
Corrected patch follows.
Thanks,
Rafael
---
From: Rafael J. Wysocki <rjw@...k.pl>
It sometimes is necessary to destroy a device object during a suspend or
hibernation, but the PM core is supposed to control all device objects in that
cases. For this reason, it is necessary to introduce a mechanism allowing one
to ask the PM core to remove a device object corresponding to a suspended
device on one's behalf.
Define function destroy_suspended_device() that will schedule the removal of
a device object corresponding to a suspended device by the PM core during the
subsequent resume.
Signed-off-by: Rafael J. Wysocki <rjw@...k.pl>
---
drivers/base/core.c | 44 +++++++++++++++++++++++++++++++++++++++-----
drivers/base/power/main.c | 35 ++++++++++++++++++++++++++---------
drivers/base/power/power.h | 1 +
include/linux/device.h | 8 ++++++++
4 files changed, 74 insertions(+), 14 deletions(-)
Index: linux-2.6/drivers/base/core.c
===================================================================
--- linux-2.6.orig/drivers/base/core.c
+++ linux-2.6/drivers/base/core.c
@@ -1156,14 +1156,11 @@ error:
EXPORT_SYMBOL_GPL(device_create);
/**
- * device_destroy - removes a device that was created with device_create()
+ * find_device - finds a device that was created with device_create()
* @class: pointer to the struct class that this device was registered with
* @devt: the dev_t of the device that was previously registered
- *
- * This call unregisters and cleans up a device that was created with a
- * call to device_create().
*/
-void device_destroy(struct class *class, dev_t devt)
+static struct device *find_device(struct class *class, dev_t devt)
{
struct device *dev = NULL;
struct device *dev_tmp;
@@ -1176,12 +1173,49 @@ void device_destroy(struct class *class,
}
}
up(&class->sem);
+ return dev;
+}
+/**
+ * device_destroy - removes a device that was created with device_create()
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call unregisters and cleans up a device that was created with a
+ * call to device_create().
+ */
+void device_destroy(struct class *class, dev_t devt)
+{
+ struct device *dev;
+
+ dev = find_device(class, devt);
if (dev)
device_unregister(dev);
}
EXPORT_SYMBOL_GPL(device_destroy);
+#ifdef CONFIG_PM_SLEEP
+/**
+ * destroy_suspended_device - schedules the removal of a suspended device
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call notifies the PM core of the necessity to unregister a suspended
+ * device created with a call to device_create() (devices cannot be
+ * unregistered directly while suspended, since the PM core controls them in
+ * that cases).
+ */
+void destroy_suspended_device(struct class *class, dev_t devt)
+{
+ struct device *dev;
+
+ dev = find_device(class, devt);
+ if (dev)
+ device_pm_schedule_removal(dev);
+}
+EXPORT_SYMBOL_GPL(destroy_suspended_device);
+#endif /* CONFIG_PM_SLEEP */
+
/**
* device_rename - renames a device
* @dev: the pointer to the struct device to be renamed
Index: linux-2.6/include/linux/device.h
===================================================================
--- linux-2.6.orig/include/linux/device.h
+++ linux-2.6/include/linux/device.h
@@ -521,6 +521,14 @@ extern struct device *device_create(stru
dev_t devt, const char *fmt, ...)
__attribute__((format(printf,4,5)));
extern void device_destroy(struct class *cls, dev_t devt);
+#ifdef CONFIG_PM_SLEEP
+extern void destroy_suspended_device(struct class *cls, dev_t devt);
+#else /* !CONFIG_PM_SLEEP */
+static inline void destroy_suspended_device(struct class *cls, dev_t devt)
+{
+ device_destroy(cls, devt);
+}
+#endif /* !CONFIG_PM_SLEEP */
/*
* Platform "fixup" functions - allow the platform to have their say
Index: linux-2.6/drivers/base/power/power.h
===================================================================
--- linux-2.6.orig/drivers/base/power/power.h
+++ linux-2.6/drivers/base/power/power.h
@@ -20,6 +20,7 @@ static inline struct device *to_device(s
extern void device_pm_add(struct device *);
extern void device_pm_remove(struct device *);
+extern void device_pm_schedule_removal(struct device *);
#else /* CONFIG_PM_SLEEP */
Index: linux-2.6/drivers/base/power/main.c
===================================================================
--- linux-2.6.orig/drivers/base/power/main.c
+++ linux-2.6/drivers/base/power/main.c
@@ -31,6 +31,7 @@
LIST_HEAD(dpm_active);
static LIST_HEAD(dpm_off);
static LIST_HEAD(dpm_off_irq);
+static LIST_HEAD(dpm_destroy);
static DEFINE_MUTEX(dpm_mtx);
static DEFINE_MUTEX(dpm_list_mtx);
@@ -59,6 +60,16 @@ void device_pm_remove(struct device *dev
mutex_unlock(&dpm_list_mtx);
}
+void device_pm_schedule_removal(struct device *dev)
+{
+ pr_debug("PM: Removing info for %s:%s\n",
+ dev->bus ? dev->bus->name : "No Bus",
+ kobject_name(&dev->kobj));
+ mutex_lock(&dpm_list_mtx);
+ list_move_tail(&dev->power.entry, &dpm_destroy);
+ mutex_unlock(&dpm_list_mtx);
+}
+
/*------------------------- Resume routines -------------------------*/
@@ -113,11 +124,14 @@ static int resume_device_early(struct de
return error;
}
-/*
- * Resume the devices that have either not gone through
- * the late suspend, or that did go through it but also
- * went through the early resume
+/**
+ * dpm_resume - Restore state of each device in system.
+ *
+ * Walk the dpm_off list, remove each entry, resume the device,
+ * then add it to the dpm_active list. Unregister devices scheduled for
+ * removal.
*/
+
static void dpm_resume(void)
{
mutex_lock(&dpm_list_mtx);
@@ -134,14 +148,17 @@ static void dpm_resume(void)
put_device(dev);
}
mutex_unlock(&dpm_list_mtx);
-}
+ /* Unregister devices scheduled for removal */
+ while (!list_empty(&dpm_destroy)) {
+ struct list_head *entry = dpm_destroy.next;
+ struct device *dev = to_device(entry);
+ device_unregister(dev);
+ }
+}
/**
- * device_resume - Restore state of each device in system.
- *
- * Walk the dpm_off list, remove each entry, resume the device,
- * then add it to the dpm_active list.
+ * device_resume - Invoke dpm_resume() under dpm_mtx.
*/
void device_resume(void)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists