brcm2708: update against latest rpi-3.10.y branch
[openwrt.git] / target / linux / brcm2708 / patches-3.10 / 0049-dwc_otg-Fix-unsafe-access-of-QTD-during-URB-enqueue.patch
1 From 08e3e98d28e32852e43bf25fb3e64bb3f5e6af4d 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/174] 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 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
21 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
22 @@ -462,6 +462,8 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_
23  {
24         dwc_irqflags_t flags;
25         int retval = 0;
26 +       uint8_t needs_scheduling = 0;
27 +       dwc_otg_transaction_type_e tr_type;
28         dwc_otg_qtd_t *qtd;
29         gintmsk_data_t intr_mask = {.d32 = 0 };
30  
31 @@ -493,22 +495,22 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_
32                 return -DWC_E_NO_MEMORY;
33         }
34  #endif
35 -       retval =
36 -           dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
37 +       intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
38 +       if(!intr_mask.b.sofintr) needs_scheduling = 1;
39 +       if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP))
40 +               /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
41 +               needs_scheduling = 0;
42 +
43 +       retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
44              // creates a new queue in ep_handle if it doesn't exist already
45         if (retval < 0) {
46                 DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
47                           "Error status %d\n", retval);
48                 dwc_otg_hcd_qtd_free(qtd);
49 +               return retval;
50         }
51 -       intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
52 -       if (!intr_mask.b.sofintr && retval == 0) {
53 -               dwc_otg_transaction_type_e tr_type;
54 -               if ((qtd->qh->ep_type == UE_BULK)
55 -                   && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
56 -                       /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
57 -                       return 0;
58 -               }
59 +
60 +       if(needs_scheduling) {
61                 DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
62                 tr_type = dwc_otg_hcd_select_transactions(hcd);
63                 if (tr_type != DWC_OTG_TRANSACTION_NONE) {
64 @@ -516,7 +518,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_
65                 }
66                 DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
67         }
68 -
69         return retval;
70  }
71  
72 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
73 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
74 @@ -937,7 +937,7 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t *
75         if (*qh == NULL) {
76                 *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
77                 if (*qh == NULL) {
78 -                       retval = -1;
79 +                       retval = -DWC_E_NO_MEMORY;
80                         goto done;
81                 }
82         }