From 7aedfdd8f2dd282976faa9c98f473f056851fb85 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Fri, 16 Dec 2016 17:16:32 -0800 Subject: usb: pd: Register power_supply notifier after completing init There is a rare but possible chance that just after registering the psy_changed notifier callback with the power_supply framework that it could be called immediately, schedule the usbpd_sm, and execute the worker on another thread, all before usbpd_create() has completed. Since some structures, notably pd->rx_lock, haven't been fully initialized yet, this leads to spin_lock() call accessing uninitialized data. Fix this by moving the power_supply_reg_notifier() call to the very end of usbpd_create() after everything has been initialized. Change-Id: I7d2bc9eca8e7e30dbc656be620a0f4fd8eea2239 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 2fbe4c8faa79..dfc63b47ae81 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -2974,11 +2974,6 @@ struct usbpd *usbpd_create(struct device *parent) goto destroy_wq; } - pd->psy_nb.notifier_call = psy_changed; - ret = power_supply_reg_notifier(&pd->psy_nb); - if (ret) - goto put_psy; - /* * associate extcon with the parent dev as it could have a DT * node which will be useful for extcon_get_edev_by_phandle() @@ -2987,26 +2982,26 @@ struct usbpd *usbpd_create(struct device *parent) if (IS_ERR(pd->extcon)) { usbpd_err(&pd->dev, "failed to allocate extcon device\n"); ret = PTR_ERR(pd->extcon); - goto unreg_psy; + goto put_psy; } pd->extcon->mutually_exclusive = usbpd_extcon_exclusive; ret = devm_extcon_dev_register(parent, pd->extcon); if (ret) { usbpd_err(&pd->dev, "failed to register extcon device\n"); - goto unreg_psy; + goto put_psy; } pd->vbus = devm_regulator_get(parent, "vbus"); if (IS_ERR(pd->vbus)) { ret = PTR_ERR(pd->vbus); - goto unreg_psy; + goto put_psy; } pd->vconn = devm_regulator_get(parent, "vconn"); if (IS_ERR(pd->vconn)) { ret = PTR_ERR(pd->vconn); - goto unreg_psy; + goto put_psy; } pd->vconn_is_external = device_property_present(parent, @@ -3031,7 +3026,7 @@ struct usbpd *usbpd_create(struct device *parent) &pd->dr_desc); if (IS_ERR(pd->dual_role)) { usbpd_err(&pd->dev, "could not register dual_role instance\n"); - goto unreg_psy; + goto put_psy; } else { pd->dual_role->drv_data = pd; } @@ -3045,13 +3040,18 @@ struct usbpd *usbpd_create(struct device *parent) INIT_LIST_HEAD(&pd->svid_handlers); init_completion(&pd->swap_complete); + pd->psy_nb.notifier_call = psy_changed; + ret = power_supply_reg_notifier(&pd->psy_nb); + if (ret) + goto del_inst; + /* force read initial power_supply values */ psy_changed(&pd->psy_nb, PSY_EVENT_PROP_CHANGED, pd->usb_psy); return pd; -unreg_psy: - power_supply_unreg_notifier(&pd->psy_nb); +del_inst: + list_del(&pd->instance); put_psy: power_supply_put(pd->usb_psy); destroy_wq: -- cgit v1.2.3