I tracked down this issue. Using usbmon, the control and interrupt transfers would go on for days without problem, but once and a while, d1c301e0 2316273046 S Ci:1:002:0 s a1 01 0314 0000 0003 8 < de7cfde0 2334333394 C Ii:1:002:1 0:64 6 = 0c640000 3c00 de7cfde0 2334333468 S Ii:1:002:1 -115:64 6 < de7cfde0 2337308683 C Ii:1:002:1 0:64 4 = 06000008
there would be a control transfer submitted followed by only interrupt transfers. The control transfer would not complete and the usbhid queue would built up until it was full and "generic-usb 0003:051D:0002.0001: control queue full" would be printed from then on. The following patch has been merged into the git kernel tree after 2.6.33, and will be in 2.6.34. I verified it fixes this bug on my system. Note the 10 second delay and error -104 in one request. c2fede40 161671434 S Ci:1:002:0 s a1 01 0326 0000 0004 8 < c2fede40 161747009 C Ci:1:002:0 0 4 = 26343130 c2fede40 161847590 S Ci:1:002:0 s a1 01 0314 0000 0003 8 < c2fede40 161848982 C Ci:1:002:0 0 3 = 140000 c2fede40 161908315 S Ci:1:002:0 s a1 01 0314 0000 0003 8 < c2fede40 171928585 C Ci:1:002:0 -104 3 = 140000 c2fede40 171928605 S Ci:1:002:0 s a1 01 0306 0000 0004 8 < c2fede40 171930579 C Ci:1:002:0 0 4 = 06000008 c2fede40 171968852 S Ci:1:002:0 s a1 01 030c 0000 0006 8 < c2fede40 171970572 C Ci:1:002:0 0 6 = 0c640000 3f00 c2fede40 171989721 S Ci:1:002:0 s a1 01 030c 0000 0006 8 < c2fede40 171991562 C Ci:1:002:0 0 6 = 0c640000 3f00 -- David Fries <[email protected]> http://fries.net/~david/ (PGP encryption key available) commit 858155fbcc0cd713f6382c527bb1c3abc0ed6d00 Author: Oliver Neukum <[email protected]> Date: Fri Feb 12 13:02:28 2010 +0100 HID: usbhid: introduce timeout for stuck ctrl/out URBs Some devices do not react to a control request (seen on APC UPS's) resulting in a slow stream of messages, "generic-usb ... control queue full". Therefore request needs a timeout. Cc: [email protected] Signed-off-by: Oliver Neukum <[email protected]> Signed-off-by: David Fries <[email protected]> Signed-off-by: Jiri Kosina <[email protected]> diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 5406074..74bd3ca 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -316,6 +316,7 @@ static int hid_submit_out(struct hid_device *hid) err_hid("usb_submit_urb(out) failed"); return -1; } + usbhid->last_out = jiffies; } else { /* * queue work to wake up the device. @@ -377,6 +378,7 @@ static int hid_submit_ctrl(struct hid_device *hid) err_hid("usb_submit_urb(ctrl) failed"); return -1; } + usbhid->last_ctrl = jiffies; } else { /* * queue work to wake up the device. @@ -512,9 +514,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re usbhid->out[usbhid->outhead].report = report; usbhid->outhead = head; - if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) + if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) { if (hid_submit_out(hid)) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); + } else { + /* + * the queue is known to run + * but an earlier request may be stuck + * we may need to time out + * no race because this is called under + * spinlock + */ + if (time_after(jiffies, usbhid->last_out + HZ * 5)) + usb_unlink_urb(usbhid->urbout); + } return; } @@ -535,9 +548,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re usbhid->ctrl[usbhid->ctrlhead].dir = dir; usbhid->ctrlhead = head; - if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) { if (hid_submit_ctrl(hid)) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); + } else { + /* + * the queue is known to run + * but an earlier request may be stuck + * we may need to time out + * no race because this is called under + * spinlock + */ + if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) + usb_unlink_urb(usbhid->urbctrl); + } } void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 08f505c..ec20400 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -80,12 +80,14 @@ struct usbhid_device { unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ char *ctrlbuf; /* Control buffer */ dma_addr_t ctrlbuf_dma; /* Control buffer dma */ + unsigned long last_ctrl; /* record of last output for timeouts */ struct urb *urbout; /* Output URB */ struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ unsigned char outhead, outtail; /* Output pipe fifo head & tail */ char *outbuf; /* Output buffer */ dma_addr_t outbuf_dma; /* Output buffer dma */ + unsigned long last_out; /* record of last output for timeouts */ spinlock_t lock; /* fifo spinlock */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ -- To UNSUBSCRIBE, email to [email protected] with a subject of "unsubscribe". Trouble? Contact [email protected]

