Skip to content

Commit 38203b8

Browse files
jbrun3tgregkh
authored andcommitted
usb: cdc-acm: fix cooldown mechanism
Commit a4e7279 ("cdc-acm: introduce a cool down") is causing regression if there is some USB error, such as -EPROTO. This has been reported on some samples of the Odroid-N2 using the Combee II Zibgee USB dongle. > struct acm *acm = container_of(work, struct acm, work) is incorrect in case of a delayed work and causes warnings, usually from the workqueue: > WARNING: CPU: 0 PID: 0 at kernel/workqueue.c:1474 __queue_work+0x480/0x528. When this happens, USB eventually stops working completely after a while. Also the ACM_ERROR_DELAY bit is never set, so the cooldown mechanism previously introduced cannot be triggered and acm_submit_read_urb() is never called. This changes makes the cdc-acm driver use a single delayed work, fixing the pointer arithmetic in acm_softint() and set the ACM_ERROR_DELAY when the cooldown mechanism appear to be needed. Fixes: a4e7279 ("cdc-acm: introduce a cool down") Cc: Oliver Neukum <oneukum@suse.com> Reported-by: Pascal Vizeli <pascal.vizeli@nabucasa.com> Acked-by: Oliver Neukum <oneukum@suse.com> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com> Link: https://lore.kernel.org/r/20201019170702.150534-1-jbrunet@baylibre.com Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 3cd54a6 commit 38203b8

2 files changed

Lines changed: 6 additions & 9 deletions

File tree

drivers/usb/class/cdc-acm.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ static void acm_read_bulk_callback(struct urb *urb)
508508
"%s - cooling babbling device\n", __func__);
509509
usb_mark_last_busy(acm->dev);
510510
set_bit(rb->index, &acm->urbs_in_error_delay);
511+
set_bit(ACM_ERROR_DELAY, &acm->flags);
511512
cooldown = true;
512513
break;
513514
default:
@@ -533,7 +534,7 @@ static void acm_read_bulk_callback(struct urb *urb)
533534

534535
if (stopped || stalled || cooldown) {
535536
if (stalled)
536-
schedule_work(&acm->work);
537+
schedule_delayed_work(&acm->dwork, 0);
537538
else if (cooldown)
538539
schedule_delayed_work(&acm->dwork, HZ / 2);
539540
return;
@@ -563,13 +564,13 @@ static void acm_write_bulk(struct urb *urb)
563564
acm_write_done(acm, wb);
564565
spin_unlock_irqrestore(&acm->write_lock, flags);
565566
set_bit(EVENT_TTY_WAKEUP, &acm->flags);
566-
schedule_work(&acm->work);
567+
schedule_delayed_work(&acm->dwork, 0);
567568
}
568569

569570
static void acm_softint(struct work_struct *work)
570571
{
571572
int i;
572-
struct acm *acm = container_of(work, struct acm, work);
573+
struct acm *acm = container_of(work, struct acm, dwork.work);
573574

574575
if (test_bit(EVENT_RX_STALL, &acm->flags)) {
575576
smp_mb(); /* against acm_suspend() */
@@ -585,7 +586,7 @@ static void acm_softint(struct work_struct *work)
585586
if (test_and_clear_bit(ACM_ERROR_DELAY, &acm->flags)) {
586587
for (i = 0; i < acm->rx_buflimit; i++)
587588
if (test_and_clear_bit(i, &acm->urbs_in_error_delay))
588-
acm_submit_read_urb(acm, i, GFP_NOIO);
589+
acm_submit_read_urb(acm, i, GFP_KERNEL);
589590
}
590591

591592
if (test_and_clear_bit(EVENT_TTY_WAKEUP, &acm->flags))
@@ -1351,7 +1352,6 @@ static int acm_probe(struct usb_interface *intf,
13511352
acm->ctrlsize = ctrlsize;
13521353
acm->readsize = readsize;
13531354
acm->rx_buflimit = num_rx_buf;
1354-
INIT_WORK(&acm->work, acm_softint);
13551355
INIT_DELAYED_WORK(&acm->dwork, acm_softint);
13561356
init_waitqueue_head(&acm->wioctl);
13571357
spin_lock_init(&acm->write_lock);
@@ -1561,7 +1561,6 @@ static void acm_disconnect(struct usb_interface *intf)
15611561
}
15621562

15631563
acm_kill_urbs(acm);
1564-
cancel_work_sync(&acm->work);
15651564
cancel_delayed_work_sync(&acm->dwork);
15661565

15671566
tty_unregister_device(acm_tty_driver, acm->minor);
@@ -1604,7 +1603,6 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
16041603
return 0;
16051604

16061605
acm_kill_urbs(acm);
1607-
cancel_work_sync(&acm->work);
16081606
cancel_delayed_work_sync(&acm->dwork);
16091607
acm->urbs_in_error_delay = 0;
16101608

drivers/usb/class/cdc-acm.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ struct acm {
112112
# define ACM_ERROR_DELAY 3
113113
unsigned long urbs_in_error_delay; /* these need to be restarted after a delay */
114114
struct usb_cdc_line_coding line; /* bits, stop, parity */
115-
struct work_struct work; /* work queue entry for various purposes*/
116-
struct delayed_work dwork; /* for cool downs needed in error recovery */
115+
struct delayed_work dwork; /* work queue entry for various purposes */
117116
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
118117
unsigned int ctrlout; /* output control lines (DTR, RTS) */
119118
struct async_icount iocount; /* counters for control line changes */

0 commit comments

Comments
 (0)