Commit 1e510b8f authored by Patrick Mochel's avatar Patrick Mochel

driver model: introduce device_sem to protect global device list instead of device_lock.

- device_sem is added to make the global list walks easier (for power mgmt and shutdown), so
  they don't have to take and drop device_lock a lot. 

- Change list modifications to take device_sem instead of device_lock.

- Ditto for device refcount modifications.

- Kill get_device_locked(), as all the users are now gone. 
parent ec0a28d2
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
extern struct list_head global_device_list; extern struct list_head global_device_list;
extern spinlock_t device_lock; extern spinlock_t device_lock;
extern struct semaphore device_sem;
extern struct device * get_device_locked(struct device *); extern struct device * get_device_locked(struct device *);
......
...@@ -19,6 +19,8 @@ LIST_HEAD(global_device_list); ...@@ -19,6 +19,8 @@ LIST_HEAD(global_device_list);
int (*platform_notify)(struct device * dev) = NULL; int (*platform_notify)(struct device * dev) = NULL;
int (*platform_notify_remove)(struct device * dev) = NULL; int (*platform_notify_remove)(struct device * dev) = NULL;
DECLARE_MUTEX(device_sem);
spinlock_t device_lock = SPIN_LOCK_UNLOCKED; spinlock_t device_lock = SPIN_LOCK_UNLOCKED;
#define to_dev(node) container_of(node,struct device,driver_list) #define to_dev(node) container_of(node,struct device,driver_list)
...@@ -30,14 +32,14 @@ int device_add(struct device *dev) ...@@ -30,14 +32,14 @@ int device_add(struct device *dev)
if (!dev || !strlen(dev->bus_id)) if (!dev || !strlen(dev->bus_id))
return -EINVAL; return -EINVAL;
spin_lock(&device_lock); down(&device_sem);
dev->present = 1; dev->present = 1;
if (dev->parent) { if (dev->parent) {
list_add_tail(&dev->g_list,&dev->parent->g_list); list_add_tail(&dev->g_list,&dev->parent->g_list);
list_add_tail(&dev->node,&dev->parent->children); list_add_tail(&dev->node,&dev->parent->children);
} else } else
list_add_tail(&dev->g_list,&global_device_list); list_add_tail(&dev->g_list,&global_device_list);
spin_unlock(&device_lock); up(&device_sem);
pr_debug("DEV: registering device: ID = '%s', name = %s\n", pr_debug("DEV: registering device: ID = '%s', name = %s\n",
dev->bus_id, dev->name); dev->bus_id, dev->name);
...@@ -57,10 +59,10 @@ int device_add(struct device *dev) ...@@ -57,10 +59,10 @@ int device_add(struct device *dev)
devclass_add_device(dev); devclass_add_device(dev);
register_done: register_done:
if (error) { if (error) {
spin_lock(&device_lock); up(&device_sem);
list_del_init(&dev->g_list); list_del_init(&dev->g_list);
list_del_init(&dev->node); list_del_init(&dev->node);
spin_unlock(&device_lock); up(&device_sem);
} }
return error; return error;
} }
...@@ -106,22 +108,15 @@ int device_register(struct device *dev) ...@@ -106,22 +108,15 @@ int device_register(struct device *dev)
return error; return error;
} }
struct device * get_device_locked(struct device * dev) struct device * get_device(struct device * dev)
{ {
struct device * ret = dev; struct device * ret = dev;
down(&device_sem);
if (dev && dev->present && atomic_read(&dev->refcount) > 0) if (dev && dev->present && atomic_read(&dev->refcount) > 0)
atomic_inc(&dev->refcount); atomic_inc(&dev->refcount);
else else
ret = NULL; ret = NULL;
return ret; up(&device_sem);
}
struct device * get_device(struct device * dev)
{
struct device * ret;
spin_lock(&device_lock);
ret = get_device_locked(dev);
spin_unlock(&device_lock);
return ret; return ret;
} }
...@@ -131,12 +126,14 @@ struct device * get_device(struct device * dev) ...@@ -131,12 +126,14 @@ struct device * get_device(struct device * dev)
*/ */
void put_device(struct device * dev) void put_device(struct device * dev)
{ {
if (!atomic_dec_and_lock(&dev->refcount,&device_lock)) down(&device_sem);
if (!atomic_dec_and_test(&dev->refcount)) {
up(&device_sem);
return; return;
}
list_del_init(&dev->node); list_del_init(&dev->node);
list_del_init(&dev->g_list); list_del_init(&dev->g_list);
list_del_init(&dev->driver_list); up(&device_sem);
spin_unlock(&device_lock);
BUG_ON(dev->present); BUG_ON(dev->present);
...@@ -179,9 +176,9 @@ void device_del(struct device * dev) ...@@ -179,9 +176,9 @@ void device_del(struct device * dev)
*/ */
void device_unregister(struct device * dev) void device_unregister(struct device * dev)
{ {
spin_lock(&device_lock); down(&device_sem);
dev->present = 0; dev->present = 0;
spin_unlock(&device_lock); up(&device_sem);
pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n", pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n",
dev->bus_id,dev->name); dev->bus_id,dev->name);
......
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