diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-10-05 00:46:11 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-10-05 01:36:41 -0400 |
commit | f6cd378372bff06093d72f978c0150eeed3ea201 (patch) | |
tree | 352d6d4e720c3e59f47865fb36bb2d78a702d7e6 | |
parent | d2520a426dc3033c00077e923a553fc6c98c7564 (diff) |
Input: wacom - fix runtime PM related deadlock
When runtime PM is enabled by default for input devices, X hangs in
wacom open:
[<ffffffff814a00ea>] mutex_lock+0x1a/0x40
[<ffffffffa02bc94b>] wacom_resume+0x3b/0x90 [wacom]
[<ffffffff81327a32>] usb_resume_interface+0xd2/0x190
[<ffffffff81327b5d>] usb_resume_both+0x6d/0x110
[<ffffffff81327c24>] usb_runtime_resume+0x24/0x40
[<ffffffff8130a2cf>] __pm_runtime_resume+0x26f/0x450
[<ffffffff8130a23a>] __pm_runtime_resume+0x1da/0x450
[<ffffffff8130a53a>] pm_runtime_resume+0x2a/0x50
[<ffffffff81328176>] usb_autopm_get_interface+0x26/0x60
[<ffffffffa02bc626>] wacom_open+0x36/0x90 [wacom]
wacom_open() takes wacom->lock and calls usb_autopm_get_interface(),
which in turn calls wacom_resume() which tries to acquire the lock
again.
The fix is to call usb_autopm_get_interface() first, before we take
the lock.
Since we do not do usb_autopm_put_interface() until wacom_close()
is called runtime PM is effectively disabled for the driver, however
changing it now would risk regressions so the complete fix will
have to wait till the next merge window.
Reported-by: Jiri Slaby <jslaby@suse.cz>
Acked-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/tablet/wacom_sys.c | 23 |
1 files changed, 12 insertions, 11 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 42ba3691d908..b35876ee6908 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
@@ -103,27 +103,26 @@ static void wacom_sys_irq(struct urb *urb) | |||
103 | static int wacom_open(struct input_dev *dev) | 103 | static int wacom_open(struct input_dev *dev) |
104 | { | 104 | { |
105 | struct wacom *wacom = input_get_drvdata(dev); | 105 | struct wacom *wacom = input_get_drvdata(dev); |
106 | int retval = 0; | ||
106 | 107 | ||
107 | mutex_lock(&wacom->lock); | 108 | if (usb_autopm_get_interface(wacom->intf) < 0) |
108 | |||
109 | wacom->irq->dev = wacom->usbdev; | ||
110 | |||
111 | if (usb_autopm_get_interface(wacom->intf) < 0) { | ||
112 | mutex_unlock(&wacom->lock); | ||
113 | return -EIO; | 109 | return -EIO; |
114 | } | 110 | |
111 | mutex_lock(&wacom->lock); | ||
115 | 112 | ||
116 | if (usb_submit_urb(wacom->irq, GFP_KERNEL)) { | 113 | if (usb_submit_urb(wacom->irq, GFP_KERNEL)) { |
117 | usb_autopm_put_interface(wacom->intf); | 114 | retval = -EIO; |
118 | mutex_unlock(&wacom->lock); | 115 | goto out; |
119 | return -EIO; | ||
120 | } | 116 | } |
121 | 117 | ||
122 | wacom->open = true; | 118 | wacom->open = true; |
123 | wacom->intf->needs_remote_wakeup = 1; | 119 | wacom->intf->needs_remote_wakeup = 1; |
124 | 120 | ||
121 | out: | ||
125 | mutex_unlock(&wacom->lock); | 122 | mutex_unlock(&wacom->lock); |
126 | return 0; | 123 | if (retval) |
124 | usb_autopm_put_interface(wacom->intf); | ||
125 | return retval; | ||
127 | } | 126 | } |
128 | 127 | ||
129 | static void wacom_close(struct input_dev *dev) | 128 | static void wacom_close(struct input_dev *dev) |
@@ -135,6 +134,8 @@ static void wacom_close(struct input_dev *dev) | |||
135 | wacom->open = false; | 134 | wacom->open = false; |
136 | wacom->intf->needs_remote_wakeup = 0; | 135 | wacom->intf->needs_remote_wakeup = 0; |
137 | mutex_unlock(&wacom->lock); | 136 | mutex_unlock(&wacom->lock); |
137 | |||
138 | usb_autopm_put_interface(wacom->intf); | ||
138 | } | 139 | } |
139 | 140 | ||
140 | static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, | 141 | static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, |