diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-18 20:21:49 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-18 20:21:49 +0300 |
commit | 5695d5d1970f975de059bb6dec76941440f62488 (patch) | |
tree | 6b03381a0b103324c286a83ebb4154719b514feb /drivers/usb/class/cdc-wdm.c | |
parent | 1f7a4c73a739a63b3f108d8eda6f947fdc70dd65 (diff) | |
parent | 29c692c96b3a39cd1911fb79cd2505af8d070f07 (diff) | |
download | linux-5695d5d1970f975de059bb6dec76941440f62488.tar.xz |
Merge tag 'usb-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH:
"Here is the big USB and phy driver patch set for 4.19-rc1.
Nothing huge but there was a lot of work that happened this
development cycle:
- lots of type-c work, with drivers graduating out of staging, and
displayport support being added.
- new PHY drivers
- the normal collection of gadget driver updates and fixes
- code churn to work on the urb handling path, using irqsave()
everywhere in anticipation of making this codepath a lot simpler in
the future.
- usbserial driver fixes and reworks
- other misc changes
All of these have been in linux-next with no reported issues for a
while"
* tag 'usb-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (159 commits)
USB: serial: pl2303: add a new device id for ATEN
usb: renesas_usbhs: Kconfig: convert to SPDX identifiers
usb: dwc3: gadget: Check MaxPacketSize from descriptor
usb: dwc2: Turn on uframe_sched on "stm32f4x9_fsotg" platforms
usb: dwc2: Turn on uframe_sched on "amlogic" platforms
usb: dwc2: Turn on uframe_sched on "his" platforms
usb: dwc2: Turn on uframe_sched on "bcm" platforms
usb: dwc2: gadget: ISOC's starting flow improvement
usb: dwc2: Make dwc2_readl/writel functions endianness-agnostic.
usb: dwc3: core: Enable AutoRetry feature in the controller
usb: dwc3: Set default mode for dwc_usb31
usb: gadget: udc: renesas_usb3: Add register of usb role switch
usb: dwc2: replace ioread32/iowrite32_rep with dwc2_readl/writel_rep
usb: dwc2: Modify dwc2_readl/writel functions prototype
usb: dwc3: pci: Intel Merrifield can be host
usb: dwc3: pci: Supply device properties via driver data
arm64: dts: dwc3: description of incr burst type
usb: dwc3: Enable undefined length INCR burst type
usb: dwc3: add global soc bus configuration reg0
usb: dwc3: Describe 'wakeup_work' field of struct dwc3_pci
...
Diffstat (limited to 'drivers/usb/class/cdc-wdm.c')
-rw-r--r-- | drivers/usb/class/cdc-wdm.c | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index a0d284ef3f40..bec581fb7c63 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -96,6 +96,7 @@ struct wdm_device { struct mutex rlock; wait_queue_head_t wait; struct work_struct rxwork; + struct work_struct service_outs_intr; int werr; int rerr; int resp_count; @@ -141,26 +142,26 @@ found: static void wdm_out_callback(struct urb *urb) { struct wdm_device *desc; + unsigned long flags; + desc = urb->context; - spin_lock(&desc->iuspin); + spin_lock_irqsave(&desc->iuspin, flags); desc->werr = urb->status; - spin_unlock(&desc->iuspin); + spin_unlock_irqrestore(&desc->iuspin, flags); kfree(desc->outbuf); desc->outbuf = NULL; clear_bit(WDM_IN_USE, &desc->flags); wake_up(&desc->wait); } -/* forward declaration */ -static int service_outstanding_interrupt(struct wdm_device *desc); - static void wdm_in_callback(struct urb *urb) { + unsigned long flags; struct wdm_device *desc = urb->context; int status = urb->status; int length = urb->actual_length; - spin_lock(&desc->iuspin); + spin_lock_irqsave(&desc->iuspin, flags); clear_bit(WDM_RESPONDING, &desc->flags); if (status) { @@ -209,8 +210,6 @@ static void wdm_in_callback(struct urb *urb) } } skip_error: - set_bit(WDM_READ, &desc->flags); - wake_up(&desc->wait); if (desc->rerr) { /* @@ -219,14 +218,17 @@ skip_error: * We should respond to further attempts from the device to send * data, so that we can get unstuck. */ - service_outstanding_interrupt(desc); + schedule_work(&desc->service_outs_intr); + } else { + set_bit(WDM_READ, &desc->flags); + wake_up(&desc->wait); } - - spin_unlock(&desc->iuspin); + spin_unlock_irqrestore(&desc->iuspin, flags); } static void wdm_int_callback(struct urb *urb) { + unsigned long flags; int rv = 0; int responding; int status = urb->status; @@ -286,7 +288,7 @@ static void wdm_int_callback(struct urb *urb) goto exit; } - spin_lock(&desc->iuspin); + spin_lock_irqsave(&desc->iuspin, flags); responding = test_and_set_bit(WDM_RESPONDING, &desc->flags); if (!desc->resp_count++ && !responding && !test_bit(WDM_DISCONNECTING, &desc->flags) @@ -294,7 +296,7 @@ static void wdm_int_callback(struct urb *urb) rv = usb_submit_urb(desc->response, GFP_ATOMIC); dev_dbg(&desc->intf->dev, "submit response URB %d\n", rv); } - spin_unlock(&desc->iuspin); + spin_unlock_irqrestore(&desc->iuspin, flags); if (rv < 0) { clear_bit(WDM_RESPONDING, &desc->flags); if (rv == -EPERM) @@ -758,6 +760,21 @@ static void wdm_rxwork(struct work_struct *work) } } +static void service_interrupt_work(struct work_struct *work) +{ + struct wdm_device *desc; + + desc = container_of(work, struct wdm_device, service_outs_intr); + + spin_lock_irq(&desc->iuspin); + service_outstanding_interrupt(desc); + if (!desc->resp_count) { + set_bit(WDM_READ, &desc->flags); + wake_up(&desc->wait); + } + spin_unlock_irq(&desc->iuspin); +} + /* --- hotplug --- */ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep, @@ -779,6 +796,7 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber); desc->intf = intf; INIT_WORK(&desc->rxwork, wdm_rxwork); + INIT_WORK(&desc->service_outs_intr, service_interrupt_work); rv = -EINVAL; if (!usb_endpoint_is_int_in(ep)) @@ -964,6 +982,7 @@ static void wdm_disconnect(struct usb_interface *intf) mutex_lock(&desc->wlock); kill_urbs(desc); cancel_work_sync(&desc->rxwork); + cancel_work_sync(&desc->service_outs_intr); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); @@ -1006,6 +1025,7 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) /* callback submits work - order is essential */ kill_urbs(desc); cancel_work_sync(&desc->rxwork); + cancel_work_sync(&desc->service_outs_intr); } if (!PMSG_IS_AUTO(message)) { mutex_unlock(&desc->wlock); @@ -1065,6 +1085,7 @@ static int wdm_pre_reset(struct usb_interface *intf) mutex_lock(&desc->wlock); kill_urbs(desc); cancel_work_sync(&desc->rxwork); + cancel_work_sync(&desc->service_outs_intr); return 0; } |