diff options
-rw-r--r-- | drivers/power/power_supply_core.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index bcff7fdf733a..26518c8218ea 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c | |||
@@ -78,7 +78,14 @@ static void power_supply_changed_work(struct work_struct *work) | |||
78 | dev_dbg(psy->dev, "%s\n", __func__); | 78 | dev_dbg(psy->dev, "%s\n", __func__); |
79 | 79 | ||
80 | spin_lock_irqsave(&psy->changed_lock, flags); | 80 | spin_lock_irqsave(&psy->changed_lock, flags); |
81 | if (psy->changed) { | 81 | /* |
82 | * Check 'changed' here to avoid issues due to race between | ||
83 | * power_supply_changed() and this routine. In worst case | ||
84 | * power_supply_changed() can be called again just before we take above | ||
85 | * lock. During the first call of this routine we will mark 'changed' as | ||
86 | * false and it will stay false for the next call as well. | ||
87 | */ | ||
88 | if (likely(psy->changed)) { | ||
82 | psy->changed = false; | 89 | psy->changed = false; |
83 | spin_unlock_irqrestore(&psy->changed_lock, flags); | 90 | spin_unlock_irqrestore(&psy->changed_lock, flags); |
84 | class_for_each_device(power_supply_class, NULL, psy, | 91 | class_for_each_device(power_supply_class, NULL, psy, |
@@ -89,12 +96,13 @@ static void power_supply_changed_work(struct work_struct *work) | |||
89 | kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); | 96 | kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); |
90 | spin_lock_irqsave(&psy->changed_lock, flags); | 97 | spin_lock_irqsave(&psy->changed_lock, flags); |
91 | } | 98 | } |
99 | |||
92 | /* | 100 | /* |
93 | * Dependent power supplies (e.g. battery) may have changed state | 101 | * Hold the wakeup_source until all events are processed. |
94 | * as a result of this event, so poll again and hold the | 102 | * power_supply_changed() might have called again and have set 'changed' |
95 | * wakeup_source until all events are processed. | 103 | * to true. |
96 | */ | 104 | */ |
97 | if (!psy->changed) | 105 | if (likely(!psy->changed)) |
98 | pm_relax(psy->dev); | 106 | pm_relax(psy->dev); |
99 | spin_unlock_irqrestore(&psy->changed_lock, flags); | 107 | spin_unlock_irqrestore(&psy->changed_lock, flags); |
100 | } | 108 | } |