ixp4xx: remove linux 3.10 support
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.10 / 0049-dwc_otg-Fix-unsafe-access-of-QTD-during-URB-enqueue.patch
1 From 1ef8aaf1ef348a22b72ba4367c5e2e5727542f59 Mon Sep 17 00:00:00 2001
2 From: P33M <P33M@github.com>
3 Date: Fri, 15 Feb 2013 22:36:47 +0000
4 Subject: [PATCH 049/196] dwc_otg: Fix unsafe access of QTD during URB enqueue
5
6 In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the
7 transaction could complete almost immediately after the qtd was assigned
8 to a host channel during URB enqueue, which meant the qtd pointer was no
9 longer valid having been completed and removed. Usually, this resulted in
10 an OOPS during URB submission. By predetermining whether transactions
11 need to be queued or not, this unsafe pointer access is avoided.
12
13 This bug was only evident on the Pi model A where a device was attached
14 that had no periodic endpoints (e.g. USB pendrive or some wlan devices).
15 ---
16 drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 23 ++++++++++++-----------
17 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 2 +-
18 2 files changed, 13 insertions(+), 12 deletions(-)
19
20 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
21 index d5c94f4..e653d84 100644
22 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
23 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
24 @@ -462,6 +462,8 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
25 {
26 dwc_irqflags_t flags;
27 int retval = 0;
28 + uint8_t needs_scheduling = 0;
29 + dwc_otg_transaction_type_e tr_type;
30 dwc_otg_qtd_t *qtd;
31 gintmsk_data_t intr_mask = {.d32 = 0 };
32
33 @@ -493,22 +495,22 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
34 return -DWC_E_NO_MEMORY;
35 }
36 #endif
37 - retval =
38 - dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
39 + intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
40 + if(!intr_mask.b.sofintr) needs_scheduling = 1;
41 + if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP))
42 + /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
43 + needs_scheduling = 0;
44 +
45 + retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
46 // creates a new queue in ep_handle if it doesn't exist already
47 if (retval < 0) {
48 DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
49 "Error status %d\n", retval);
50 dwc_otg_hcd_qtd_free(qtd);
51 + return retval;
52 }
53 - intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
54 - if (!intr_mask.b.sofintr && retval == 0) {
55 - dwc_otg_transaction_type_e tr_type;
56 - if ((qtd->qh->ep_type == UE_BULK)
57 - && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
58 - /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
59 - return 0;
60 - }
61 +
62 + if(needs_scheduling) {
63 DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
64 tr_type = dwc_otg_hcd_select_transactions(hcd);
65 if (tr_type != DWC_OTG_TRANSACTION_NONE) {
66 @@ -516,7 +518,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
67 }
68 DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
69 }
70 -
71 return retval;
72 }
73
74 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
75 index b337e1b..b3e6e52 100644
76 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
77 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
78 @@ -937,7 +937,7 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
79 if (*qh == NULL) {
80 *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
81 if (*qh == NULL) {
82 - retval = -1;
83 + retval = -DWC_E_NO_MEMORY;
84 goto done;
85 }
86 }
87 --
88 1.9.1
89