aboutsummaryrefslogtreecommitdiffstats
path: root/include
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 /include
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 'include')
-rw-r--r--include/linux/usb.h8
1 files changed, 8 insertions, 0 deletions
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 859a88e6ce9..c8e55aa979d 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -120,6 +120,11 @@ enum usb_interface_condition {
120 * to the sysfs representation for that device. 120 * to the sysfs representation for that device.
121 * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not 121 * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
122 * allowed unless the counter is 0. 122 * allowed unless the counter is 0.
123 * @reset_ws: Used for scheduling resets from atomic context.
124 * @reset_running: set to 1 if the interface is currently running a
125 * queued reset so that usb_cancel_queued_reset() doesn't try to
126 * remove from the workqueue when running inside the worker
127 * thread. See __usb_queue_reset_device().
123 * 128 *
124 * USB device drivers attach to interfaces on a physical device. Each 129 * USB device drivers attach to interfaces on a physical device. Each
125 * interface encapsulates a single high level function, such as feeding 130 * interface encapsulates a single high level function, such as feeding
@@ -168,10 +173,12 @@ struct usb_interface {
168 unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ 173 unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
169 unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ 174 unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
170 unsigned needs_binding:1; /* needs delayed unbind/rebind */ 175 unsigned needs_binding:1; /* needs delayed unbind/rebind */
176 unsigned reset_running:1;
171 177
172 struct device dev; /* interface specific device info */ 178 struct device dev; /* interface specific device info */
173 struct device *usb_dev; 179 struct device *usb_dev;
174 int pm_usage_cnt; /* usage counter for autosuspend */ 180 int pm_usage_cnt; /* usage counter for autosuspend */
181 struct work_struct reset_ws; /* for resets in atomic context */
175}; 182};
176#define to_usb_interface(d) container_of(d, struct usb_interface, dev) 183#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
177#define interface_to_usbdev(intf) \ 184#define interface_to_usbdev(intf) \
@@ -507,6 +514,7 @@ extern int usb_lock_device_for_reset(struct usb_device *udev,
507 514
508/* USB port reset for device reinitialization */ 515/* USB port reset for device reinitialization */
509extern int usb_reset_device(struct usb_device *dev); 516extern int usb_reset_device(struct usb_device *dev);
517extern void usb_queue_reset_device(struct usb_interface *dev);
510 518
511extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); 519extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
512 520