summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/base.h33
-rw-r--r--drivers/base/bus.c44
-rw-r--r--drivers/base/core.c108
-rw-r--r--drivers/base/cpu.c2
-rw-r--r--drivers/base/dd.c45
-rw-r--r--drivers/base/driver.c15
-rw-r--r--drivers/base/firmware_class.c4
-rw-r--r--drivers/base/iommu.c2
-rw-r--r--drivers/base/node.c2
-rw-r--r--drivers/base/platform.c60
-rw-r--r--drivers/base/power/main.c67
-rw-r--r--drivers/base/power/power.h8
-rw-r--r--drivers/base/sys.c69
-rw-r--r--drivers/base/topology.c33
14 files changed, 340 insertions, 152 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 0a5f055dffba..ddc97496db4a 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -63,6 +63,32 @@ struct class_private {
#define to_class(obj) \
container_of(obj, struct class_private, class_subsys.kobj)
+/**
+ * struct device_private - structure to hold the private to the driver core portions of the device structure.
+ *
+ * @klist_children - klist containing all children of this device
+ * @knode_parent - node in sibling list
+ * @knode_driver - node in driver list
+ * @knode_bus - node in bus list
+ * @device - pointer back to the struct class that this structure is
+ * associated with.
+ *
+ * Nothing outside of the driver core should ever touch these fields.
+ */
+struct device_private {
+ struct klist klist_children;
+ struct klist_node knode_parent;
+ struct klist_node knode_driver;
+ struct klist_node knode_bus;
+ struct device *device;
+};
+#define to_device_private_parent(obj) \
+ container_of(obj, struct device_private, knode_parent)
+#define to_device_private_driver(obj) \
+ container_of(obj, struct device_private, knode_driver)
+#define to_device_private_bus(obj) \
+ container_of(obj, struct device_private, knode_bus)
+
/* initialisation functions */
extern int devices_init(void);
extern int buses_init(void);
@@ -86,10 +112,13 @@ extern void bus_remove_driver(struct device_driver *drv);
extern void driver_detach(struct device_driver *drv);
extern int driver_probe_device(struct device_driver *drv, struct device *dev);
+static inline int driver_match_device(struct device_driver *drv,
+ struct device *dev)
+{
+ return drv->bus->match && drv->bus->match(dev, drv);
+}
extern void sysdev_shutdown(void);
-extern int sysdev_suspend(pm_message_t state);
-extern int sysdev_resume(void);
extern char *make_class_name(const char *name, struct kobject *kobj);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 83f32b891fa9..dc030f1f00f1 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -198,7 +198,7 @@ static ssize_t driver_bind(struct device_driver *drv,
int err = -ENODEV;
dev = bus_find_device_by_name(bus, NULL, buf);
- if (dev && dev->driver == NULL) {
+ if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {
if (dev->parent) /* Needed for USB */
down(&dev->parent->sem);
down(&dev->sem);
@@ -253,7 +253,14 @@ static ssize_t store_drivers_probe(struct bus_type *bus,
static struct device *next_device(struct klist_iter *i)
{
struct klist_node *n = klist_next(i);
- return n ? container_of(n, struct device, knode_bus) : NULL;
+ struct device *dev = NULL;
+ struct device_private *dev_prv;
+
+ if (n) {
+ dev_prv = to_device_private_bus(n);
+ dev = dev_prv->device;
+ }
+ return dev;
}
/**
@@ -286,7 +293,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start,
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
- (start ? &start->knode_bus : NULL));
+ (start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
@@ -320,7 +327,7 @@ struct device *bus_find_device(struct bus_type *bus,
return NULL;
klist_iter_init_node(&bus->p->klist_devices, &i,
- (start ? &start->knode_bus : NULL));
+ (start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
break;
@@ -507,7 +514,8 @@ void bus_attach_device(struct device *dev)
ret = device_attach(dev);
WARN_ON(ret < 0);
if (ret >= 0)
- klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
+ klist_add_tail(&dev->p->knode_bus,
+ &bus->p->klist_devices);
}
}
@@ -528,8 +536,8 @@ void bus_remove_device(struct device *dev)
sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
dev_name(dev));
device_remove_attrs(dev->bus, dev);
- if (klist_node_attached(&dev->knode_bus))
- klist_del(&dev->knode_bus);
+ if (klist_node_attached(&dev->p->knode_bus))
+ klist_del(&dev->p->knode_bus);
pr_debug("bus: '%s': remove device %s\n",
dev->bus->name, dev_name(dev));
@@ -831,14 +839,16 @@ static void bus_remove_attrs(struct bus_type *bus)
static void klist_devices_get(struct klist_node *n)
{
- struct device *dev = container_of(n, struct device, knode_bus);
+ struct device_private *dev_prv = to_device_private_bus(n);
+ struct device *dev = dev_prv->device;
get_device(dev);
}
static void klist_devices_put(struct klist_node *n)
{
- struct device *dev = container_of(n, struct device, knode_bus);
+ struct device_private *dev_prv = to_device_private_bus(n);
+ struct device *dev = dev_prv->device;
put_device(dev);
}
@@ -932,6 +942,7 @@ bus_uevent_fail:
kset_unregister(&bus->p->subsys);
kfree(bus->p);
out:
+ bus->p = NULL;
return retval;
}
EXPORT_SYMBOL_GPL(bus_register);
@@ -953,6 +964,7 @@ void bus_unregister(struct bus_type *bus)
bus_remove_file(bus, &bus_attr_uevent);
kset_unregister(&bus->p->subsys);
kfree(bus->p);
+ bus->p = NULL;
}
EXPORT_SYMBOL_GPL(bus_unregister);
@@ -993,18 +1005,20 @@ static void device_insertion_sort_klist(struct device *a, struct list_head *list
{
struct list_head *pos;
struct klist_node *n;
+ struct device_private *dev_prv;
struct device *b;
list_for_each(pos, list) {
n = container_of(pos, struct klist_node, n_node);
- b = container_of(n, struct device, knode_bus);
+ dev_prv = to_device_private_bus(n);
+ b = dev_prv->device;
if (compare(a, b) <= 0) {
- list_move_tail(&a->knode_bus.n_node,
- &b->knode_bus.n_node);
+ list_move_tail(&a->p->knode_bus.n_node,
+ &b->p->knode_bus.n_node);
return;
}
}
- list_move_tail(&a->knode_bus.n_node, list);
+ list_move_tail(&a->p->knode_bus.n_node, list);
}
void bus_sort_breadthfirst(struct bus_type *bus,
@@ -1014,6 +1028,7 @@ void bus_sort_breadthfirst(struct bus_type *bus,
LIST_HEAD(sorted_devices);
struct list_head *pos, *tmp;
struct klist_node *n;
+ struct device_private *dev_prv;
struct device *dev;
struct klist *device_klist;
@@ -1022,7 +1037,8 @@ void bus_sort_breadthfirst(struct bus_type *bus,
spin_lock(&device_klist->k_lock);
list_for_each_safe(pos, tmp, &device_klist->k_list) {
n = container_of(pos, struct klist_node, n_node);
- dev = container_of(n, struct device, knode_bus);
+ dev_prv = to_device_private_bus(n);
+ dev = dev_prv->device;
device_insertion_sort_klist(dev, &sorted_devices, compare);
}
list_splice(&sorted_devices, &device_klist->k_list);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index f3eae630e589..e73c92d13a23 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -109,6 +109,7 @@ static struct sysfs_ops dev_sysfs_ops = {
static void device_release(struct kobject *kobj)
{
struct device *dev = to_dev(kobj);
+ struct device_private *p = dev->p;
if (dev->release)
dev->release(dev);
@@ -120,6 +121,7 @@ static void device_release(struct kobject *kobj)
WARN(1, KERN_ERR "Device '%s' does not have a release() "
"function, it is broken and must be fixed.\n",
dev_name(dev));
+ kfree(p);
}
static struct kobj_type device_ktype = {
@@ -134,8 +136,6 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
if (ktype == &device_ktype) {
struct device *dev = to_dev(kobj);
- if (dev->uevent_suppress)
- return 0;
if (dev->bus)
return 1;
if (dev->class)
@@ -507,14 +507,16 @@ EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
static void klist_children_get(struct klist_node *n)
{
- struct device *dev = container_of(n, struct device, knode_parent);
+ struct device_private *p = to_device_private_parent(n);
+ struct device *dev = p->device;
get_device(dev);
}
static void klist_children_put(struct klist_node *n)
{
- struct device *dev = container_of(n, struct device, knode_parent);
+ struct device_private *p = to_device_private_parent(n);
+ struct device *dev = p->device;
put_device(dev);
}
@@ -538,8 +540,6 @@ void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);
- klist_init(&dev->klist_children, klist_children_get,
- klist_children_put);
INIT_LIST_HEAD(&dev->dma_pools);
init_MUTEX(&dev->sem);
spin_lock_init(&dev->devres_lock);
@@ -777,17 +777,12 @@ static void device_remove_class_symlinks(struct device *dev)
int dev_set_name(struct device *dev, const char *fmt, ...)
{
va_list vargs;
- char *s;
+ int err;
va_start(vargs, fmt);
- vsnprintf(dev->bus_id, sizeof(dev->bus_id), fmt, vargs);
+ err = kobject_set_name_vargs(&dev->kobj, fmt, vargs);
va_end(vargs);
-
- /* ewww... some of these buggers have / in the name... */
- while ((s = strchr(dev->bus_id, '/')))
- *s = '!';
-
- return 0;
+ return err;
}
EXPORT_SYMBOL_GPL(dev_set_name);
@@ -864,12 +859,26 @@ int device_add(struct device *dev)
if (!dev)
goto done;
- /* Temporarily support init_name if it is set.
- * It will override bus_id for now */
- if (dev->init_name)
- dev_set_name(dev, "%s", dev->init_name);
+ dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
+ if (!dev->p) {
+ error = -ENOMEM;
+ goto done;
+ }
+ dev->p->device = dev;
+ klist_init(&dev->p->klist_children, klist_children_get,
+ klist_children_put);
+
+ /*
+ * for statically allocated devices, which should all be converted
+ * some day, we need to initialize the name. We prevent reading back
+ * the name, and force the use of dev_name()
+ */
+ if (dev->init_name) {
+ dev_set_name(dev, dev->init_name);
+ dev->init_name = NULL;
+ }
- if (!strlen(dev->bus_id))
+ if (!dev_name(dev))
goto done;
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
@@ -928,7 +937,8 @@ int device_add(struct device *dev)
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_attach_device(dev);
if (parent)
- klist_add_tail(&dev->knode_parent, &parent->klist_children);
+ klist_add_tail(&dev->p->knode_parent,
+ &parent->p->klist_children);
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
@@ -1042,7 +1052,7 @@ void device_del(struct device *dev)
device_pm_remove(dev);
dpm_sysfs_remove(dev);
if (parent)
- klist_del(&dev->knode_parent);
+ klist_del(&dev->p->knode_parent);
if (MAJOR(dev->devt)) {
device_remove_sys_dev_entry(dev);
device_remove_file(dev, &devt_attr);
@@ -1103,7 +1113,14 @@ void device_unregister(struct device *dev)
static struct device *next_device(struct klist_iter *i)
{
struct klist_node *n = klist_next(i);
- return n ? container_of(n, struct device, knode_parent) : NULL;
+ struct device *dev = NULL;
+ struct device_private *p;
+
+ if (n) {
+ p = to_device_private_parent(n);
+ dev = p->device;
+ }
+ return dev;
}
/**
@@ -1125,7 +1142,7 @@ int device_for_each_child(struct device *parent, void *data,
struct device *child;
int error = 0;
- klist_iter_init(&parent->klist_children, &i);
+ klist_iter_init(&parent->p->klist_children, &i);
while ((child = next_device(&i)) && !error)
error = fn(child, data);
klist_iter_exit(&i);
@@ -1156,7 +1173,7 @@ struct device *device_find_child(struct device *parent, void *data,
if (!parent)
return NULL;
- klist_iter_init(&parent->klist_children, &i);
+ klist_iter_init(&parent->p->klist_children, &i);
while ((child = next_device(&i)))
if (match(child, data) && get_device(child))
break;
@@ -1348,7 +1365,10 @@ struct device *device_create_vargs(struct class *class, struct device *parent,
dev->release = device_create_release;
dev_set_drvdata(dev, drvdata);
- vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
+ retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
+ if (retval)
+ goto error;
+
retval = device_register(dev);
if (retval)
goto error;
@@ -1452,19 +1472,15 @@ int device_rename(struct device *dev, char *new_name)
old_class_name = make_class_name(dev->class->name, &dev->kobj);
#endif
- old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+ old_device_name = kstrdup(dev_name(dev), GFP_KERNEL);
if (!old_device_name) {
error = -ENOMEM;
goto out;
}
- strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
- strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
error = kobject_rename(&dev->kobj, new_name);
- if (error) {
- strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
+ if (error)
goto out;
- }
#ifdef CONFIG_SYSFS_DEPRECATED
if (old_class_name) {
@@ -1545,8 +1561,10 @@ out:
* device_move - moves a device to a new parent
* @dev: the pointer to the struct device to be moved
* @new_parent: the new parent of the device (can by NULL)
+ * @dpm_order: how to reorder the dpm_list
*/
-int device_move(struct device *dev, struct device *new_parent)
+int device_move(struct device *dev, struct device *new_parent,
+ enum dpm_order dpm_order)
{
int error;
struct device *old_parent;
@@ -1556,6 +1574,7 @@ int device_move(struct device *dev, struct device *new_parent)
if (!dev)
return -EINVAL;
+ device_pm_lock();
new_parent = get_device(new_parent);
new_parent_kobj = get_device_parent(dev, new_parent);
@@ -1570,9 +1589,10 @@ int device_move(struct device *dev, struct device *new_parent)
old_parent = dev->parent;
dev->parent = new_parent;
if (old_parent)
- klist_remove(&dev->knode_parent);
+ klist_remove(&dev->p->knode_parent);
if (new_parent) {
- klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+ klist_add_tail(&dev->p->knode_parent,
+ &new_parent->p->klist_children);
set_dev_node(dev, dev_to_node(new_parent));
}
@@ -1584,11 +1604,11 @@ int device_move(struct device *dev, struct device *new_parent)
device_move_class_links(dev, new_parent, old_parent);
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
if (new_parent)
- klist_remove(&dev->knode_parent);
+ klist_remove(&dev->p->knode_parent);
dev->parent = old_parent;
if (old_parent) {
- klist_add_tail(&dev->knode_parent,
- &old_parent->klist_children);
+ klist_add_tail(&dev->p->knode_parent,
+ &old_parent->p->klist_children);
set_dev_node(dev, dev_to_node(old_parent));
}
}
@@ -1596,9 +1616,23 @@ int device_move(struct device *dev, struct device *new_parent)
put_device(new_parent);
goto out;
}
+ switch (dpm_order) {
+ case DPM_ORDER_NONE:
+ break;
+ case DPM_ORDER_DEV_AFTER_PARENT:
+ device_pm_move_after(dev, new_parent);
+ break;
+ case DPM_ORDER_PARENT_BEFORE_DEV:
+ device_pm_move_before(new_parent, dev);
+ break;
+ case DPM_ORDER_DEV_LAST:
+ device_pm_move_last(dev);
+ break;
+ }
out_put:
put_device(old_parent);
out:
+ device_pm_unlock();
put_device(dev);
return error;
}
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 719ee5c1c8d9..5b257a57bc57 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -107,7 +107,7 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
/*
* Print cpu online, possible, present, and system maps
*/
-static ssize_t print_cpus_map(char *buf, cpumask_t *map)
+static ssize_t print_cpus_map(char *buf, const struct cpumask *map)
{
int n = cpulist_scnprintf(buf, PAGE_SIZE-2, map);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 315bed8d5e7f..f17c3266a0e0 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -18,9 +18,11 @@
*/
#include <linux/device.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
+#include <linux/async.h>
#include "base.h"
#include "power/power.h"
@@ -28,7 +30,7 @@
static void driver_bound(struct device *dev)
{
- if (klist_node_attached(&dev->knode_driver)) {
+ if (klist_node_attached(&dev->p->knode_driver)) {
printk(KERN_WARNING "%s: device %s already bound\n",
__func__, kobject_name(&dev->kobj));
return;
@@ -41,7 +43,7 @@ static void driver_bound(struct device *dev)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev);
- klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices);
+ klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
}
static int driver_sysfs_add(struct device *dev)
@@ -168,18 +170,23 @@ int driver_probe_done(void)
}
/**
+ * wait_for_device_probe
+ * Wait for device probing to be completed.
+ */
+void wait_for_device_probe(void)
+{
+ /* wait for the known devices to complete their probing */
+ wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
+ async_synchronize_full();
+}
+
+/**
* driver_probe_device - attempt to bind device & driver together
* @drv: driver to bind a device to
* @dev: device to try to bind to the driver
*
- * First, we call the bus's match function, if one present, which should
- * compare the device IDs the driver supports with the device IDs of the
- * device. Note we don't do this ourselves because we don't know the
- * format of the ID structures, nor what is to be considered a match and
- * what is not.
- *
- * This function returns 1 if a match is found, -ENODEV if the device is
- * not registered, and 0 otherwise.
+ * This function returns -ENODEV if the device is not registered,
+ * 1 if the device is bound sucessfully and 0 otherwise.
*
* This function must be called with @dev->sem held. When called for a
* USB interface, @dev->parent->sem must be held as well.
@@ -190,21 +197,22 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
if (!device_is_registered(dev))
return -ENODEV;
- if (drv->bus->match && !drv->bus->match(dev, drv))
- goto done;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
ret = really_probe(dev, drv);
-done:
return ret;
}
static int __device_attach(struct device_driver *drv, void *data)
{
struct device *dev = data;
+
+ if (!driver_match_device(drv, dev))
+ return 0;
+
return driver_probe_device(drv, dev);
}
@@ -257,7 +265,7 @@ static int __driver_attach(struct device *dev, void *data)
* is an error.
*/
- if (drv->bus->match && !drv->bus->match(dev, drv))
+ if (!driver_match_device(drv, dev))
return 0;
if (dev->parent) /* Needed for USB */
@@ -310,7 +318,7 @@ static void __device_release_driver(struct device *dev)
drv->remove(dev);
devres_release_all(dev);
dev->driver = NULL;
- klist_remove(&dev->knode_driver);
+ klist_remove(&dev->p->knode_driver);
}
}
@@ -340,6 +348,7 @@ EXPORT_SYMBOL_GPL(device_release_driver);
*/
void driver_detach(struct device_driver *drv)
{
+ struct device_private *dev_prv;
struct device *dev;
for (;;) {
@@ -348,8 +357,10 @@ void driver_detach(struct device_driver *drv)
spin_unlock(&drv->p->klist_devices.k_lock);
break;
}
- dev = list_entry(drv->p->klist_devices.k_list.prev,
- struct device, knode_driver.n_node);
+ dev_prv = list_entry(drv->p->klist_devices.k_list.prev,
+ struct device_private,
+ knode_driver.n_node);
+ dev = dev_prv->device;
get_device(dev);
spin_unlock(&drv->p->klist_devices.k_lock);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 1e2bda780e48..c51f11bb29ae 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -19,7 +19,14 @@
static struct device *next_device(struct klist_iter *i)
{
struct klist_node *n = klist_next(i);
- return n ? container_of(n, struct device, knode_driver) : NULL;
+ struct device *dev = NULL;
+ struct device_private *dev_prv;
+
+ if (n) {
+ dev_prv = to_device_private_driver(n);
+ dev = dev_prv->device;
+ }
+ return dev;
}
/**
@@ -42,7 +49,7 @@ int driver_for_each_device(struct device_driver *drv, struct device *start,
return -EINVAL;
klist_iter_init_node(&drv->p->klist_devices, &i,
- start ? &start->knode_driver : NULL);
+ start ? &start->p->knode_driver : NULL);
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
@@ -76,7 +83,7 @@ struct device *driver_find_device(struct device_driver *drv,
return NULL;
klist_iter_init_node(&drv->p->klist_devices, &i,
- (start ? &start->knode_driver : NULL));
+ (start ? &start->p->knode_driver : NULL));
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
break;
@@ -216,6 +223,8 @@ int driver_register(struct device_driver *drv)
int ret;
struct device_driver *other;
+ BUG_ON(!drv->bus->p);
+
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 44699d9dd85c..d3a59c688fe4 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -319,7 +319,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
f_dev->parent = device;
f_dev->class = &firmware_class;
dev_set_drvdata(f_dev, fw_priv);
- f_dev->uevent_suppress = 1;
+ dev_set_uevent_suppress(f_dev, 1);
retval = device_register(f_dev);
if (retval) {
dev_err(device, "%s: device_register failed\n", __func__);
@@ -366,7 +366,7 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p,
}
if (uevent)
- f_dev->uevent_suppress = 0;
+ dev_set_uevent_suppress(f_dev, 0);
*dev_p = f_dev;
goto out;
diff --git a/drivers/base/iommu.c b/drivers/base/iommu.c
index 5e039d4f877c..c2d1eed90376 100644
--- a/drivers/base/iommu.c
+++ b/drivers/base/iommu.c
@@ -31,7 +31,7 @@ void register_iommu(struct iommu_ops *ops)
iommu_ops = ops;
}
-bool iommu_found()
+bool iommu_found(void)
{
return iommu_ops != NULL;
}
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 43fa90b837ee..f8f578a71b25 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -303,7 +303,7 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
- unsigned int nid;
+ int nid;
nid = get_nid_for_pfn(pfn);
if (nid < 0)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 349a1013603f..d2198f64ad4e 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -217,6 +217,7 @@ int platform_device_add_data(struct platform_device *pdev, const void *data,
if (d) {
memcpy(d, data, size);
pdev->dev.platform_data = d;
+ pdev->platform_data = d;
}
return d ? 0 : -ENOMEM;
}
@@ -246,6 +247,21 @@ int platform_device_add(struct platform_device *pdev)
else
dev_set_name(&pdev->dev, pdev->name);
+ /* We will remove platform_data field from struct device
+ * if all platform devices pass its platform specific data
+ * from platform_device. The conversion is going to be a
+ * long time, so we allow the two cases coexist to make
+ * this kind of fix more easily*/
+ if (pdev->platform_data && pdev->dev.platform_data) {
+ printk(KERN_ERR
+ "%s: use which platform_data?\n",
+ dev_name(&pdev->dev));
+ } else if (pdev->platform_data) {
+ pdev->dev.platform_data = pdev->platform_data;
+ } else if (pdev->dev.platform_data) {
+ pdev->platform_data = pdev->dev.platform_data;
+ }
+
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
@@ -584,10 +600,25 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct platform_device *pdev = to_platform_device(dev);
- add_uevent_var(env, "MODALIAS=platform:%s", pdev->name);
+ add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
+ (pdev->id_entry) ? pdev->id_entry->name : pdev->name);
return 0;
}
+static const struct platform_device_id *platform_match_id(
+ struct platform_device_id *id,
+ struct platform_device *pdev)
+{
+ while (id->name[0]) {
+ if (strcmp(pdev->name, id->name) == 0) {
+ pdev->id_entry = id;
+ return id;
+ }
+ id++;
+ }
+ return NULL;
+}
+
/**
* platform_match - bind platform device to platform driver.
* @dev: device.
@@ -603,9 +634,14 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
*/
static int platform_match(struct device *dev, struct device_driver *drv)
{
- struct platform_device *pdev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct platform_driver *pdrv = to_platform_driver(drv);
- pdev = container_of(dev, struct platform_device, dev);
+ /* match against the id table first */
+ if (pdrv->id_table)
+ return platform_match_id(pdrv->id_table, pdev) != NULL;
+
+ /* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
@@ -623,26 +659,24 @@ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg)
{
- struct platform_driver *drv = to_platform_driver(dev->driver);
- struct platform_device *pdev;
+ struct platform_driver *pdrv = to_platform_driver(dev->driver);
+ struct platform_device *pdev = to_platform_device(dev);
int ret = 0;
- pdev = container_of(dev, struct platform_device, dev);
- if (dev->driver && drv->suspend_late)
- ret = drv->suspend_late(pdev, mesg);
+ if (dev->driver && pdrv->suspend_late)
+ ret = pdrv->suspend_late(pdev, mesg);
return ret;
}
static int platform_legacy_resume_early(struct device *dev)
{
- struct platform_driver *drv = to_platform_driver(dev->driver);
- struct platform_device *pdev;
+ struct platform_driver *pdrv = to_platform_driver(dev->driver);
+ struct platform_device *pdev = to_platform_device(dev);
int ret = 0;
- pdev = container_of(dev, struct platform_device, dev);
- if (dev->driver && drv->resume_early)
- ret = drv->resume_early(pdev);
+ if (dev->driver && pdrv->resume_early)
+ ret = pdrv->resume_early(pdev);
return ret;
}
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 670c9d6c1407..69b4ddb7de3b 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -23,6 +23,7 @@
#include <linux/pm.h>
#include <linux/resume-trace.h>
#include <linux/rwsem.h>
+#include <linux/interrupt.h>
#include "../base.h"
#include "power.h"
@@ -107,6 +108,50 @@ void device_pm_remove(struct device *dev)
}
/**
+ * device_pm_move_before - move device in dpm_list
+ * @deva: Device to move in dpm_list
+ * @devb: Device @deva should come before
+ */
+void device_pm_move_before(struct device *deva, struct device *devb)
+{
+ pr_debug("PM: Moving %s:%s before %s:%s\n",
+ deva->bus ? deva->bus->name : "No Bus",
+ kobject_name(&deva->kobj),
+ devb->bus ? devb->bus->name : "No Bus",
+ kobject_name(&devb->kobj));
+ /* Delete deva from dpm_list and reinsert before devb. */
+ list_move_tail(&deva->power.entry, &devb->power.entry);
+}
+
+/**
+ * device_pm_move_after - move device in dpm_list
+ * @deva: Device to move in dpm_list
+ * @devb: Device @deva should come after
+ */
+void device_pm_move_after(struct device *deva, struct device *devb)
+{
+ pr_debug("PM: Moving %s:%s after %s:%s\n",
+ deva->bus ? deva->bus->name : "No Bus",
+ kobject_name(&deva->kobj),
+ devb->bus ? devb->bus->name : "No Bus",
+ kobject_name(&devb->kobj));
+ /* Delete deva from dpm_list and reinsert after devb. */
+ list_move(&deva->power.entry, &devb->power.entry);
+}
+
+/**
+ * device_pm_move_last - move device to end of dpm_list
+ * @dev: Device to move in dpm_list
+ */
+void device_pm_move_last(struct device *dev)
+{
+ pr_debug("PM: Moving %s:%s to end of list\n",
+ dev->bus ? dev->bus->name : "No Bus",
+ kobject_name(&dev->kobj));
+ list_move_tail(&dev->power.entry, &dpm_list);
+}
+
+/**
* pm_op - execute the PM operation appropiate for given PM event
* @dev: Device.
* @ops: PM operations to choose from.
@@ -305,7 +350,8 @@ static int resume_device_noirq(struct device *dev, pm_message_t state)
* Execute the appropriate "noirq resume" callback for all devices marked
* as DPM_OFF_IRQ.
*
- * Must be called with interrupts disabled and only one CPU running.
+ * Must be called under dpm_list_mtx. Device drivers should not receive
+ * interrupts while it's being executed.
*/
static void dpm_power_up(pm_message_t state)
{
@@ -326,15 +372,13 @@ static void dpm_power_up(pm_message_t state)
* device_power_up - Turn on all devices that need special attention.
* @state: PM transition of the system being carried out.
*
- * Power on system devices, then devices that required we shut them down
- * with interrupts disabled.
- *
- * Must be called with interrupts disabled.
+ * Call the "early" resume handlers and enable device drivers to receive
+ * interrupts.
*/
void device_power_up(pm_message_t state)
{
- sysdev_resume();
dpm_power_up(state);
+ resume_device_irqs();
}
EXPORT_SYMBOL_GPL(device_power_up);
@@ -559,16 +603,17 @@ static int suspend_device_noirq(struct device *dev, pm_message_t state)
* device_power_down - Shut down special devices.
* @state: PM transition of the system being carried out.
*
- * Power down devices that require interrupts to be disabled.
- * Then power down system devices.
+ * Prevent device drivers from receiving interrupts and call the "late"
+ * suspend handlers.
*
- * Must be called with interrupts disabled and only one CPU running.
+ * Must be called under dpm_list_mtx.
*/
int device_power_down(pm_message_t state)
{
struct device *dev;
int error = 0;
+ suspend_device_irqs();
list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
error = suspend_device_noirq(dev, state);
if (error) {
@@ -577,10 +622,8 @@ int device_power_down(pm_message_t state)
}
dev->power.status = DPM_OFF_IRQ;
}
- if (!error)
- error = sysdev_suspend(state);
if (error)
- dpm_power_up(resume_event(state));
+ device_power_up(resume_event(state));
return error;
}
EXPORT_SYMBOL_GPL(device_power_down);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 41f51fae042f..c7cb4fc3735c 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -18,11 +18,19 @@ static inline struct device *to_device(struct list_head *entry)
extern void device_pm_add(struct device *);
extern void device_pm_remove(struct device *);
+extern void device_pm_move_before(struct device *, struct device *);
+extern void device_pm_move_after(struct device *, struct device *);
+extern void device_pm_move_last(struct device *);
#else /* CONFIG_PM_SLEEP */
static inline void device_pm_add(struct device *dev) {}
static inline void device_pm_remove(struct device *dev) {}
+static inline void device_pm_move_before(struct device *deva,
+ struct device *devb) {}
+static inline void device_pm_move_after(struct device *deva,
+ struct device *devb) {}
+static inline void device_pm_move_last(struct device *dev) {}
#endif
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index c98c31ec2f75..76ce75bad91e 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -22,6 +22,7 @@
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/mutex.h>
+#include <linux/interrupt.h>
#include "base.h"
@@ -30,10 +31,10 @@
static ssize_t
-sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
+sysdev_show(struct kobject *kobj, struct attribute *attr, char *buffer)
{
- struct sys_device * sysdev = to_sysdev(kobj);
- struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
+ struct sys_device *sysdev = to_sysdev(kobj);
+ struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr);
if (sysdev_attr->show)
return sysdev_attr->show(sysdev, sysdev_attr, buffer);
@@ -42,11 +43,11 @@ sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
static ssize_t
-sysdev_store(struct kobject * kobj, struct attribute * attr,
- const char * buffer, size_t count)
+sysdev_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
{
- struct sys_device * sysdev = to_sysdev(kobj);
- struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
+ struct sys_device *sysdev = to_sysdev(kobj);
+ struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr);
if (sysdev_attr->store)
return sysdev_attr->store(sysdev, sysdev_attr, buffer, count);
@@ -63,13 +64,13 @@ static struct kobj_type ktype_sysdev = {
};
-int sysdev_create_file(struct sys_device * s, struct sysdev_attribute * a)
+int sysdev_create_file(struct sys_device *s, struct sysdev_attribute *a)
{
return sysfs_create_file(&s->kobj, &a->attr);
}
-void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a)
+void sysdev_remove_file(struct sys_device *s, struct sysdev_attribute *a)
{
sysfs_remove_file(&s->kobj, &a->attr);
}
@@ -84,7 +85,7 @@ EXPORT_SYMBOL_GPL(sysdev_remove_file);
static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,
char *buffer)
{
- struct sysdev_class * class = to_sysdev_class(kobj);
+ struct sysdev_class *class = to_sysdev_class(kobj);
struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
if (class_attr->show)
@@ -95,8 +96,8 @@ static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,
static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr,
const char *buffer, size_t count)
{
- struct sysdev_class * class = to_sysdev_class(kobj);
- struct sysdev_class_attribute * class_attr = to_sysdev_class_attr(attr);
+ struct sysdev_class *class = to_sysdev_class(kobj);
+ struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
if (class_attr->store)
return class_attr->store(class, buffer, count);
@@ -128,7 +129,7 @@ EXPORT_SYMBOL_GPL(sysdev_class_remove_file);
static struct kset *system_kset;
-int sysdev_class_register(struct sysdev_class * cls)
+int sysdev_class_register(struct sysdev_class *cls)
{
pr_debug("Registering sysdev class '%s'\n", cls->name);
@@ -141,7 +142,7 @@ int sysdev_class_register(struct sysdev_class * cls)
return kset_register(&cls->kset);
}
-void sysdev_class_unregister(struct sysdev_class * cls)
+void sysdev_class_unregister(struct sysdev_class *cls)
{
pr_debug("Unregistering sysdev class '%s'\n",
kobject_name(&cls->kset.kobj));
@@ -203,8 +204,8 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
* @cls: Class driver belongs to.
* @drv: Driver.
*/
-void sysdev_driver_unregister(struct sysdev_class * cls,
- struct sysdev_driver * drv)
+void sysdev_driver_unregister(struct sysdev_class *cls,
+ struct sysdev_driver *drv)
{
mutex_lock(&sysdev_drivers_lock);
list_del_init(&drv->entry);
@@ -229,10 +230,10 @@ EXPORT_SYMBOL_GPL(sysdev_driver_unregister);
* @sysdev: device in question
*
*/
-int sysdev_register(struct sys_device * sysdev)
+int sysdev_register(struct sys_device *sysdev)
{
int error;
- struct sysdev_class * cls = sysdev->cls;
+ struct sysdev_class *cls = sysdev->cls;
if (!cls)
return -EINVAL;
@@ -252,7 +253,7 @@ int sysdev_register(struct sys_device * sysdev)
sysdev->id);
if (!error) {
- struct sysdev_driver * drv;
+ struct sysdev_driver *drv;
pr_debug("Registering sys device '%s'\n",
kobject_name(&sysdev->kobj));
@@ -274,9 +275,9 @@ int sysdev_register(struct sys_device * sysdev)
return error;
}
-void sysdev_unregister(struct sys_device * sysdev)
+void sysdev_unregister(struct sys_device *sysdev)
{
- struct sysdev_driver * drv;
+ struct sysdev_driver *drv;
mutex_lock(&sysdev_drivers_lock);
list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
@@ -303,22 +304,21 @@ void sysdev_unregister(struct sys_device * sysdev)
* is guaranteed by virtue of the fact that child devices are registered
* after their parents.
*/
-
void sysdev_shutdown(void)
{
- struct sysdev_class * cls;
+ struct sysdev_class *cls;
pr_debug("Shutting Down System Devices\n");
mutex_lock(&sysdev_drivers_lock);
list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
- struct sys_device * sysdev;
+ struct sys_device *sysdev;
pr_debug("Shutting down type '%s':\n",
kobject_name(&cls->kset.kobj));
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
- struct sysdev_driver * drv;
+ struct sysdev_driver *drv;
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
/* Call auxillary drivers first */
@@ -363,14 +363,20 @@ static void __sysdev_resume(struct sys_device *dev)
* This is only called by the device PM core, so we let them handle
* all synchronization.
*/
-
int sysdev_suspend(pm_message_t state)
{
- struct sysdev_class * cls;
+ struct sysdev_class *cls;
struct sys_device *sysdev, *err_dev;
struct sysdev_driver *drv, *err_drv;
int ret;
+ pr_debug("Checking wake-up interrupts\n");
+
+ /* Return error code if there are any wake-up interrupts pending */
+ ret = check_wakeup_irqs();
+ if (ret)
+ return ret;
+
pr_debug("Suspending System Devices\n");
list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
@@ -432,7 +438,7 @@ aux_driver:
}
return ret;
}
-
+EXPORT_SYMBOL_GPL(sysdev_suspend);
/**
* sysdev_resume - Bring system devices back to life.
@@ -442,15 +448,14 @@ aux_driver:
*
* Note: Interrupts are disabled when called.
*/
-
int sysdev_resume(void)
{
- struct sysdev_class * cls;
+ struct sysdev_class *cls;
pr_debug("Resuming System Devices\n");
list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) {
- struct sys_device * sysdev;
+ struct sys_device *sysdev;
pr_debug("Resuming type '%s':\n",
kobject_name(&cls->kset.kobj));
@@ -463,7 +468,7 @@ int sysdev_resume(void)
}
return 0;
}
-
+EXPORT_SYMBOL_GPL(sysdev_resume);
int __init system_bus_init(void)
{
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index a778fb52b11f..bf6b13206d00 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -31,7 +31,10 @@
#include <linux/hardirq.h>
#include <linux/topology.h>
-#define define_one_ro(_name) \
+#define define_one_ro_named(_name, _func) \
+static SYSDEV_ATTR(_name, 0444, _func, NULL)
+
+#define define_one_ro(_name) \
static SYSDEV_ATTR(_name, 0444, show_##_name, NULL)
#define define_id_show_func(name) \
@@ -42,8 +45,8 @@ static ssize_t show_##name(struct sys_device *dev, \
return sprintf(buf, "%d\n", topology_##name(cpu)); \
}
-#if defined(topology_thread_siblings) || defined(topology_core_siblings)
-static ssize_t show_cpumap(int type, cpumask_t *mask, char *buf)
+#if defined(topology_thread_cpumask) || defined(topology_core_cpumask)
+static ssize_t show_cpumap(int type, const struct cpumask *mask, char *buf)
{
ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
int n = 0;
@@ -65,7 +68,7 @@ static ssize_t show_##name(struct sys_device *dev, \
struct sysdev_attribute *attr, char *buf) \
{ \
unsigned int cpu = dev->id; \
- return show_cpumap(0, &(topology_##name(cpu)), buf); \
+ return show_cpumap(0, topology_##name(cpu), buf); \
}
#define define_siblings_show_list(name) \
@@ -74,7 +77,7 @@ static ssize_t show_##name##_list(struct sys_device *dev, \
char *buf) \
{ \
unsigned int cpu = dev->id; \
- return show_cpumap(1, &(topology_##name(cpu)), buf); \
+ return show_cpumap(1, topology_##name(cpu), buf); \
}
#else
@@ -82,9 +85,7 @@ static ssize_t show_##name##_list(struct sys_device *dev, \
static ssize_t show_##name(struct sys_device *dev, \
struct sysdev_attribute *attr, char *buf) \
{ \
- unsigned int cpu = dev->id; \
- cpumask_t mask = topology_##name(cpu); \
- return show_cpumap(0, &mask, buf); \
+ return show_cpumap(0, topology_##name(dev->id), buf); \
}
#define define_siblings_show_list(name) \
@@ -92,9 +93,7 @@ static ssize_t show_##name##_list(struct sys_device *dev, \
struct sysdev_attribute *attr, \
char *buf) \
{ \
- unsigned int cpu = dev->id; \
- cpumask_t mask = topology_##name(cpu); \
- return show_cpumap(1, &mask, buf); \
+ return show_cpumap(1, topology_##name(dev->id), buf); \
}
#endif
@@ -107,13 +106,13 @@ define_one_ro(physical_package_id);
define_id_show_func(core_id);
define_one_ro(core_id);
-define_siblings_show_func(thread_siblings);
-define_one_ro(thread_siblings);
-define_one_ro(thread_siblings_list);
+define_siblings_show_func(thread_cpumask);
+define_one_ro_named(thread_siblings, show_thread_cpumask);
+define_one_ro_named(thread_siblings_list, show_thread_cpumask_list);
-define_siblings_show_func(core_siblings);
-define_one_ro(core_siblings);
-define_one_ro(core_siblings_list);
+define_siblings_show_func(core_cpumask);
+define_one_ro_named(core_siblings, show_core_cpumask);
+define_one_ro_named(core_siblings_list, show_core_cpumask_list);
static struct attribute *default_attrs[] = {
&attr_physical_package_id.attr,