brcm2708: update against latest rpi-3.10.y branch
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.10 / 0071-dwc_otg-Call-usb_hcd_unlink_urb_from_ep-with-lock-he.patch
1 From 9b8c30f46a381533c92a6424ff25f9014d8802b0 Mon Sep 17 00:00:00 2001
2 From: Mike Bradley <mike.bradley@incanetworks.com>
3 Date: Mon, 17 Jun 2013 11:31:42 -0700
4 Subject: [PATCH 071/174] dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock
5 held in completion handler
6
7 usb_hcd_unlink_urb_from_ep must be called with the HCD lock held. Calling it
8 asynchronously in the tasklet was not safe (regression in
9 c4564d4a1a0a9b10d4419e48239f5d99e88d2667).
10
11 This change unlinks it from the endpoint prior to queueing it for handling in
12 the tasklet, and also adds a check to ensure the urb is OK to be unlinked
13 before doing so.
14
15 NULL pointer dereference kernel oopses had been observed in usb_hcd_giveback_urb
16 when a USB device was unplugged/replugged during data transfer. This effect
17 was reproduced using automated USB port power control, hundreds of replug
18 events were performed during active transfers to confirm that the problem was
19 eliminated.
20 ---
21 drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 2 +-
22 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 18 ++++++++++++++----
23 2 files changed, 15 insertions(+), 5 deletions(-)
24
25 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
26 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
27 @@ -704,6 +704,7 @@ static void completion_tasklet_func(void
28 urb_tq_entry_t *item;
29 dwc_irqflags_t flags;
30
31 + /* This could just be spin_lock_irq */
32 DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
33 while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) {
34 item = DWC_TAILQ_FIRST(&hcd->completed_urb_list);
35 @@ -713,7 +714,6 @@ static void completion_tasklet_func(void
36 DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
37 DWC_FREE(item);
38
39 - usb_hcd_unlink_urb_from_ep(hcd->priv, urb);
40 usb_hcd_giveback_urb(hcd->priv, urb, urb->status);
41
42 DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
43 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
44 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
45 @@ -265,13 +265,15 @@ static void free_bus_bandwidth(struct us
46
47 /**
48 * Sets the final status of an URB and returns it to the device driver. Any
49 - * required cleanup of the URB is performed.
50 + * required cleanup of the URB is performed. The HCD lock should be held on
51 + * entry.
52 */
53 static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
54 dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
55 {
56 struct urb *urb = (struct urb *)urb_handle;
57 urb_tq_entry_t *new_entry;
58 + int rc = 0;
59 if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
60 DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
61 __func__, urb, usb_pipedevice(urb->pipe),
62 @@ -363,9 +365,17 @@ static int _complete(dwc_otg_hcd_t * hcd
63 #endif
64 } else {
65 new_entry->urb = urb;
66 - DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry,
67 - urb_tq_entries);
68 - DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet);
69 +#if USB_URB_EP_LINKING
70 + rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
71 + if(0 == rc) {
72 + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
73 + }
74 +#endif
75 + if(0 == rc) {
76 + DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry,
77 + urb_tq_entries);
78 + DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet);
79 + }
80 }
81 return 0;
82 }