aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoger Quadros2018-03-02 03:24:47 -0600
committerJean-Jacques Hiblot2018-03-05 03:48:11 -0600
commitf0968ac62d71fda8d7cb3c5f68a339990cdd6346 (patch)
treee4c3a9e17f2b9a8e201d9bba702105811f166e35
parent88530b8d5c2989bec3c281e70a64e3fd838cfeb1 (diff)
downloadkernel-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.c57
-rw-r--r--drivers/usb/core/hcd.c7
-rw-r--r--include/linux/usb/otg.h6
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)
1114EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd); 1114EXPORT_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 */
1127int 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}
1171EXPORT_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}
3058EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); 3061EXPORT_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);
164int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum, 164int 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);
166int usb_otg_unregister_hcd(struct usb_hcd *hcd); 166int usb_otg_unregister_hcd(struct usb_hcd *hcd);
167int usb_otg_shutdown_hcd(struct usb_hcd *hcd);
167int usb_otg_register_gadget(struct usb_gadget *gadget, 168int usb_otg_register_gadget(struct usb_gadget *gadget,
168 struct otg_gadget_ops *ops); 169 struct otg_gadget_ops *ops);
169int usb_otg_unregister_gadget(struct usb_gadget *gadget); 170int 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
202static inline int usb_otg_shutdown_hcd(struct usb_hcd *hcd)
203{
204 return -ENOTSUPP;
205}
206
201static inline int usb_otg_register_gadget(struct usb_gadget *gadget, 207static inline int usb_otg_register_gadget(struct usb_gadget *gadget,
202 struct otg_gadget_ops *ops) 208 struct otg_gadget_ops *ops)
203{ 209{