aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/driver.c
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2008-11-13 13:31:35 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 12:59:53 -0500
commitdc023dceec861c60bc1d1a17a2c6496ddac26ee7 (patch)
tree908529b3eb975acb2582f679d20a81bfadc95bf4 /drivers/usb/core/driver.c
parent9ac39f28b5237a629e41ccfc1f73d3a55723045c (diff)
USB: Introduce usb_queue_reset() to do resets from atomic contexts
This patch introduces a new call to be able to do a USB reset from an atomic contect. This is quite helpful in USB callbacks to handle errors (when the only thing that can be done is to do a device reset). It is done queuing a work struct that will do the actual reset. The struct is "attached" to an interface so pending requests from an interface are removed when said interface is unbound from the driver. The call flow then becomes: usb_queue_reset_device() __usb_queue_reset_device() [workqueue] usb_reset_device() usb_probe_interface() usb_cancel_queue_reset() [error path] usb_unbind_interface() usb_cancel_queue_reset() usb_driver_release_interface() usb_cancel_queue_reset() Note usb_cancel_queue_reset() needs smarts to try not to unqueue when it is actually being executed. This happens when we run the reset from the workqueue: usb_reset_device() is called and on interface unbind time, usb_cancel_queue_reset() would be called. That would deadlock on cancel_work_sync(). To avoid that, we set (before running usb_reset_device()) usb_intf->reset_running and clear it inmediately after returning. Patch is against 2.6.28-rc2 and depends on http://marc.info/?l=linux-usb&m=122581634925308&w=2 (as submitted by Alan Stern). Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com> Cc: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r--drivers/usb/core/driver.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 23b3c7e79d4..7e26fb3c275 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -184,6 +184,20 @@ static int usb_unbind_device(struct device *dev)
184 return 0; 184 return 0;
185} 185}
186 186
187/*
188 * Cancel any pending scheduled resets
189 *
190 * [see usb_queue_reset_device()]
191 *
192 * Called after unconfiguring / when releasing interfaces. See
193 * comments in __usb_queue_reset_device() regarding
194 * udev->reset_running.
195 */
196static void usb_cancel_queued_reset(struct usb_interface *iface)
197{
198 if (iface->reset_running == 0)
199 cancel_work_sync(&iface->reset_ws);
200}
187 201
188/* called from driver core with dev locked */ 202/* called from driver core with dev locked */
189static int usb_probe_interface(struct device *dev) 203static int usb_probe_interface(struct device *dev)
@@ -242,6 +256,7 @@ static int usb_probe_interface(struct device *dev)
242 mark_quiesced(intf); 256 mark_quiesced(intf);
243 intf->needs_remote_wakeup = 0; 257 intf->needs_remote_wakeup = 0;
244 intf->condition = USB_INTERFACE_UNBOUND; 258 intf->condition = USB_INTERFACE_UNBOUND;
259 usb_cancel_queued_reset(intf);
245 } else 260 } else
246 intf->condition = USB_INTERFACE_BOUND; 261 intf->condition = USB_INTERFACE_BOUND;
247 262
@@ -272,6 +287,7 @@ static int usb_unbind_interface(struct device *dev)
272 usb_disable_interface(udev, intf); 287 usb_disable_interface(udev, intf);
273 288
274 driver->disconnect(intf); 289 driver->disconnect(intf);
290 usb_cancel_queued_reset(intf);
275 291
276 /* Reset other interface state. 292 /* Reset other interface state.
277 * We cannot do a Set-Interface if the device is suspended or 293 * We cannot do a Set-Interface if the device is suspended or
@@ -380,8 +396,10 @@ void usb_driver_release_interface(struct usb_driver *driver,
380 if (device_is_registered(dev)) { 396 if (device_is_registered(dev)) {
381 iface->condition = USB_INTERFACE_UNBINDING; 397 iface->condition = USB_INTERFACE_UNBINDING;
382 device_release_driver(dev); 398 device_release_driver(dev);
399 } else {
400 iface->condition = USB_INTERFACE_UNBOUND;
401 usb_cancel_queued_reset(iface);
383 } 402 }
384
385 dev->driver = NULL; 403 dev->driver = NULL;
386 usb_set_intfdata(iface, NULL); 404 usb_set_intfdata(iface, NULL);
387 405
@@ -942,7 +960,8 @@ static int usb_suspend_interface(struct usb_device *udev,
942 if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf)) 960 if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf))
943 goto done; 961 goto done;
944 962
945 if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */ 963 /* This can happen; see usb_driver_release_interface() */
964 if (intf->condition == USB_INTERFACE_UNBOUND)
946 goto done; 965 goto done;
947 driver = to_usb_driver(intf->dev.driver); 966 driver = to_usb_driver(intf->dev.driver);
948 967