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 | |
| 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>
| -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 b1fd00d9a5c7..a2f1cd3766f3 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 | ||
