Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cdc-acm: handle read pipe errors

Read urbs are submitted back only on success, causing read pipe
running out of urbs after few errors. No more characters can
be read from tty device then until it is reopened and no errors
are reported.
Fix that by always submitting urbs back and clearing stall on
-EPIPE.

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
Acked-by: Oliver Neukum <oneukum@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ladislav Michl and committed by
Greg Kroah-Hartman
1aba579f d305394e

+53 -10
+50 -10
drivers/usb/class/cdc-acm.c
··· 429 429 dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n", 430 430 rb->index, urb->actual_length, status); 431 431 432 + set_bit(rb->index, &acm->read_urbs_free); 433 + 432 434 if (!acm->dev) { 433 - set_bit(rb->index, &acm->read_urbs_free); 434 435 dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); 435 436 return; 436 437 } 437 438 438 - if (status) { 439 - set_bit(rb->index, &acm->read_urbs_free); 440 - if ((status != -ENOENT) || (urb->actual_length == 0)) 441 - return; 439 + switch (status) { 440 + case 0: 441 + usb_mark_last_busy(acm->dev); 442 + acm_process_read_urb(acm, urb); 443 + break; 444 + case -EPIPE: 445 + set_bit(EVENT_RX_STALL, &acm->flags); 446 + schedule_work(&acm->work); 447 + return; 448 + case -ENOENT: 449 + case -ECONNRESET: 450 + case -ESHUTDOWN: 451 + dev_dbg(&acm->data->dev, 452 + "%s - urb shutting down with status: %d\n", 453 + __func__, status); 454 + return; 455 + default: 456 + dev_dbg(&acm->data->dev, 457 + "%s - nonzero urb status received: %d\n", 458 + __func__, status); 459 + break; 442 460 } 443 461 444 - usb_mark_last_busy(acm->dev); 445 - 446 - acm_process_read_urb(acm, urb); 447 462 /* 448 463 * Unthrottle may run on another CPU which needs to see events 449 464 * in the same order. Submission has an implict barrier 450 465 */ 451 466 smp_mb__before_atomic(); 452 - set_bit(rb->index, &acm->read_urbs_free); 453 467 454 468 /* throttle device if requested by tty */ 455 469 spin_lock_irqsave(&acm->read_lock, flags); ··· 493 479 spin_lock_irqsave(&acm->write_lock, flags); 494 480 acm_write_done(acm, wb); 495 481 spin_unlock_irqrestore(&acm->write_lock, flags); 482 + set_bit(EVENT_TTY_WAKEUP, &acm->flags); 496 483 schedule_work(&acm->work); 497 484 } 498 485 499 486 static void acm_softint(struct work_struct *work) 500 487 { 488 + int i; 501 489 struct acm *acm = container_of(work, struct acm, work); 502 490 503 - tty_port_tty_wakeup(&acm->port); 491 + if (test_bit(EVENT_RX_STALL, &acm->flags)) { 492 + if (!(usb_autopm_get_interface(acm->data))) { 493 + for (i = 0; i < acm->rx_buflimit; i++) 494 + usb_kill_urb(acm->read_urbs[i]); 495 + usb_clear_halt(acm->dev, acm->in); 496 + acm_submit_read_urbs(acm, GFP_KERNEL); 497 + usb_autopm_put_interface(acm->data); 498 + } 499 + clear_bit(EVENT_RX_STALL, &acm->flags); 500 + } 501 + 502 + if (test_bit(EVENT_TTY_WAKEUP, &acm->flags)) { 503 + tty_port_tty_wakeup(&acm->port); 504 + clear_bit(EVENT_TTY_WAKEUP, &acm->flags); 505 + } 504 506 } 505 507 506 508 /* ··· 1661 1631 1662 1632 #endif /* CONFIG_PM */ 1663 1633 1634 + static int acm_pre_reset(struct usb_interface *intf) 1635 + { 1636 + struct acm *acm = usb_get_intfdata(intf); 1637 + 1638 + clear_bit(EVENT_RX_STALL, &acm->flags); 1639 + 1640 + return 0; 1641 + } 1642 + 1664 1643 #define NOKIA_PCSUITE_ACM_INFO(x) \ 1665 1644 USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \ 1666 1645 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ ··· 1911 1872 .resume = acm_resume, 1912 1873 .reset_resume = acm_reset_resume, 1913 1874 #endif 1875 + .pre_reset = acm_pre_reset, 1914 1876 .id_table = acm_ids, 1915 1877 #ifdef CONFIG_PM 1916 1878 .supports_autosuspend = 1,
+3
drivers/usb/class/cdc-acm.h
··· 103 103 spinlock_t write_lock; 104 104 struct mutex mutex; 105 105 bool disconnected; 106 + unsigned long flags; 107 + # define EVENT_TTY_WAKEUP 0 108 + # define EVENT_RX_STALL 1 106 109 struct usb_cdc_line_coding line; /* bits, stop, parity */ 107 110 struct work_struct work; /* work queue entry for line discipline waking up */ 108 111 unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */