diff options
author | Jean Delvare <khali@linux-fr.org> | 2009-06-19 10:58:19 -0400 |
---|---|---|
committer | Jean Delvare <khali@linux-fr.org> | 2009-06-19 10:58:19 -0400 |
commit | 35fc37f8188177e3ba3e7f99a6e3300e490e9181 (patch) | |
tree | ed2e7f589cb33b0b8bb81aa0a7958c3d6c0cb002 /drivers/i2c/i2c-core.c | |
parent | e549c2b54dd90a056d6824b885d438b7437874f0 (diff) |
i2c: Limit core locking to the necessary sections
The i2c-core code tends to hold the core lock for longer than it
should. Limit locking to the necessary sections for both performance
and clarity. This is also a requirement to support I2C multiplexers in
the future.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Tested-by: Rodolfo Giometti <giometti@linux.it>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Diffstat (limited to 'drivers/i2c/i2c-core.c')
-rw-r--r-- | drivers/i2c/i2c-core.c | 51 |
1 files changed, 28 insertions, 23 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b1fd00d9a5c..a2f1cd3766f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -38,6 +38,9 @@ | |||
38 | #include "i2c-core.h" | 38 | #include "i2c-core.h" |
39 | 39 | ||
40 | 40 | ||
41 | /* core_lock protects i2c_adapter_idr, and guarantees | ||
42 | that device detection, deletion of detected devices, and attach_adapter | ||
43 | and detach_adapter calls are serialized */ | ||
41 | static DEFINE_MUTEX(core_lock); | 44 | static DEFINE_MUTEX(core_lock); |
42 | static DEFINE_IDR(i2c_adapter_idr); | 45 | static DEFINE_IDR(i2c_adapter_idr); |
43 | 46 | ||
@@ -418,13 +421,13 @@ static int i2c_register_adapter(struct i2c_adapter *adap) | |||
418 | int res = 0, dummy; | 421 | int res = 0, dummy; |
419 | 422 | ||
420 | /* Can't register until after driver model init */ | 423 | /* Can't register until after driver model init */ |
421 | if (unlikely(WARN_ON(!i2c_bus_type.p))) | 424 | if (unlikely(WARN_ON(!i2c_bus_type.p))) { |
422 | return -EAGAIN; | 425 | res = -EAGAIN; |
426 | goto out_list; | ||
427 | } | ||
423 | 428 | ||
424 | mutex_init(&adap->bus_lock); | 429 | mutex_init(&adap->bus_lock); |
425 | 430 | ||
426 | mutex_lock(&core_lock); | ||
427 | |||
428 | /* Set default timeout to 1 second if not already set */ | 431 | /* Set default timeout to 1 second if not already set */ |
429 | if (adap->timeout == 0) | 432 | if (adap->timeout == 0) |
430 | adap->timeout = HZ; | 433 | adap->timeout = HZ; |
@@ -443,16 +446,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap) | |||
443 | i2c_scan_static_board_info(adap); | 446 | i2c_scan_static_board_info(adap); |
444 | 447 | ||
445 | /* Notify drivers */ | 448 | /* Notify drivers */ |
449 | mutex_lock(&core_lock); | ||
446 | dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, | 450 | dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, |
447 | i2c_do_add_adapter); | 451 | i2c_do_add_adapter); |
448 | |||
449 | out_unlock: | ||
450 | mutex_unlock(&core_lock); | 452 | mutex_unlock(&core_lock); |
451 | return res; | 453 | |
454 | return 0; | ||
452 | 455 | ||
453 | out_list: | 456 | out_list: |
457 | mutex_lock(&core_lock); | ||
454 | idr_remove(&i2c_adapter_idr, adap->nr); | 458 | idr_remove(&i2c_adapter_idr, adap->nr); |
455 | goto out_unlock; | 459 | mutex_unlock(&core_lock); |
460 | return res; | ||
456 | } | 461 | } |
457 | 462 | ||
458 | /** | 463 | /** |
@@ -590,22 +595,25 @@ static int __unregister_client(struct device *dev, void *dummy) | |||
590 | int i2c_del_adapter(struct i2c_adapter *adap) | 595 | int i2c_del_adapter(struct i2c_adapter *adap) |
591 | { | 596 | { |
592 | int res = 0; | 597 | int res = 0; |
593 | 598 | struct i2c_adapter *found; | |
594 | mutex_lock(&core_lock); | ||
595 | 599 | ||
596 | /* First make sure that this adapter was ever added */ | 600 | /* First make sure that this adapter was ever added */ |
597 | if (idr_find(&i2c_adapter_idr, adap->nr) != adap) { | 601 | mutex_lock(&core_lock); |
602 | found = idr_find(&i2c_adapter_idr, adap->nr); | ||
603 | mutex_unlock(&core_lock); | ||
604 | if (found != adap) { | ||
598 | pr_debug("i2c-core: attempting to delete unregistered " | 605 | pr_debug("i2c-core: attempting to delete unregistered " |
599 | "adapter [%s]\n", adap->name); | 606 | "adapter [%s]\n", adap->name); |
600 | res = -EINVAL; | 607 | return -EINVAL; |
601 | goto out_unlock; | ||
602 | } | 608 | } |
603 | 609 | ||
604 | /* Tell drivers about this removal */ | 610 | /* Tell drivers about this removal */ |
611 | mutex_lock(&core_lock); | ||
605 | res = bus_for_each_drv(&i2c_bus_type, NULL, adap, | 612 | res = bus_for_each_drv(&i2c_bus_type, NULL, adap, |
606 | i2c_do_del_adapter); | 613 | i2c_do_del_adapter); |
614 | mutex_unlock(&core_lock); | ||
607 | if (res) | 615 | if (res) |
608 | goto out_unlock; | 616 | return res; |
609 | 617 | ||
610 | /* Detach any active clients. This can't fail, thus we do not | 618 | /* Detach any active clients. This can't fail, thus we do not |
611 | checking the returned value. */ | 619 | checking the returned value. */ |
@@ -619,7 +627,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) | |||
619 | wait_for_completion(&adap->dev_released); | 627 | wait_for_completion(&adap->dev_released); |
620 | 628 | ||
621 | /* free bus id */ | 629 | /* free bus id */ |
630 | mutex_lock(&core_lock); | ||
622 | idr_remove(&i2c_adapter_idr, adap->nr); | 631 | idr_remove(&i2c_adapter_idr, adap->nr); |
632 | mutex_unlock(&core_lock); | ||
623 | 633 | ||
624 | dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); | 634 | dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); |
625 | 635 | ||
@@ -627,9 +637,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) | |||
627 | added again */ | 637 | added again */ |
628 | memset(&adap->dev, 0, sizeof(adap->dev)); | 638 | memset(&adap->dev, 0, sizeof(adap->dev)); |
629 | 639 | ||
630 | out_unlock: | 640 | return 0; |
631 | mutex_unlock(&core_lock); | ||
632 | return res; | ||
633 | } | 641 | } |
634 | EXPORT_SYMBOL(i2c_del_adapter); | 642 | EXPORT_SYMBOL(i2c_del_adapter); |
635 | 643 | ||
@@ -674,16 +682,15 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) | |||
674 | if (res) | 682 | if (res) |
675 | return res; | 683 | return res; |
676 | 684 | ||
677 | mutex_lock(&core_lock); | ||
678 | |||
679 | pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); | 685 | pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); |
680 | 686 | ||
681 | INIT_LIST_HEAD(&driver->clients); | 687 | INIT_LIST_HEAD(&driver->clients); |
682 | /* Walk the adapters that are already present */ | 688 | /* Walk the adapters that are already present */ |
689 | mutex_lock(&core_lock); | ||
683 | class_for_each_device(&i2c_adapter_class, NULL, driver, | 690 | class_for_each_device(&i2c_adapter_class, NULL, driver, |
684 | __attach_adapter); | 691 | __attach_adapter); |
685 | |||
686 | mutex_unlock(&core_lock); | 692 | mutex_unlock(&core_lock); |
693 | |||
687 | return 0; | 694 | return 0; |
688 | } | 695 | } |
689 | EXPORT_SYMBOL(i2c_register_driver); | 696 | EXPORT_SYMBOL(i2c_register_driver); |
@@ -721,14 +728,12 @@ static int __detach_adapter(struct device *dev, void *data) | |||
721 | void i2c_del_driver(struct i2c_driver *driver) | 728 | void i2c_del_driver(struct i2c_driver *driver) |
722 | { | 729 | { |
723 | mutex_lock(&core_lock); | 730 | mutex_lock(&core_lock); |
724 | |||
725 | class_for_each_device(&i2c_adapter_class, NULL, driver, | 731 | class_for_each_device(&i2c_adapter_class, NULL, driver, |
726 | __detach_adapter); | 732 | __detach_adapter); |
733 | mutex_unlock(&core_lock); | ||
727 | 734 | ||
728 | driver_unregister(&driver->driver); | 735 | driver_unregister(&driver->driver); |
729 | pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); | 736 | pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); |
730 | |||
731 | mutex_unlock(&core_lock); | ||
732 | } | 737 | } |
733 | EXPORT_SYMBOL(i2c_del_driver); | 738 | EXPORT_SYMBOL(i2c_del_driver); |
734 | 739 | ||