The adapters (de)registration are now protectd by using a dedicated mutex instead of using global "core_lock" one. This allow multiple (and recursive) (de)registration of several adapters (or i2c multiplexers acting as i2c virtual adapters). Signed-off-by: Rodolfo Giometti <giometti@xxxxxxxx> --- drivers/i2c/i2c-core.c | 57 +++++++++++++++++++++++------------------------ 1 files changed, 28 insertions(+), 29 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 5d3646f..4b088ef 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -40,6 +40,7 @@ static DEFINE_MUTEX(core_lock); +static DEFINE_MUTEX(idr_adapter_lock); static DEFINE_IDR(i2c_adapter_idr); #define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) @@ -438,7 +439,7 @@ static int i2c_do_add_adapter(struct device_driver *d, void *data) static int i2c_register_adapter(struct i2c_adapter *adap) { - int res = 0, dummy; + int res, dummy; /* Can't register until after driver model init */ if (unlikely(WARN_ON(!i2c_bus_type.p))) @@ -448,8 +449,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap) mutex_init(&adap->clist_lock); INIT_LIST_HEAD(&adap->clients); - mutex_lock(&core_lock); - /* Add the adapter to the driver core. * If the parent pointer is not set up, * we add this adapter to the host bus. @@ -463,8 +462,13 @@ static int i2c_register_adapter(struct i2c_adapter *adap) adap->dev.release = &i2c_adapter_dev_release; adap->dev.class = &i2c_adapter_class; res = device_register(&adap->dev); - if (res) - goto out_list; + if (res) { + mutex_lock(&idr_adapter_lock); + idr_remove(&i2c_adapter_idr, adap->nr); + mutex_unlock(&idr_adapter_lock); + + return res; + } dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); @@ -476,13 +480,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter); -out_unlock: - mutex_unlock(&core_lock); - return res; - -out_list: - idr_remove(&i2c_adapter_idr, adap->nr); - goto out_unlock; + return 0; } /** @@ -506,11 +504,11 @@ retry: if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) return -ENOMEM; - mutex_lock(&core_lock); + mutex_lock(&idr_adapter_lock); /* "above" here means "above or equal to", sigh */ res = idr_get_new_above(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, &id); - mutex_unlock(&core_lock); + mutex_unlock(&idr_adapter_lock); if (res < 0) { if (res == -EAGAIN) @@ -555,7 +553,7 @@ retry: if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) return -ENOMEM; - mutex_lock(&core_lock); + mutex_lock(&idr_adapter_lock); /* "above" here means "above or equal to", sigh; * we need the "equal to" result to force the result */ @@ -564,7 +562,7 @@ retry: status = -EBUSY; idr_remove(&i2c_adapter_idr, id); } - mutex_unlock(&core_lock); + mutex_unlock(&idr_adapter_lock); if (status == -EAGAIN) goto retry; @@ -612,19 +610,25 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) */ int i2c_del_adapter(struct i2c_adapter *adap) { + struct i2c_adapter *ptr; struct i2c_client *client, *_n; - int res = 0, dummy; + int dummy; - mutex_lock(&core_lock); + mutex_lock(&idr_adapter_lock); /* First make sure that this adapter was ever added */ - if (idr_find(&i2c_adapter_idr, adap->nr) != adap) { + ptr = idr_find(&i2c_adapter_idr, adap->nr); + if (ptr != adap) { pr_debug("i2c-core: attempting to delete unregistered " "adapter [%s]\n", adap->name); - res = -EINVAL; - goto out_unlock; + mutex_unlock(&idr_adapter_lock); + return -EINVAL; } + /* ... then remove adapter ID */ + idr_remove(&i2c_adapter_idr, adap->nr); + mutex_unlock(&idr_adapter_lock); + /* Tell drivers about this removal */ dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_del_adapter); @@ -655,18 +659,13 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* wait for sysfs to drop all references */ wait_for_completion(&adap->dev_released); - /* free bus id */ - idr_remove(&i2c_adapter_idr, adap->nr); - dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); /* Clear the device structure in case this adapter is ever going to be added again */ memset(&adap->dev, 0, sizeof(adap->dev)); - out_unlock: - mutex_unlock(&core_lock); - return res; + return 0; } EXPORT_SYMBOL(i2c_del_adapter); @@ -1497,12 +1496,12 @@ struct i2c_adapter* i2c_get_adapter(int id) { struct i2c_adapter *adapter; - mutex_lock(&core_lock); + mutex_lock(&idr_adapter_lock); adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; - mutex_unlock(&core_lock); + mutex_unlock(&idr_adapter_lock); return adapter; } EXPORT_SYMBOL(i2c_get_adapter); -- 1.5.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html