ixp4xx: remove linux 3.10 support
[openwrt.git] / target / linux / brcm2708 / patches-3.10 / 0082-dwc_otg-prevent-OOPSes-during-device-disconnects.patch
1 From 2e2f1ef719a2fa55fd1d95d9536fa8cca94459a4 Mon Sep 17 00:00:00 2001
2 From: P33M <P33M@github.com>
3 Date: Thu, 18 Jul 2013 17:07:26 +0100
4 Subject: [PATCH 082/196] dwc_otg: prevent OOPSes during device disconnects
5
6 The dwc_otg_urb_enqueue function is thread-unsafe. In particular the
7 access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and
8 friends does not occur within a critical section and so if a device
9 was unplugged during activity there was a high chance that the
10 usbcore hub_thread would try to disable the endpoint with partially-
11 formed entries in the URB queue. This would result in BUG() or null
12 pointer dereferences.
13
14 Fix so that access of urb->hcpriv, enqueuing to the hardware and
15 adding to usbcore endpoint URB lists is contained within a single
16 critical section.
17 ---
18  drivers/usb/host/dwc_otg/dwc_otg_hcd.c       |  3 ---
19  drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 14 +++++---------
20  drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c |  6 +-----
21  3 files changed, 6 insertions(+), 17 deletions(-)
22
23 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
24 index af9108c..a1970dc 100644
25 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
26 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
27 @@ -464,7 +464,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
28                             dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
29                             int atomic_alloc)
30  {
31 -       dwc_irqflags_t flags;
32         int retval = 0;
33         uint8_t needs_scheduling = 0;
34         dwc_otg_transaction_type_e tr_type;
35 @@ -515,12 +514,10 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
36         }
37  
38         if(needs_scheduling) {
39 -               DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
40                 tr_type = dwc_otg_hcd_select_transactions(hcd);
41                 if (tr_type != DWC_OTG_TRANSACTION_NONE) {
42                         dwc_otg_hcd_queue_transactions(hcd, tr_type);
43                 }
44 -               DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
45         }
46         return retval;
47  }
48 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
49 index 0f72bd5..ad03ff1 100644
50 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
51 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
52 @@ -679,9 +679,7 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
53  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
54         struct usb_host_endpoint *ep = urb->ep;
55  #endif
56 -#if USB_URB_EP_LINKING
57         dwc_irqflags_t irqflags;
58 -#endif
59          void **ref_ep_hcpriv = &ep->hcpriv;
60         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
61         dwc_otg_hcd_urb_t *dwc_otg_urb;
62 @@ -733,7 +731,6 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
63         if(dwc_otg_urb == NULL)
64                 return -ENOMEM;
65  
66 -       urb->hcpriv = dwc_otg_urb;
67         if (!dwc_otg_urb && urb->number_of_packets)
68                 return -ENOMEM;
69  
70 @@ -775,10 +772,10 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
71                                                     iso_frame_desc[i].length);
72         }
73  
74 -#if USB_URB_EP_LINKING
75         DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
76 +       urb->hcpriv = dwc_otg_urb;
77 +#if USB_URB_EP_LINKING
78         retval = usb_hcd_link_urb_to_ep(hcd, urb);
79 -       DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
80         if (0 == retval)
81  #endif
82         {
83 @@ -794,17 +791,16 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
84                                                 urb);
85                         }
86                 } else {
87 -#if USB_URB_EP_LINKING
88 -                       dwc_irqflags_t irqflags;
89                         DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
90 -                       DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
91 +#if USB_URB_EP_LINKING
92                         usb_hcd_unlink_urb_from_ep(hcd, urb);
93 -                       DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
94  #endif
95 +                       urb->hcpriv = NULL;
96                         if (retval == -DWC_E_NO_DEVICE)
97                                 retval = -ENODEV;
98                 }
99         }
100 +       DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
101         return retval;
102  }
103  
104 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
105 index 8125307..5aed416 100644
106 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
107 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
108 @@ -919,6 +919,7 @@ void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
109   * QH to place the QTD into.  If it does not find a QH, then it will create a
110   * new QH. If the QH to which the QTD is added is not currently scheduled, it
111   * is placed into the proper schedule based on its EP type.
112 + * HCD lock must be held and interrupts must be disabled on entry
113   *
114   * @param[in] qtd The QTD to add
115   * @param[in] hcd The DWC HCD structure
116 @@ -931,8 +932,6 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
117                         dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
118  {
119         int retval = 0;
120 -       dwc_irqflags_t flags;
121 -
122         dwc_otg_hcd_urb_t *urb = qtd->urb;
123  
124         /*
125 @@ -946,15 +945,12 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
126                         goto done;
127                 }
128         }
129 -       DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
130         retval = dwc_otg_hcd_qh_add(hcd, *qh);
131         if (retval == 0) {
132                 DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
133                                         qtd_list_entry);
134                 qtd->qh = *qh;
135         }
136 -       DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
137 -
138  done:
139  
140         return retval;
141 -- 
142 1.9.1
143