Skip to content

Commit bf6e4ee

Browse files
jwrdegoedevinodkoul
authored andcommitted
phy: ti: tusb1210: Resolve charger-det crash if charger psy is unregistered
The power_supply frame-work is not really designed for there to be long living in kernel references to power_supply devices. Specifically unregistering a power_supply while some other code has a reference to it triggers a WARN in power_supply_unregister(): WARN_ON(atomic_dec_return(&psy->use_cnt)); Folllowed by the power_supply still getting removed and the backing data freed anyway, leaving the tusb1210 charger-detect code with a dangling reference, resulting in a crash the next time tusb1210_get_online() is called. Fix this by only holding the reference in tusb1210_get_online() freeing it at the end of the function. Note this still leaves a theoretical race window, but it avoids the issue when manually rmmod-ing the charger chip driver during development. Fixes: 48969a5 ("phy: ti: tusb1210: Add charger detection") Signed-off-by: Hans de Goede <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 025a6f7 commit bf6e4ee

File tree

1 file changed

+12
-11
lines changed

1 file changed

+12
-11
lines changed

drivers/phy/ti/phy-tusb1210.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ struct tusb1210 {
6969
struct delayed_work chg_det_work;
7070
struct notifier_block psy_nb;
7171
struct power_supply *psy;
72-
struct power_supply *charger;
7372
#endif
7473
};
7574

@@ -236,19 +235,24 @@ static const char * const tusb1210_chargers[] = {
236235

237236
static bool tusb1210_get_online(struct tusb1210 *tusb)
238237
{
238+
struct power_supply *charger = NULL;
239239
union power_supply_propval val;
240-
int i;
240+
bool online = false;
241+
int i, ret;
241242

242-
for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !tusb->charger; i++)
243-
tusb->charger = power_supply_get_by_name(tusb1210_chargers[i]);
243+
for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !charger; i++)
244+
charger = power_supply_get_by_name(tusb1210_chargers[i]);
244245

245-
if (!tusb->charger)
246+
if (!charger)
246247
return false;
247248

248-
if (power_supply_get_property(tusb->charger, POWER_SUPPLY_PROP_ONLINE, &val))
249-
return false;
249+
ret = power_supply_get_property(charger, POWER_SUPPLY_PROP_ONLINE, &val);
250+
if (ret == 0)
251+
online = val.intval;
252+
253+
power_supply_put(charger);
250254

251-
return val.intval;
255+
return online;
252256
}
253257

254258
static void tusb1210_chg_det_work(struct work_struct *work)
@@ -473,9 +477,6 @@ static void tusb1210_remove_charger_detect(struct tusb1210 *tusb)
473477
cancel_delayed_work_sync(&tusb->chg_det_work);
474478
power_supply_unregister(tusb->psy);
475479
}
476-
477-
if (tusb->charger)
478-
power_supply_put(tusb->charger);
479480
}
480481
#else
481482
static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { }

0 commit comments

Comments
 (0)