summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/Kconfig1
-rw-r--r--drivers/base/Makefile4
-rw-r--r--drivers/base/bus.c22
-rw-r--r--drivers/base/class.c23
-rw-r--r--drivers/base/core.c210
-rw-r--r--drivers/base/memory.c94
-rw-r--r--drivers/base/node.c22
-rw-r--r--drivers/base/platform.c81
-rw-r--r--drivers/base/power/runtime.c2
-rw-r--r--drivers/base/sys.c8
10 files changed, 182 insertions, 285 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index ef38aff737eb..fd96345bc35c 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -71,7 +71,6 @@ config PREVENT_FIRMWARE_BUILD
config FW_LOADER
tristate "Userspace firmware loading support" if EMBEDDED
- depends on HOTPLUG
default y
---help---
This option is provided for the case where no in-kernel-tree modules
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index c12c7f2f2a6f..5f51c3b4451e 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -19,7 +19,5 @@ obj-$(CONFIG_MODULES) += module.o
endif
obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
-ifeq ($(CONFIG_DEBUG_DRIVER),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index eb1b7fa20dce..33c270a64db7 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -440,22 +440,6 @@ static void device_remove_attrs(struct bus_type *bus, struct device *dev)
}
}
-#ifdef CONFIG_SYSFS_DEPRECATED
-static int make_deprecated_bus_links(struct device *dev)
-{
- return sysfs_create_link(&dev->kobj,
- &dev->bus->p->subsys.kobj, "bus");
-}
-
-static void remove_deprecated_bus_links(struct device *dev)
-{
- sysfs_remove_link(&dev->kobj, "bus");
-}
-#else
-static inline int make_deprecated_bus_links(struct device *dev) { return 0; }
-static inline void remove_deprecated_bus_links(struct device *dev) { }
-#endif
-
/**
* bus_add_device - add device to bus
* @dev: device being added
@@ -482,15 +466,10 @@ int bus_add_device(struct device *dev)
&dev->bus->p->subsys.kobj, "subsystem");
if (error)
goto out_subsys;
- error = make_deprecated_bus_links(dev);
- if (error)
- goto out_deprecated;
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
}
return 0;
-out_deprecated:
- sysfs_remove_link(&dev->kobj, "subsystem");
out_subsys:
sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
out_id:
@@ -530,7 +509,6 @@ void bus_remove_device(struct device *dev)
{
if (dev->bus) {
sysfs_remove_link(&dev->kobj, "subsystem");
- remove_deprecated_bus_links(dev);
sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
dev_name(dev));
device_remove_attrs(dev->bus, dev);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 8e231d05b400..9c63a5687d69 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -184,9 +184,9 @@ int __class_register(struct class *cls, struct lock_class_key *key)
if (!cls->dev_kobj)
cls->dev_kobj = sysfs_dev_char_kobj;
-#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK)
+#if defined(CONFIG_BLOCK)
/* let the block class directory show up in the root of sysfs */
- if (cls != &block_class)
+ if (!sysfs_deprecated || cls != &block_class)
cp->class_subsys.kobj.kset = class_kset;
#else
cp->class_subsys.kobj.kset = class_kset;
@@ -276,25 +276,6 @@ void class_destroy(struct class *cls)
class_unregister(cls);
}
-#ifdef CONFIG_SYSFS_DEPRECATED
-char *make_class_name(const char *name, struct kobject *kobj)
-{
- char *class_name;
- int size;
-
- size = strlen(name) + strlen(kobject_name(kobj)) + 2;
-
- class_name = kmalloc(size, GFP_KERNEL);
- if (!class_name)
- return NULL;
-
- strcpy(class_name, name);
- strcat(class_name, ":");
- strcat(class_name, kobject_name(kobj));
- return class_name;
-}
-#endif
-
/**
* class_dev_iter_init - initialize class device iterator
* @iter: class iterator to initialize
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d1b2c9adc271..6ed645411c40 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -26,6 +26,19 @@
#include "base.h"
#include "power/power.h"
+#ifdef CONFIG_SYSFS_DEPRECATED
+#ifdef CONFIG_SYSFS_DEPRECATED_V2
+long sysfs_deprecated = 1;
+#else
+long sysfs_deprecated = 0;
+#endif
+static __init int sysfs_deprecated_setup(char *arg)
+{
+ return strict_strtol(arg, 10, &sysfs_deprecated);
+}
+early_param("sysfs.deprecated", sysfs_deprecated_setup);
+#endif
+
int (*platform_notify)(struct device *dev) = NULL;
int (*platform_notify_remove)(struct device *dev) = NULL;
static struct kobject *dev_kobj;
@@ -203,37 +216,6 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
if (dev->driver)
add_uevent_var(env, "DRIVER=%s", dev->driver->name);
-#ifdef CONFIG_SYSFS_DEPRECATED
- if (dev->class) {
- struct device *parent = dev->parent;
-
- /* find first bus device in parent chain */
- while (parent && !parent->bus)
- parent = parent->parent;
- if (parent && parent->bus) {
- const char *path;
-
- path = kobject_get_path(&parent->kobj, GFP_KERNEL);
- if (path) {
- add_uevent_var(env, "PHYSDEVPATH=%s", path);
- kfree(path);
- }
-
- add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
-
- if (parent->driver)
- add_uevent_var(env, "PHYSDEVDRIVER=%s",
- parent->driver->name);
- }
- } else if (dev->bus) {
- add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
-
- if (dev->driver)
- add_uevent_var(env, "PHYSDEVDRIVER=%s",
- dev->driver->name);
- }
-#endif
-
/* have the bus specific function add its stuff */
if (dev->bus && dev->bus->uevent) {
retval = dev->bus->uevent(dev, env);
@@ -251,7 +233,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
__func__, retval);
}
- /* have the device type specific fuction add its stuff */
+ /* have the device type specific function add its stuff */
if (dev->type && dev->type->uevent) {
retval = dev->type->uevent(dev, env);
if (retval)
@@ -578,24 +560,6 @@ void device_initialize(struct device *dev)
set_dev_node(dev, -1);
}
-#ifdef CONFIG_SYSFS_DEPRECATED
-static struct kobject *get_device_parent(struct device *dev,
- struct device *parent)
-{
- /* class devices without a parent live in /sys/class/<classname>/ */
- if (dev->class && (!parent || parent->class != dev->class))
- return &dev->class->p->class_subsys.kobj;
- /* all other devices keep their parent */
- else if (parent)
- return &parent->kobj;
-
- return NULL;
-}
-
-static inline void cleanup_device_parent(struct device *dev) {}
-static inline void cleanup_glue_dir(struct device *dev,
- struct kobject *glue_dir) {}
-#else
static struct kobject *virtual_device_parent(struct device *dev)
{
static struct kobject *virtual_dir = NULL;
@@ -666,6 +630,15 @@ static struct kobject *get_device_parent(struct device *dev,
struct kobject *parent_kobj;
struct kobject *k;
+#ifdef CONFIG_BLOCK
+ /* block disks show up in /sys/block */
+ if (sysfs_deprecated && dev->class == &block_class) {
+ if (parent && parent->class == &block_class)
+ return &parent->kobj;
+ return &block_class.p->class_subsys.kobj;
+ }
+#endif
+
/*
* If we have no parent, we live in "virtual".
* Class-devices with a non class-device as parent, live
@@ -719,7 +692,6 @@ static void cleanup_device_parent(struct device *dev)
{
cleanup_glue_dir(dev, dev->kobj.parent);
}
-#endif
static void setup_parent(struct device *dev, struct device *parent)
{
@@ -742,70 +714,29 @@ static int device_add_class_symlinks(struct device *dev)
if (error)
goto out;
-#ifdef CONFIG_SYSFS_DEPRECATED
- /* stacked class devices need a symlink in the class directory */
- if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
- device_is_not_partition(dev)) {
- error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
- &dev->kobj, dev_name(dev));
- if (error)
- goto out_subsys;
- }
-
if (dev->parent && device_is_not_partition(dev)) {
- struct device *parent = dev->parent;
- char *class_name;
-
- /*
- * stacked class devices have the 'device' link
- * pointing to the bus device instead of the parent
- */
- while (parent->class && !parent->bus && parent->parent)
- parent = parent->parent;
-
- error = sysfs_create_link(&dev->kobj,
- &parent->kobj,
+ error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
"device");
if (error)
- goto out_busid;
-
- class_name = make_class_name(dev->class->name,
- &dev->kobj);
- if (class_name)
- error = sysfs_create_link(&dev->parent->kobj,
- &dev->kobj, class_name);
- kfree(class_name);
- if (error)
- goto out_device;
+ goto out_subsys;
}
- return 0;
-out_device:
- if (dev->parent && device_is_not_partition(dev))
- sysfs_remove_link(&dev->kobj, "device");
-out_busid:
- if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
- device_is_not_partition(dev))
- sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj,
- dev_name(dev));
-#else
+#ifdef CONFIG_BLOCK
+ /* /sys/block has directories and does not need symlinks */
+ if (sysfs_deprecated && dev->class == &block_class)
+ return 0;
+#endif
+
/* link in the class directory pointing to the device */
error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
&dev->kobj, dev_name(dev));
if (error)
- goto out_subsys;
+ goto out_device;
- if (dev->parent && device_is_not_partition(dev)) {
- error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
- "device");
- if (error)
- goto out_busid;
- }
return 0;
-out_busid:
- sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
-#endif
+out_device:
+ sysfs_remove_link(&dev->kobj, "device");
out_subsys:
sysfs_remove_link(&dev->kobj, "subsystem");
@@ -818,30 +749,14 @@ static void device_remove_class_symlinks(struct device *dev)
if (!dev->class)
return;
-#ifdef CONFIG_SYSFS_DEPRECATED
- if (dev->parent && device_is_not_partition(dev)) {
- char *class_name;
-
- class_name = make_class_name(dev->class->name, &dev->kobj);
- if (class_name) {
- sysfs_remove_link(&dev->parent->kobj, class_name);
- kfree(class_name);
- }
- sysfs_remove_link(&dev->kobj, "device");
- }
-
- if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
- device_is_not_partition(dev))
- sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj,
- dev_name(dev));
-#else
if (dev->parent && device_is_not_partition(dev))
sysfs_remove_link(&dev->kobj, "device");
-
- sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
-#endif
-
sysfs_remove_link(&dev->kobj, "subsystem");
+#ifdef CONFIG_BLOCK
+ if (sysfs_deprecated && dev->class == &block_class)
+ return;
+#endif
+ sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
}
/**
@@ -1613,41 +1528,23 @@ int device_rename(struct device *dev, const char *new_name)
pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev),
__func__, new_name);
-#ifdef CONFIG_SYSFS_DEPRECATED
- if ((dev->class) && (dev->parent))
- old_class_name = make_class_name(dev->class->name, &dev->kobj);
-#endif
-
old_device_name = kstrdup(dev_name(dev), GFP_KERNEL);
if (!old_device_name) {
error = -ENOMEM;
goto out;
}
-#ifndef CONFIG_SYSFS_DEPRECATED
if (dev->class) {
error = sysfs_rename_link(&dev->class->p->class_subsys.kobj,
&dev->kobj, old_device_name, new_name);
if (error)
goto out;
}
-#endif
+
error = kobject_rename(&dev->kobj, new_name);
if (error)
goto out;
-#ifdef CONFIG_SYSFS_DEPRECATED
- if (old_class_name) {
- new_class_name = make_class_name(dev->class->name, &dev->kobj);
- if (new_class_name) {
- error = sysfs_rename_link(&dev->parent->kobj,
- &dev->kobj,
- old_class_name,
- new_class_name);
- }
- }
-#endif
-
out:
put_device(dev);
@@ -1664,40 +1561,13 @@ static int device_move_class_links(struct device *dev,
struct device *new_parent)
{
int error = 0;
-#ifdef CONFIG_SYSFS_DEPRECATED
- char *class_name;
- class_name = make_class_name(dev->class->name, &dev->kobj);
- if (!class_name) {
- error = -ENOMEM;
- goto out;
- }
- if (old_parent) {
- sysfs_remove_link(&dev->kobj, "device");
- sysfs_remove_link(&old_parent->kobj, class_name);
- }
- if (new_parent) {
- error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
- "device");
- if (error)
- goto out;
- error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
- class_name);
- if (error)
- sysfs_remove_link(&dev->kobj, "device");
- } else
- error = 0;
-out:
- kfree(class_name);
- return error;
-#else
if (old_parent)
sysfs_remove_link(&dev->kobj, "device");
if (new_parent)
error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
"device");
return error;
-#endif
}
/**
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 933442f40321..cafeaaf0428f 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -27,6 +27,8 @@
#include <asm/atomic.h>
#include <asm/uaccess.h>
+static DEFINE_MUTEX(mem_sysfs_mutex);
+
#define MEMORY_CLASS_NAME "memory"
static struct sysdev_class memory_sysdev_class = {
@@ -435,6 +437,45 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn)
return 0;
}
+struct memory_block *find_memory_block_hinted(struct mem_section *section,
+ struct memory_block *hint)
+{
+ struct kobject *kobj;
+ struct sys_device *sysdev;
+ struct memory_block *mem;
+ char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1];
+
+ kobj = hint ? &hint->sysdev.kobj : NULL;
+
+ /*
+ * This only works because we know that section == sysdev->id
+ * slightly redundant with sysdev_register()
+ */
+ sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section));
+
+ kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj);
+ if (!kobj)
+ return NULL;
+
+ sysdev = container_of(kobj, struct sys_device, kobj);
+ mem = container_of(sysdev, struct memory_block, sysdev);
+
+ return mem;
+}
+
+/*
+ * For now, we have a linear search to go find the appropriate
+ * memory_block corresponding to a particular phys_index. If
+ * this gets to be a real problem, we can always use a radix
+ * tree or something here.
+ *
+ * This could be made generic for all sysdev classes.
+ */
+struct memory_block *find_memory_block(struct mem_section *section)
+{
+ return find_memory_block_hinted(section, NULL);
+}
+
static int add_memory_block(int nid, struct mem_section *section,
unsigned long state, enum mem_add_context context)
{
@@ -445,8 +486,11 @@ static int add_memory_block(int nid, struct mem_section *section,
if (!mem)
return -ENOMEM;
+ mutex_lock(&mem_sysfs_mutex);
+
mem->phys_index = __section_nr(section);
mem->state = state;
+ mem->section_count++;
mutex_init(&mem->state_mutex);
start_pfn = section_nr_to_pfn(mem->phys_index);
mem->phys_device = arch_get_memory_phys_device(start_pfn);
@@ -465,53 +509,29 @@ static int add_memory_block(int nid, struct mem_section *section,
ret = register_mem_sect_under_node(mem, nid);
}
+ mutex_unlock(&mem_sysfs_mutex);
return ret;
}
-/*
- * For now, we have a linear search to go find the appropriate
- * memory_block corresponding to a particular phys_index. If
- * this gets to be a real problem, we can always use a radix
- * tree or something here.
- *
- * This could be made generic for all sysdev classes.
- */
-struct memory_block *find_memory_block(struct mem_section *section)
-{
- struct kobject *kobj;
- struct sys_device *sysdev;
- struct memory_block *mem;
- char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1];
-
- /*
- * This only works because we know that section == sysdev->id
- * slightly redundant with sysdev_register()
- */
- sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section));
-
- kobj = kset_find_obj(&memory_sysdev_class.kset, name);
- if (!kobj)
- return NULL;
-
- sysdev = container_of(kobj, struct sys_device, kobj);
- mem = container_of(sysdev, struct memory_block, sysdev);
-
- return mem;
-}
-
int remove_memory_block(unsigned long node_id, struct mem_section *section,
int phys_device)
{
struct memory_block *mem;
+ mutex_lock(&mem_sysfs_mutex);
mem = find_memory_block(section);
- unregister_mem_sect_under_nodes(mem);
- mem_remove_simple_file(mem, phys_index);
- mem_remove_simple_file(mem, state);
- mem_remove_simple_file(mem, phys_device);
- mem_remove_simple_file(mem, removable);
- unregister_memory(mem, section);
+ mem->section_count--;
+ if (mem->section_count == 0) {
+ unregister_mem_sect_under_nodes(mem);
+ mem_remove_simple_file(mem, phys_index);
+ mem_remove_simple_file(mem, state);
+ mem_remove_simple_file(mem, phys_device);
+ mem_remove_simple_file(mem, removable);
+ unregister_memory(mem, section);
+ }
+
+ mutex_unlock(&mem_sysfs_mutex);
return 0;
}
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 2872e86837b2..ce012a9c6201 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -160,6 +160,18 @@ static ssize_t node_read_numastat(struct sys_device * dev,
}
static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
+static ssize_t node_read_vmstat(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
+{
+ int nid = dev->id;
+ return sprintf(buf,
+ "nr_written %lu\n"
+ "nr_dirtied %lu\n",
+ node_page_state(nid, NR_WRITTEN),
+ node_page_state(nid, NR_DIRTIED));
+}
+static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
+
static ssize_t node_read_distance(struct sys_device * dev,
struct sysdev_attribute *attr, char * buf)
{
@@ -243,6 +255,7 @@ int register_node(struct node *node, int num, struct node *parent)
sysdev_create_file(&node->sysdev, &attr_meminfo);
sysdev_create_file(&node->sysdev, &attr_numastat);
sysdev_create_file(&node->sysdev, &attr_distance);
+ sysdev_create_file(&node->sysdev, &attr_vmstat);
scan_unevictable_register_node(node);
@@ -267,6 +280,7 @@ void unregister_node(struct node *node)
sysdev_remove_file(&node->sysdev, &attr_meminfo);
sysdev_remove_file(&node->sysdev, &attr_numastat);
sysdev_remove_file(&node->sysdev, &attr_distance);
+ sysdev_remove_file(&node->sysdev, &attr_vmstat);
scan_unevictable_unregister_node(node);
hugetlb_unregister_node(node); /* no-op, if memoryless node */
@@ -409,25 +423,27 @@ static int link_mem_sections(int nid)
unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
unsigned long pfn;
+ struct memory_block *mem_blk = NULL;
int err = 0;
for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
unsigned long section_nr = pfn_to_section_nr(pfn);
struct mem_section *mem_sect;
- struct memory_block *mem_blk;
int ret;
if (!present_section_nr(section_nr))
continue;
mem_sect = __nr_to_section(section_nr);
- mem_blk = find_memory_block(mem_sect);
+ mem_blk = find_memory_block_hinted(mem_sect, mem_blk);
ret = register_mem_sect_under_node(mem_blk, nid);
if (!err)
err = ret;
/* discard ref obtained in find_memory_block() */
- kobject_put(&mem_blk->sysdev.kobj);
}
+
+ if (mem_blk)
+ kobject_put(&mem_blk->sysdev.kobj);
return err;
}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index c6c933f58102..f051cfff18af 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -147,6 +147,7 @@ static void platform_device_release(struct device *dev)
struct platform_object *pa = container_of(dev, struct platform_object,
pdev.dev);
+ of_device_node_put(&pa->pdev.dev);
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.resource);
kfree(pa);
@@ -192,6 +193,9 @@ int platform_device_add_resources(struct platform_device *pdev,
{
struct resource *r;
+ if (!res)
+ return 0;
+
r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
if (r) {
pdev->resource = r;
@@ -215,8 +219,12 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources);
int platform_device_add_data(struct platform_device *pdev, const void *data,
size_t size)
{
- void *d = kmemdup(data, size, GFP_KERNEL);
+ void *d;
+
+ if (!data)
+ return 0;
+ d = kmemdup(data, size, GFP_KERNEL);
if (d) {
pdev->dev.platform_data = d;
return 0;
@@ -373,17 +381,13 @@ struct platform_device *__init_or_module platform_device_register_resndata(
pdev->dev.parent = parent;
- if (res) {
- ret = platform_device_add_resources(pdev, res, num);
- if (ret)
- goto err;
- }
+ ret = platform_device_add_resources(pdev, res, num);
+ if (ret)
+ goto err;
- if (data) {
- ret = platform_device_add_data(pdev, data, size);
- if (ret)
- goto err;
- }
+ ret = platform_device_add_data(pdev, data, size);
+ if (ret)
+ goto err;
ret = platform_device_add(pdev);
if (ret) {
@@ -488,12 +492,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
* if the probe was successful, and make sure any forced probes of
* new devices fail.
*/
- spin_lock(&platform_bus_type.p->klist_drivers.k_lock);
+ spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
drv->probe = NULL;
if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
retval = -ENODEV;
drv->driver.probe = platform_drv_probe_fail;
- spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
+ spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);
if (code != retval)
platform_driver_unregister(drv);
@@ -530,17 +534,13 @@ struct platform_device * __init_or_module platform_create_bundle(
goto err_out;
}
- if (res) {
- error = platform_device_add_resources(pdev, res, n_res);
- if (error)
- goto err_pdev_put;
- }
+ error = platform_device_add_resources(pdev, res, n_res);
+ if (error)
+ goto err_pdev_put;
- if (data) {
- error = platform_device_add_data(pdev, data, size);
- if (error)
- goto err_pdev_put;
- }
+ error = platform_device_add_data(pdev, data, size);
+ if (error)
+ goto err_pdev_put;
error = platform_device_add(pdev);
if (error)
@@ -976,6 +976,41 @@ struct bus_type platform_bus_type = {
};
EXPORT_SYMBOL_GPL(platform_bus_type);
+/**
+ * platform_bus_get_pm_ops() - return pointer to busses dev_pm_ops
+ *
+ * This function can be used by platform code to get the current
+ * set of dev_pm_ops functions used by the platform_bus_type.
+ */
+const struct dev_pm_ops * __init platform_bus_get_pm_ops(void)
+{
+ return platform_bus_type.pm;
+}
+
+/**
+ * platform_bus_set_pm_ops() - update dev_pm_ops for the platform_bus_type
+ *
+ * @pm: pointer to new dev_pm_ops struct to be used for platform_bus_type
+ *
+ * Platform code can override the dev_pm_ops methods of
+ * platform_bus_type by using this function. It is expected that
+ * platform code will first do a platform_bus_get_pm_ops(), then
+ * kmemdup it, then customize selected methods and pass a pointer to
+ * the new struct dev_pm_ops to this function.
+ *
+ * Since platform-specific code is customizing methods for *all*
+ * devices (not just platform-specific devices) it is expected that
+ * any custom overrides of these functions will keep existing behavior
+ * and simply extend it. For example, any customization of the
+ * runtime PM methods should continue to call the pm_generic_*
+ * functions as the default ones do in addition to the
+ * platform-specific behavior.
+ */
+void __init platform_bus_set_pm_ops(const struct dev_pm_ops *pm)
+{
+ platform_bus_type.pm = pm;
+}
+
int __init platform_bus_init(void)
{
int error;
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 1dd8676d7f55..126ca492dd08 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -503,7 +503,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
* the resume will actually succeed.
*/
if (dev->power.no_callbacks && !parent && dev->parent) {
- spin_lock(&dev->parent->power.lock);
+ spin_lock_nested(&dev->parent->power.lock, SINGLE_DEPTH_NESTING);
if (dev->parent->power.disable_depth > 0
|| dev->parent->power.ignore_children
|| dev->parent->power.runtime_status == RPM_ACTIVE) {
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 9354dc10a363..1667aaf4fde6 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -432,13 +432,13 @@ int sysdev_suspend(pm_message_t state)
/* resume current sysdev */
cls_driver:
drv = NULL;
- printk(KERN_ERR "Class suspend failed for %s\n",
- kobject_name(&sysdev->kobj));
+ printk(KERN_ERR "Class suspend failed for %s: %d\n",
+ kobject_name(&sysdev->kobj), ret);
aux_driver:
if (drv)
- printk(KERN_ERR "Class driver suspend failed for %s\n",
- kobject_name(&sysdev->kobj));
+ printk(KERN_ERR "Class driver suspend failed for %s: %d\n",
+ kobject_name(&sysdev->kobj), ret);
list_for_each_entry(err_drv, &cls->drivers, entry) {
if (err_drv == drv)
break;