Module Name: src
Committed By: skrll
Date: Thu Jan 2 15:54:10 UTC 2014
Modified Files:
src/sys/external/bsd/dwc2: dwc2.c
src/sys/external/bsd/dwc2/dist: dwc2_hcd.c dwc2_hcdqueue.c
Log Message:
Protect access of urb->hcpriv by adapting the following change from the
Raspberry PI dwc_otg driver.
https://github.com/raspberrypi/linux/commit/38753ce72d4f10d5d0f1ed27fa691a2ba8910941
dwc_otg: prevent OOPSes during device disconnects
The dwc_otg_urb_enqueue function is thread-unsafe. In particular the
access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and
friends does not occur within a critical section and so if a device
was unplugged during activity there was a high chance that the
usbcore hub_thread would try to disable the endpoint with partially-
formed entries in the URB queue. This would result in BUG() or null
pointer dereferences.
Fix so that access of urb->hcpriv, enqueuing to the hardware and
adding to usbcore endpoint URB lists is contained within a single
critical section.
To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/sys/external/bsd/dwc2/dwc2.c
cvs rdiff -u -r1.9 -r1.10 src/sys/external/bsd/dwc2/dist/dwc2_hcd.c
cvs rdiff -u -r1.6 -r1.7 src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/external/bsd/dwc2/dwc2.c
diff -u src/sys/external/bsd/dwc2/dwc2.c:1.22 src/sys/external/bsd/dwc2/dwc2.c:1.23
--- src/sys/external/bsd/dwc2/dwc2.c:1.22 Tue Dec 31 09:10:43 2013
+++ src/sys/external/bsd/dwc2/dwc2.c Thu Jan 2 15:54:10 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc2.c,v 1.22 2013/12/31 09:10:43 skrll Exp $ */
+/* $NetBSD: dwc2.c,v 1.23 2014/01/02 15:54:10 skrll Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.22 2013/12/31 09:10:43 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.23 2014/01/02 15:54:10 skrll Exp $");
#include "opt_usb.h"
@@ -1298,7 +1298,6 @@ dwc2_device_start(usbd_xfer_handle xfer)
memset(dwc2_urb, 0, sizeof(*dwc2_urb) +
sizeof(dwc2_urb->iso_descs[0]) * DWC2_MAXISOCPACKETS);
- dwc2_urb->priv = xfer;
dwc2_hcd_urb_set_pipeinfo(hsotg, dwc2_urb, addr, epnum, xfertype, dir,
mps);
@@ -1379,6 +1378,9 @@ dwc2_device_start(usbd_xfer_handle xfer)
}
/* might need to check cpu_intr_p */
+ mutex_spin_enter(&hsotg->lock);
+
+ dwc2_urb->priv = xfer;
retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &dpipe->priv, 0);
if (retval)
goto fail;
@@ -1389,14 +1391,14 @@ dwc2_device_start(usbd_xfer_handle xfer)
}
if (alloc_bandwidth) {
- mutex_spin_enter(&hsotg->lock);
dwc2_allocate_bus_bandwidth(hsotg,
dwc2_hcd_get_ep_bandwidth(hsotg, dpipe),
xfer);
- mutex_spin_exit(&hsotg->lock);
}
fail:
+ mutex_spin_exit(&hsotg->lock);
+
// mutex_exit(&sc->sc_lock);
switch (retval) {
Index: src/sys/external/bsd/dwc2/dist/dwc2_hcd.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hcd.c:1.9 src/sys/external/bsd/dwc2/dist/dwc2_hcd.c:1.10
--- src/sys/external/bsd/dwc2/dist/dwc2_hcd.c:1.9 Sun Nov 24 12:25:19 2013
+++ src/sys/external/bsd/dwc2/dist/dwc2_hcd.c Thu Jan 2 15:54:10 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc2_hcd.c,v 1.9 2013/11/24 12:25:19 skrll Exp $ */
+/* $NetBSD: dwc2_hcd.c,v 1.10 2014/01/02 15:54:10 skrll Exp $ */
/*
* hcd.c - DesignWare HS OTG Controller host-mode routines
@@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_hcd.c,v 1.9 2013/11/24 12:25:19 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_hcd.c,v 1.10 2014/01/02 15:54:10 skrll Exp $");
#include <sys/types.h>
#include <sys/kmem.h>
@@ -367,7 +367,6 @@ dwc2_hcd_urb_enqueue(struct dwc2_hsotg *
{
struct dwc2_softc *sc = hsotg->hsotg_sc;
struct dwc2_qtd *qtd;
- unsigned long flags;
u32 intr_mask;
int retval;
int dev_speed;
@@ -421,11 +420,9 @@ dwc2_hcd_urb_enqueue(struct dwc2_hsotg *
*/
return 0;
- spin_lock_irqsave(&hsotg->lock, flags);
tr_type = dwc2_hcd_select_transactions(hsotg);
if (tr_type != DWC2_TRANSACTION_NONE)
dwc2_hcd_queue_transactions(hsotg, tr_type);
- spin_unlock_irqrestore(&hsotg->lock, flags);
}
return retval;
Index: src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c:1.6 src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c:1.7
--- src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c:1.6 Sun Nov 24 12:25:19 2013
+++ src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c Thu Jan 2 15:54:10 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc2_hcdqueue.c,v 1.6 2013/11/24 12:25:19 skrll Exp $ */
+/* $NetBSD: dwc2_hcdqueue.c,v 1.7 2014/01/02 15:54:10 skrll Exp $ */
/*
* hcd_queue.c - DesignWare HS OTG Controller host queuing routines
@@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdqueue.c,v 1.6 2013/11/24 12:25:19 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdqueue.c,v 1.7 2014/01/02 15:54:10 skrll Exp $");
#include <sys/types.h>
#include <sys/kmem.h>
@@ -787,12 +787,13 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *
* Finds the correct QH to place the QTD into. If it does not find a QH, 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
*/
int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
struct dwc2_qh **qh, gfp_t mem_flags)
{
struct dwc2_hcd_urb *urb = qtd->urb;
- unsigned long flags;
int allocated = 0;
int retval;
@@ -807,15 +808,12 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *
allocated = 1;
}
- spin_lock_irqsave(&hsotg->lock, flags);
-
retval = dwc2_hcd_qh_add(hsotg, *qh);
if (retval)
goto fail;
qtd->qh = *qh;
list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
- spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
@@ -832,10 +830,7 @@ fail:
qtd_list_entry)
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
- spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hcd_qh_free(hsotg, qh_tmp);
- } else {
- spin_unlock_irqrestore(&hsotg->lock, flags);
}
return retval;