diff options
author | Roger Quadros | 2018-03-02 03:24:47 -0600 |
---|---|---|
committer | Jean-Jacques Hiblot | 2018-03-05 03:48:11 -0600 |
commit | f0968ac62d71fda8d7cb3c5f68a339990cdd6346 (patch) | |
tree | e4c3a9e17f2b9a8e201d9bba702105811f166e35 | |
parent | 88530b8d5c2989bec3c281e70a64e3fd838cfeb1 (diff) | |
download | kernel-omap-f0968ac62d71fda8d7cb3c5f68a339990cdd6346.tar.gz kernel-omap-f0968ac62d71fda8d7cb3c5f68a339990cdd6346.tar.xz kernel-omap-f0968ac62d71fda8d7cb3c5f68a339990cdd6346.zip |
usb: otg: Fix crash on shutdown
Since the stable backported
commit ff1ddbb38b19 ("xhci: plat: Register shutdown for xhci_plat")
we get a NULL pointer dereference on shutdown/reboot if
dual-role USB port was in device mode.
Fix this by introducing usb_otg_shutdown_hcd() which will take
care of shutting down HCD if it was running.
Fixes: 1c889f0009df ("usb: hcd: Adapt to OTG core").
Signed-off-by: Roger Quadros <rogerq@ti.com>
-rw-r--r-- | drivers/usb/common/usb-otg.c | 57 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 7 | ||||
-rw-r--r-- | include/linux/usb/otg.h | 6 |
3 files changed, 68 insertions, 2 deletions
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c index 8d2b97b9d58c..c0f06ddacb39 100644 --- a/drivers/usb/common/usb-otg.c +++ b/drivers/usb/common/usb-otg.c | |||
@@ -1114,6 +1114,63 @@ int usb_otg_unregister_hcd(struct usb_hcd *hcd) | |||
1114 | EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd); | 1114 | EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd); |
1115 | 1115 | ||
1116 | /** | 1116 | /** |
1117 | * usb_otg_shutdown_hcd - Shutdown Host controller from OTG core | ||
1118 | * @hcd: Host controller device | ||
1119 | * | ||
1120 | * This is used by the USB Host stack to shutdown the Host controller. | ||
1121 | * This functon will call hcd->driver->shutdown() only if the | ||
1122 | * Host controller was running. It will also stop the OTG FSM to prevent | ||
1123 | * further OTG state changes. | ||
1124 | * | ||
1125 | * Returns: 0 on success, error value otherwise. | ||
1126 | */ | ||
1127 | int usb_otg_shutdown_hcd(struct usb_hcd *hcd) | ||
1128 | { | ||
1129 | struct usb_otg *otgd; | ||
1130 | struct device *hcd_dev = hcd_to_bus(hcd)->controller; | ||
1131 | struct device *otg_dev = usb_otg_get_device(hcd_dev); | ||
1132 | |||
1133 | if (!otg_dev) | ||
1134 | return -EINVAL; /* we're definitely not OTG */ | ||
1135 | |||
1136 | mutex_lock(&otg_list_mutex); | ||
1137 | otgd = usb_otg_get_data(otg_dev); | ||
1138 | mutex_unlock(&otg_list_mutex); | ||
1139 | if (!otgd) { | ||
1140 | dev_dbg(hcd_dev, "otg: host wasn't registered with otg\n"); | ||
1141 | return -EINVAL; | ||
1142 | } | ||
1143 | |||
1144 | mutex_lock(&otgd->fsm.lock); | ||
1145 | |||
1146 | if (otgd->fsm_running) { | ||
1147 | int i; | ||
1148 | |||
1149 | /* no more new events queued */ | ||
1150 | otgd->fsm_running = false; | ||
1151 | |||
1152 | /* Stop state machine / timers */ | ||
1153 | if (!otgd->drd_only) { | ||
1154 | for (i = 0; i < ARRAY_SIZE(otgd->timers); i++) | ||
1155 | hrtimer_cancel(&otgd->timers[i].timer); | ||
1156 | } | ||
1157 | |||
1158 | flush_workqueue(otgd->wq); | ||
1159 | } | ||
1160 | |||
1161 | /* shutdown host controller if it was running */ | ||
1162 | if (otgd->flags & OTG_FLAG_HOST_RUNNING) { | ||
1163 | if (hcd->driver->shutdown) | ||
1164 | hcd->driver->shutdown(hcd); | ||
1165 | } | ||
1166 | |||
1167 | mutex_unlock(&otgd->fsm.lock); | ||
1168 | |||
1169 | return 0; | ||
1170 | } | ||
1171 | EXPORT_SYMBOL_GPL(usb_otg_shutdown_hcd); | ||
1172 | |||
1173 | /** | ||
1117 | * usb_otg_register_gadget - Register Gadget controller to OTG core | 1174 | * usb_otg_register_gadget - Register Gadget controller to OTG core |
1118 | * @gadget: Gadget controller | 1175 | * @gadget: Gadget controller |
1119 | * | 1176 | * |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 3856ba4518da..24b084748b63 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -3052,8 +3052,11 @@ usb_hcd_platform_shutdown(struct platform_device *dev) | |||
3052 | { | 3052 | { |
3053 | struct usb_hcd *hcd = platform_get_drvdata(dev); | 3053 | struct usb_hcd *hcd = platform_get_drvdata(dev); |
3054 | 3054 | ||
3055 | if (hcd->driver->shutdown) | 3055 | /* If OTG device, OTG core takes care of shutting down HCD */ |
3056 | hcd->driver->shutdown(hcd); | 3056 | if (usb_otg_shutdown_hcd(hcd)) { |
3057 | if (hcd->driver->shutdown) | ||
3058 | hcd->driver->shutdown(hcd); | ||
3059 | } | ||
3057 | } | 3060 | } |
3058 | EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); | 3061 | EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); |
3059 | 3062 | ||
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 8bb60e38b8a3..8d3934a42654 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h | |||
@@ -164,6 +164,7 @@ int usb_otg_unregister(struct device *dev); | |||
164 | int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum, | 164 | int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum, |
165 | unsigned long irqflags, struct otg_hcd_ops *ops); | 165 | unsigned long irqflags, struct otg_hcd_ops *ops); |
166 | int usb_otg_unregister_hcd(struct usb_hcd *hcd); | 166 | int usb_otg_unregister_hcd(struct usb_hcd *hcd); |
167 | int usb_otg_shutdown_hcd(struct usb_hcd *hcd); | ||
167 | int usb_otg_register_gadget(struct usb_gadget *gadget, | 168 | int usb_otg_register_gadget(struct usb_gadget *gadget, |
168 | struct otg_gadget_ops *ops); | 169 | struct otg_gadget_ops *ops); |
169 | int usb_otg_unregister_gadget(struct usb_gadget *gadget); | 170 | int usb_otg_unregister_gadget(struct usb_gadget *gadget); |
@@ -198,6 +199,11 @@ static inline int usb_otg_unregister_hcd(struct usb_hcd *hcd) | |||
198 | return -ENOTSUPP; | 199 | return -ENOTSUPP; |
199 | } | 200 | } |
200 | 201 | ||
202 | static inline int usb_otg_shutdown_hcd(struct usb_hcd *hcd) | ||
203 | { | ||
204 | return -ENOTSUPP; | ||
205 | } | ||
206 | |||
201 | static inline int usb_otg_register_gadget(struct usb_gadget *gadget, | 207 | static inline int usb_otg_register_gadget(struct usb_gadget *gadget, |
202 | struct otg_gadget_ops *ops) | 208 | struct otg_gadget_ops *ops) |
203 | { | 209 | { |