Skip to content

Commit

Permalink
Merge pull request #334 from P33M/rpi-3.6.y
Browse files Browse the repository at this point in the history
dwc_otg: prevent OOPSes during device disconnects
  • Loading branch information
popcornmix committed Jul 19, 2013
2 parents 0006326 + eb1b482 commit 8cdf875
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 40 deletions.
3 changes: 0 additions & 3 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
int atomic_alloc)
{
dwc_irqflags_t flags;
int retval = 0;
uint8_t needs_scheduling = 0;
dwc_otg_transaction_type_e tr_type;
Expand Down Expand Up @@ -515,12 +514,10 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
}

if(needs_scheduling) {
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
tr_type = dwc_otg_hcd_select_transactions(hcd);
if (tr_type != DWC_OTG_TRANSACTION_NONE) {
dwc_otg_hcd_queue_transactions(hcd, tr_type);
}
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
}
return retval;
}
Expand Down
59 changes: 27 additions & 32 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,9 +679,7 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
struct usb_host_endpoint *ep = urb->ep;
#endif
#if USB_URB_EP_LINKING
dwc_irqflags_t irqflags;
#endif
void **ref_ep_hcpriv = &ep->hcpriv;
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
dwc_otg_hcd_urb_t *dwc_otg_urb;
Expand Down Expand Up @@ -733,10 +731,9 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
if(dwc_otg_urb == NULL)
return -ENOMEM;

urb->hcpriv = dwc_otg_urb;
if (!dwc_otg_urb && urb->number_of_packets)
return -ENOMEM;

if (!dwc_otg_urb && urb->number_of_packets)
return -ENOMEM;

dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe), ep_type,
usb_pipein(urb->pipe),
Expand Down Expand Up @@ -775,37 +772,35 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
iso_frame_desc[i].length);
}

DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
urb->hcpriv = dwc_otg_urb;
#if USB_URB_EP_LINKING
DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
if (0 == retval)
if (0 == retval)
#endif
{
retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
/*(dwc_otg_qh_t **)*/
ref_ep_hcpriv,
mem_flags == GFP_ATOMIC ? 1 : 0);
if (0 == retval) {
if (alloc_bandwidth) {
allocate_bus_bandwidth(hcd,
dwc_otg_hcd_get_ep_bandwidth(
dwc_otg_hcd, *ref_ep_hcpriv),
urb);
}
} else {
{
retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
/*(dwc_otg_qh_t **)*/
ref_ep_hcpriv,
mem_flags == GFP_ATOMIC ? 1 : 0);
if (0 == retval) {
if (alloc_bandwidth) {
allocate_bus_bandwidth(hcd,
dwc_otg_hcd_get_ep_bandwidth(
dwc_otg_hcd, *ref_ep_hcpriv),
urb);
}
} else {
DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
#if USB_URB_EP_LINKING
dwc_irqflags_t irqflags;
DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
usb_hcd_unlink_urb_from_ep(hcd, urb);
DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
usb_hcd_unlink_urb_from_ep(hcd, urb);
#endif
if (retval == -DWC_E_NO_DEVICE) {
retval = -ENODEV;
}
}
}
urb->hcpriv = NULL;
if (retval == -DWC_E_NO_DEVICE)
retval = -ENODEV;
}
}
DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
return retval;
}

Expand Down
6 changes: 1 addition & 5 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,7 @@ void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
* QH to place the QTD into. If it does not find a QH, then it will create a
* new QH. If the QH to which the QTD is added is not currently scheduled, it
* is placed into the proper schedule based on its EP type.
* HCD lock must be held and interrupts must be disabled on entry
*
* @param[in] qtd The QTD to add
* @param[in] hcd The DWC HCD structure
Expand All @@ -931,8 +932,6 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
{
int retval = 0;
dwc_irqflags_t flags;

dwc_otg_hcd_urb_t *urb = qtd->urb;

/*
Expand All @@ -946,15 +945,12 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
goto done;
}
}
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
retval = dwc_otg_hcd_qh_add(hcd, *qh);
if (retval == 0) {
DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
qtd_list_entry);
qtd->qh = *qh;
}
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);

done:

return retval;
Expand Down

0 comments on commit 8cdf875

Please sign in to comment.