Skip to content

Commit 8cdf875

Browse files
committed
Merge pull request #334 from P33M/rpi-3.6.y
dwc_otg: prevent OOPSes during device disconnects
2 parents 0006326 + eb1b482 commit 8cdf875

File tree

3 files changed

+28
-40
lines changed

3 files changed

+28
-40
lines changed

drivers/usb/host/dwc_otg/dwc_otg_hcd.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
464464
dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
465465
int atomic_alloc)
466466
{
467-
dwc_irqflags_t flags;
468467
int retval = 0;
469468
uint8_t needs_scheduling = 0;
470469
dwc_otg_transaction_type_e tr_type;
@@ -515,12 +514,10 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
515514
}
516515

517516
if(needs_scheduling) {
518-
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
519517
tr_type = dwc_otg_hcd_select_transactions(hcd);
520518
if (tr_type != DWC_OTG_TRANSACTION_NONE) {
521519
dwc_otg_hcd_queue_transactions(hcd, tr_type);
522520
}
523-
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
524521
}
525522
return retval;
526523
}

drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -679,9 +679,7 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
679679
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
680680
struct usb_host_endpoint *ep = urb->ep;
681681
#endif
682-
#if USB_URB_EP_LINKING
683682
dwc_irqflags_t irqflags;
684-
#endif
685683
void **ref_ep_hcpriv = &ep->hcpriv;
686684
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
687685
dwc_otg_hcd_urb_t *dwc_otg_urb;
@@ -733,10 +731,9 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
733731
if(dwc_otg_urb == NULL)
734732
return -ENOMEM;
735733

736-
urb->hcpriv = dwc_otg_urb;
737-
if (!dwc_otg_urb && urb->number_of_packets)
738-
return -ENOMEM;
739-
734+
if (!dwc_otg_urb && urb->number_of_packets)
735+
return -ENOMEM;
736+
740737
dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
741738
usb_pipeendpoint(urb->pipe), ep_type,
742739
usb_pipein(urb->pipe),
@@ -775,37 +772,35 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
775772
iso_frame_desc[i].length);
776773
}
777774

775+
DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
776+
urb->hcpriv = dwc_otg_urb;
778777
#if USB_URB_EP_LINKING
779-
DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
780778
retval = usb_hcd_link_urb_to_ep(hcd, urb);
781-
DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
782-
if (0 == retval)
779+
if (0 == retval)
783780
#endif
784-
{
785-
retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
786-
/*(dwc_otg_qh_t **)*/
787-
ref_ep_hcpriv,
788-
mem_flags == GFP_ATOMIC ? 1 : 0);
789-
if (0 == retval) {
790-
if (alloc_bandwidth) {
791-
allocate_bus_bandwidth(hcd,
792-
dwc_otg_hcd_get_ep_bandwidth(
793-
dwc_otg_hcd, *ref_ep_hcpriv),
794-
urb);
795-
}
796-
} else {
781+
{
782+
retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
783+
/*(dwc_otg_qh_t **)*/
784+
ref_ep_hcpriv,
785+
mem_flags == GFP_ATOMIC ? 1 : 0);
786+
if (0 == retval) {
787+
if (alloc_bandwidth) {
788+
allocate_bus_bandwidth(hcd,
789+
dwc_otg_hcd_get_ep_bandwidth(
790+
dwc_otg_hcd, *ref_ep_hcpriv),
791+
urb);
792+
}
793+
} else {
794+
DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
797795
#if USB_URB_EP_LINKING
798-
dwc_irqflags_t irqflags;
799-
DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
800-
DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
801-
usb_hcd_unlink_urb_from_ep(hcd, urb);
802-
DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
796+
usb_hcd_unlink_urb_from_ep(hcd, urb);
803797
#endif
804-
if (retval == -DWC_E_NO_DEVICE) {
805-
retval = -ENODEV;
806-
}
807-
}
808-
}
798+
urb->hcpriv = NULL;
799+
if (retval == -DWC_E_NO_DEVICE)
800+
retval = -ENODEV;
801+
}
802+
}
803+
DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
809804
return retval;
810805
}
811806

drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,7 @@ void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
919919
* QH to place the QTD into. If it does not find a QH, then it will create a
920920
* new QH. If the QH to which the QTD is added is not currently scheduled, it
921921
* is placed into the proper schedule based on its EP type.
922+
* HCD lock must be held and interrupts must be disabled on entry
922923
*
923924
* @param[in] qtd The QTD to add
924925
* @param[in] hcd The DWC HCD structure
@@ -931,8 +932,6 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
931932
dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
932933
{
933934
int retval = 0;
934-
dwc_irqflags_t flags;
935-
936935
dwc_otg_hcd_urb_t *urb = qtd->urb;
937936

938937
/*
@@ -946,15 +945,12 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
946945
goto done;
947946
}
948947
}
949-
DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
950948
retval = dwc_otg_hcd_qh_add(hcd, *qh);
951949
if (retval == 0) {
952950
DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
953951
qtd_list_entry);
954952
qtd->qh = *qh;
955953
}
956-
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
957-
958954
done:
959955

960956
return retval;

0 commit comments

Comments
 (0)