You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
89 lines
3.4 KiB
89 lines
3.4 KiB
From 1ef8aaf1ef348a22b72ba4367c5e2e5727542f59 Mon Sep 17 00:00:00 2001
|
|
From: P33M <P33M@github.com>
|
|
Date: Fri, 15 Feb 2013 22:36:47 +0000
|
|
Subject: [PATCH 049/196] dwc_otg: Fix unsafe access of QTD during URB enqueue
|
|
|
|
In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the
|
|
transaction could complete almost immediately after the qtd was assigned
|
|
to a host channel during URB enqueue, which meant the qtd pointer was no
|
|
longer valid having been completed and removed. Usually, this resulted in
|
|
an OOPS during URB submission. By predetermining whether transactions
|
|
need to be queued or not, this unsafe pointer access is avoided.
|
|
|
|
This bug was only evident on the Pi model A where a device was attached
|
|
that had no periodic endpoints (e.g. USB pendrive or some wlan devices).
|
|
---
|
|
drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 23 ++++++++++++-----------
|
|
drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 2 +-
|
|
2 files changed, 13 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
|
|
index d5c94f4..e653d84 100644
|
|
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
|
|
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
|
|
@@ -462,6 +462,8 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
|
|
{
|
|
dwc_irqflags_t flags;
|
|
int retval = 0;
|
|
+ uint8_t needs_scheduling = 0;
|
|
+ dwc_otg_transaction_type_e tr_type;
|
|
dwc_otg_qtd_t *qtd;
|
|
gintmsk_data_t intr_mask = {.d32 = 0 };
|
|
|
|
@@ -493,22 +495,22 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
|
|
return -DWC_E_NO_MEMORY;
|
|
}
|
|
#endif
|
|
- retval =
|
|
- dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
|
|
+ intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
|
|
+ if(!intr_mask.b.sofintr) needs_scheduling = 1;
|
|
+ if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP))
|
|
+ /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
|
|
+ needs_scheduling = 0;
|
|
+
|
|
+ retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
|
|
// creates a new queue in ep_handle if it doesn't exist already
|
|
if (retval < 0) {
|
|
DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
|
|
"Error status %d\n", retval);
|
|
dwc_otg_hcd_qtd_free(qtd);
|
|
+ return retval;
|
|
}
|
|
- intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
|
|
- if (!intr_mask.b.sofintr && retval == 0) {
|
|
- dwc_otg_transaction_type_e tr_type;
|
|
- if ((qtd->qh->ep_type == UE_BULK)
|
|
- && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
|
|
- /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
|
|
- return 0;
|
|
- }
|
|
+
|
|
+ if(needs_scheduling) {
|
|
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
|
|
tr_type = dwc_otg_hcd_select_transactions(hcd);
|
|
if (tr_type != DWC_OTG_TRANSACTION_NONE) {
|
|
@@ -516,7 +518,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
|
|
}
|
|
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
|
|
}
|
|
-
|
|
return retval;
|
|
}
|
|
|
|
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
|
|
index b337e1b..b3e6e52 100644
|
|
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
|
|
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
|
|
@@ -937,7 +937,7 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
|
|
if (*qh == NULL) {
|
|
*qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
|
|
if (*qh == NULL) {
|
|
- retval = -1;
|
|
+ retval = -DWC_E_NO_MEMORY;
|
|
goto done;
|
|
}
|
|
}
|
|
--
|
|
1.9.1
|
|
|
|
|