diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-04-26 11:22:01 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-04-26 11:22:01 -0700 | 
| commit | e9a61afb69f07b1c5880984d45e5cc232ec1bf6f (patch) | |
| tree | 7b2369783e231cf6d2d301a66ff389f9d86ef12d /drivers/usb/class/cdc-acm.c | |
| parent | c5f33785719596047b0bb9df98d39fab9d1c51da (diff) | |
| parent | 2df7405f79ce1674d73c2786fe1a8727c905d65b (diff) | |
Merge tag 'usb-5.7-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB fixes from Greg KH:
 "Here are a number of USB driver fixes for 5.7-rc3.
  Nothing huge, just the usual collection of:
   - xhci fixes
   - gadget driver fixes
   - syzkaller fuzzing fixes
   - new device ids and DT bindings
   - new quirks added for broken devices
  A few of the gadget driver fixes show up twice here as they were
  applied to my branch, and also by Felipe to his branch which I then
  pulled in as we got out of sync a bit.
  All of these have been in linux-next with no reported issues"
* tag 'usb-5.7-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (33 commits)
  USB: sisusbvga: Change port variable from signed to unsigned
  usb-storage: Add unusual_devs entry for JMicron JMS566
  USB: hub: Revert commit bd0e6c9614b9 ("usb: hub: try old enumeration scheme first for high speed devices")
  USB: hub: Fix handling of connect changes during sleep
  usb: typec: altmode: Fix typec_altmode_get_partner sometimes returning an invalid pointer
  xhci: Don't clear hub TT buffer on ep0 protocol stall
  xhci: prevent bus suspend if a roothub port detected a over-current condition
  xhci: Fix handling halted endpoint even if endpoint ring appears empty
  usb: raw-gadget: Fix copy_to/from_user() checks
  usb: raw-gadget: fix raw_event_queue_fetch locking
  usb: gadget: udc: atmel: Fix vbus disconnect handling
  usb: dwc3: gadget: Fix request completion check
  USB: Add USB_QUIRK_DELAY_CTRL_MSG and USB_QUIRK_DELAY_INIT for Corsair K70 RGB RAPIDFIRE
  phy: tegra: Select USB_COMMON for usb_get_maximum_speed()
  usb: typec: tcpm: Ignore CC and vbus changes in PORT_RESET change
  usb: f_fs: Clear OS Extended descriptor counts to zero in ffs_data_reset()
  cdc-acm: introduce a cool down
  cdc-acm: close race betrween suspend() and acm_softint
  UAS: fix deadlock in error handling and PM flushing work
  UAS: no use logging any details in case of ENODEV
  ...
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 36 | 
1 files changed, 31 insertions, 5 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 84d6f7df09a4..ded8d93834ca 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -412,9 +412,12 @@ static void acm_ctrl_irq(struct urb *urb)  exit:  	retval = usb_submit_urb(urb, GFP_ATOMIC); -	if (retval && retval != -EPERM) +	if (retval && retval != -EPERM && retval != -ENODEV)  		dev_err(&acm->control->dev,  			"%s - usb_submit_urb failed: %d\n", __func__, retval); +	else +		dev_vdbg(&acm->control->dev, +			"control resubmission terminated %d\n", retval);  }  static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) @@ -430,6 +433,8 @@ static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)  			dev_err(&acm->data->dev,  				"urb %d failed submission with %d\n",  				index, res); +		} else { +			dev_vdbg(&acm->data->dev, "intended failure %d\n", res);  		}  		set_bit(index, &acm->read_urbs_free);  		return res; @@ -471,6 +476,7 @@ static void acm_read_bulk_callback(struct urb *urb)  	int status = urb->status;  	bool stopped = false;  	bool stalled = false; +	bool cooldown = false;  	dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n",  		rb->index, urb->actual_length, status); @@ -497,6 +503,14 @@ static void acm_read_bulk_callback(struct urb *urb)  			__func__, status);  		stopped = true;  		break; +	case -EOVERFLOW: +	case -EPROTO: +		dev_dbg(&acm->data->dev, +			"%s - cooling babbling device\n", __func__); +		usb_mark_last_busy(acm->dev); +		set_bit(rb->index, &acm->urbs_in_error_delay); +		cooldown = true; +		break;  	default:  		dev_dbg(&acm->data->dev,  			"%s - nonzero urb status received: %d\n", @@ -518,9 +532,11 @@ static void acm_read_bulk_callback(struct urb *urb)  	 */  	smp_mb__after_atomic(); -	if (stopped || stalled) { +	if (stopped || stalled || cooldown) {  		if (stalled)  			schedule_work(&acm->work); +		else if (cooldown) +			schedule_delayed_work(&acm->dwork, HZ / 2);  		return;  	} @@ -557,14 +573,20 @@ static void acm_softint(struct work_struct *work)  	struct acm *acm = container_of(work, struct acm, work);  	if (test_bit(EVENT_RX_STALL, &acm->flags)) { -		if (!(usb_autopm_get_interface(acm->data))) { +		smp_mb(); /* against acm_suspend() */ +		if (!acm->susp_count) {  			for (i = 0; i < acm->rx_buflimit; i++)  				usb_kill_urb(acm->read_urbs[i]);  			usb_clear_halt(acm->dev, acm->in);  			acm_submit_read_urbs(acm, GFP_KERNEL); -			usb_autopm_put_interface(acm->data); +			clear_bit(EVENT_RX_STALL, &acm->flags);  		} -		clear_bit(EVENT_RX_STALL, &acm->flags); +	} + +	if (test_and_clear_bit(ACM_ERROR_DELAY, &acm->flags)) { +		for (i = 0; i < ACM_NR; i++)  +			if (test_and_clear_bit(i, &acm->urbs_in_error_delay)) +					acm_submit_read_urb(acm, i, GFP_NOIO);  	}  	if (test_and_clear_bit(EVENT_TTY_WAKEUP, &acm->flags)) @@ -1333,6 +1355,7 @@ made_compressed_probe:  	acm->readsize = readsize;  	acm->rx_buflimit = num_rx_buf;  	INIT_WORK(&acm->work, acm_softint); +	INIT_DELAYED_WORK(&acm->dwork, acm_softint);  	init_waitqueue_head(&acm->wioctl);  	spin_lock_init(&acm->write_lock);  	spin_lock_init(&acm->read_lock); @@ -1542,6 +1565,7 @@ static void acm_disconnect(struct usb_interface *intf)  	acm_kill_urbs(acm);  	cancel_work_sync(&acm->work); +	cancel_delayed_work_sync(&acm->dwork);  	tty_unregister_device(acm_tty_driver, acm->minor); @@ -1584,6 +1608,8 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)  	acm_kill_urbs(acm);  	cancel_work_sync(&acm->work); +	cancel_delayed_work_sync(&acm->dwork); +	acm->urbs_in_error_delay = 0;  	return 0;  }  | 
