aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2012-12-21 20:56:51 -0500
committerAnton Vorontsov <anton.vorontsov@linaro.org>2013-01-05 17:03:26 -0500
commit2fbb520d2079186727786b728ebc5bf20fc85520 (patch)
treec7367c9e969e7d1e38037b58217dc4c7a71536d5 /drivers
parent41468a11199212f092cb4c071626785db6a32393 (diff)
charger_manager: Don't use [delayed_]work_pending()
There's no need to test whether a (delayed) work item in pending before queueing, flushing or cancelling it. Most uses are unnecessary and quite a few of them are buggy. Remove unnecessary pending tests and rewrite _setup_polling() so that it uses mod_delayed_work() if the next polling interval is sooner than currently scheduled. queue_delayed_work() is used otherwise. Only compile tested. I noticed that two work items - setup_polling and cm_monitor_work - schedule each other. It's a very unusual construct and I'm fairly sure it's racy. You can't break such circular dependency by calling cancel on each. I strongly recommend revising the mechanism. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Anton Vorontsov <cbou@mail.ru> Cc: David Woodhouse <dwmw2@infradead.org> Cc: Donggeun Kim <dg77.kim@samsung.com> Cc: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/power/charger-manager.c31
1 files changed, 16 insertions, 15 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 029732d83090..8acc3f8d303c 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -669,15 +669,21 @@ static void _setup_polling(struct work_struct *work)
669 WARN(cm_wq == NULL, "charger-manager: workqueue not initialized" 669 WARN(cm_wq == NULL, "charger-manager: workqueue not initialized"
670 ". try it later. %s\n", __func__); 670 ". try it later. %s\n", __func__);
671 671
672 /*
673 * Use mod_delayed_work() iff the next polling interval should
674 * occur before the currently scheduled one. If @cm_monitor_work
675 * isn't active, the end result is the same, so no need to worry
676 * about stale @next_polling.
677 */
672 _next_polling = jiffies + polling_jiffy; 678 _next_polling = jiffies + polling_jiffy;
673 679
674 if (!delayed_work_pending(&cm_monitor_work) || 680 if (time_before(_next_polling, next_polling)) {
675 (delayed_work_pending(&cm_monitor_work) &&
676 time_after(next_polling, _next_polling))) {
677 next_polling = jiffies + polling_jiffy;
678 mod_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy); 681 mod_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy);
682 next_polling = _next_polling;
683 } else {
684 if (queue_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy))
685 next_polling = _next_polling;
679 } 686 }
680
681out: 687out:
682 mutex_unlock(&cm_list_mtx); 688 mutex_unlock(&cm_list_mtx);
683} 689}
@@ -751,8 +757,7 @@ static void misc_event_handler(struct charger_manager *cm,
751 if (cm_suspended) 757 if (cm_suspended)
752 device_set_wakeup_capable(cm->dev, true); 758 device_set_wakeup_capable(cm->dev, true);
753 759
754 if (!delayed_work_pending(&cm_monitor_work) && 760 if (is_polling_required(cm) && cm->desc->polling_interval_ms)
755 is_polling_required(cm) && cm->desc->polling_interval_ms)
756 schedule_work(&setup_polling); 761 schedule_work(&setup_polling);
757 uevent_notify(cm, default_event_names[type]); 762 uevent_notify(cm, default_event_names[type]);
758} 763}
@@ -1170,8 +1175,7 @@ static int charger_extcon_notifier(struct notifier_block *self,
1170 * when charger cable is attached. 1175 * when charger cable is attached.
1171 */ 1176 */
1172 if (cable->attached && is_polling_required(cable->cm)) { 1177 if (cable->attached && is_polling_required(cable->cm)) {
1173 if (work_pending(&setup_polling)) 1178 cancel_work_sync(&setup_polling);
1174 cancel_work_sync(&setup_polling);
1175 schedule_work(&setup_polling); 1179 schedule_work(&setup_polling);
1176 } 1180 }
1177 1181
@@ -1718,10 +1722,8 @@ static int charger_manager_remove(struct platform_device *pdev)
1718 list_del(&cm->entry); 1722 list_del(&cm->entry);
1719 mutex_unlock(&cm_list_mtx); 1723 mutex_unlock(&cm_list_mtx);
1720 1724
1721 if (work_pending(&setup_polling)) 1725 cancel_work_sync(&setup_polling);
1722 cancel_work_sync(&setup_polling); 1726 cancel_delayed_work_sync(&cm_monitor_work);
1723 if (delayed_work_pending(&cm_monitor_work))
1724 cancel_delayed_work_sync(&cm_monitor_work);
1725 1727
1726 for (i = 0 ; i < desc->num_charger_regulators ; i++) { 1728 for (i = 0 ; i < desc->num_charger_regulators ; i++) {
1727 struct charger_regulator *charger 1729 struct charger_regulator *charger
@@ -1790,8 +1792,7 @@ static int cm_suspend_prepare(struct device *dev)
1790 cm_suspended = true; 1792 cm_suspended = true;
1791 } 1793 }
1792 1794
1793 if (delayed_work_pending(&cm->fullbatt_vchk_work)) 1795 cancel_delayed_work(&cm->fullbatt_vchk_work);
1794 cancel_delayed_work(&cm->fullbatt_vchk_work);
1795 cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm); 1796 cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm);
1796 cm->status_save_batt = is_batt_present(cm); 1797 cm->status_save_batt = is_batt_present(cm);
1797 1798