summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2014-07-12 20:13:49 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2014-07-12 20:13:49 +0000
commit968d9aade2b89c5889776f17a59253ccf5d649e3 (patch)
tree268c9ca191e173db82a910e2e3ed9766d8157221
parent1642d378e61c0ceb1e92a1e50fda710584c4c633 (diff)
Protect the freelists of transfer descriptors with the appropriate spl
so that we do not end up allocating two times new descriptors. This happens if a thread finds an empty list, start allocating, got interrupted and the interrupt also finds an empty list. Fix an issue reported by Nils Frohberg. ok yuo@, pirofti@
-rw-r--r--sys/dev/usb/ehci.c35
-rw-r--r--sys/dev/usb/ohci.c30
-rw-r--r--sys/dev/usb/uhci.c24
3 files changed, 50 insertions, 39 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index 7fc7f792330..9da65060f24 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehci.c,v 1.161 2014/07/12 08:21:10 mpi Exp $ */
+/* $OpenBSD: ehci.c,v 1.162 2014/07/12 20:13:48 mpi Exp $ */
/* $NetBSD: ehci.c,v 1.66 2004/06/30 03:11:56 mycroft Exp $ */
/*
@@ -57,7 +57,6 @@
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>
-#include <dev/usb/usb_quirks.h>
#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>
@@ -2316,22 +2315,20 @@ ehci_root_ctrl_done(struct usbd_xfer *xfer)
struct ehci_soft_qh *
ehci_alloc_sqh(struct ehci_softc *sc)
{
- struct ehci_soft_qh *sqh;
+ struct ehci_soft_qh *sqh = NULL;
usbd_status err;
int i, offs;
struct usb_dma dma;
+ int s;
+ s = splusb();
if (sc->sc_freeqhs == NULL) {
DPRINTFN(2, ("ehci_alloc_sqh: allocating chunk\n"));
err = usb_allocmem(&sc->sc_bus, EHCI_SQH_SIZE * EHCI_SQH_CHUNK,
EHCI_PAGE_SIZE, &dma);
-#ifdef EHCI_DEBUG
- if (err)
- printf("ehci_alloc_sqh: usb_allocmem()=%d\n", err);
-#endif
if (err)
- return (NULL);
- for(i = 0; i < EHCI_SQH_CHUNK; i++) {
+ goto out;
+ for (i = 0; i < EHCI_SQH_CHUNK; i++) {
offs = i * EHCI_SQH_SIZE;
sqh = KERNADDR(&dma, offs);
sqh->physaddr = DMAADDR(&dma, offs);
@@ -2346,14 +2343,21 @@ ehci_alloc_sqh(struct ehci_softc *sc)
memset(&sqh->qh, 0, sizeof(struct ehci_qh));
sqh->next = NULL;
sqh->prev = NULL;
+
+out:
+ splx(s);
return (sqh);
}
void
ehci_free_sqh(struct ehci_softc *sc, struct ehci_soft_qh *sqh)
{
+ int s;
+
+ s = splusb();
sqh->next = sc->sc_freeqhs;
sc->sc_freeqhs = sqh;
+ splx(s);
}
struct ehci_soft_qtd *
@@ -2365,17 +2369,13 @@ ehci_alloc_sqtd(struct ehci_softc *sc)
struct usb_dma dma;
int s;
+ s = splusb();
if (sc->sc_freeqtds == NULL) {
DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n"));
err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK,
EHCI_PAGE_SIZE, &dma);
-#ifdef EHCI_DEBUG
if (err)
- printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err);
-#endif
- if (err)
- return (NULL);
- s = splusb();
+ goto out;
for(i = 0; i < EHCI_SQTD_CHUNK; i++) {
offs = i * EHCI_SQTD_SIZE;
sqtd = KERNADDR(&dma, offs);
@@ -2385,16 +2385,15 @@ ehci_alloc_sqtd(struct ehci_softc *sc)
sqtd->nextqtd = sc->sc_freeqtds;
sc->sc_freeqtds = sqtd;
}
- splx(s);
}
- s = splusb();
sqtd = sc->sc_freeqtds;
sc->sc_freeqtds = sqtd->nextqtd;
memset(&sqtd->qtd, 0, sizeof(struct ehci_qtd));
sqtd->nextqtd = NULL;
- splx(s);
+out:
+ splx(s);
return (sqtd);
}
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index 29a9987b297..ef52e302e2d 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ohci.c,v 1.135 2014/07/10 20:57:40 mpi Exp $ */
+/* $OpenBSD: ohci.c,v 1.136 2014/07/12 20:13:48 mpi Exp $ */
/* $NetBSD: ohci.c,v 1.139 2003/02/22 05:24:16 tsutsui Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */
@@ -386,18 +386,20 @@ ohci_detach(struct device *self, int flags)
struct ohci_soft_ed *
ohci_alloc_sed(struct ohci_softc *sc)
{
- struct ohci_soft_ed *sed;
+ struct ohci_soft_ed *sed = NULL;
usbd_status err;
int i, offs;
struct usb_dma dma;
+ int s;
+ s = splusb();
if (sc->sc_freeeds == NULL) {
DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n"));
err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK,
OHCI_ED_ALIGN, &dma);
if (err)
- return (0);
- for(i = 0; i < OHCI_SED_CHUNK; i++) {
+ goto out;
+ for (i = 0; i < OHCI_SED_CHUNK; i++) {
offs = i * OHCI_SED_SIZE;
sed = KERNADDR(&dma, offs);
sed->physaddr = DMAADDR(&dma, offs);
@@ -409,51 +411,57 @@ ohci_alloc_sed(struct ohci_softc *sc)
sc->sc_freeeds = sed->next;
memset(&sed->ed, 0, sizeof(struct ohci_ed));
sed->next = NULL;
+
+out:
+ splx(s);
return (sed);
}
void
ohci_free_sed(struct ohci_softc *sc, struct ohci_soft_ed *sed)
{
+ int s;
+
+ s = splusb();
sed->next = sc->sc_freeeds;
sc->sc_freeeds = sed;
+ splx(s);
}
struct ohci_soft_td *
ohci_alloc_std(struct ohci_softc *sc)
{
- struct ohci_soft_td *std;
+ struct ohci_soft_td *std = NULL;
usbd_status err;
int i, offs;
struct usb_dma dma;
int s;
+ s = splusb();
if (sc->sc_freetds == NULL) {
DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n"));
err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK,
OHCI_TD_ALIGN, &dma);
if (err)
- return (NULL);
- s = splusb();
- for(i = 0; i < OHCI_STD_CHUNK; i++) {
+ goto out;
+ for (i = 0; i < OHCI_STD_CHUNK; i++) {
offs = i * OHCI_STD_SIZE;
std = KERNADDR(&dma, offs);
std->physaddr = DMAADDR(&dma, offs);
std->nexttd = sc->sc_freetds;
sc->sc_freetds = std;
}
- splx(s);
}
- s = splusb();
std = sc->sc_freetds;
sc->sc_freetds = std->nexttd;
memset(&std->td, 0, sizeof(struct ohci_td));
std->nexttd = NULL;
std->xfer = NULL;
ohci_hash_add_td(sc, std);
- splx(s);
+out:
+ splx(s);
return (std);
}
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index a2ca6f10226..4c3ae9cc666 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhci.c,v 1.127 2014/07/12 18:48:52 tedu Exp $ */
+/* $OpenBSD: uhci.c,v 1.128 2014/07/12 20:13:48 mpi Exp $ */
/* $NetBSD: uhci.c,v 1.172 2003/02/23 04:19:26 simonb Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */
@@ -1445,19 +1445,19 @@ uhci_run(struct uhci_softc *sc, int run)
struct uhci_soft_td *
uhci_alloc_std(struct uhci_softc *sc)
{
- struct uhci_soft_td *std;
+ struct uhci_soft_td *std = NULL;
usbd_status err;
int i, offs;
struct usb_dma dma;
int s;
+ s = splusb();
if (sc->sc_freetds == NULL) {
DPRINTFN(2,("uhci_alloc_std: allocating chunk\n"));
err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK,
UHCI_TD_ALIGN, &dma);
if (err)
- return (0);
- s = splusb();
+ goto out;
for(i = 0; i < UHCI_STD_CHUNK; i++) {
offs = i * UHCI_STD_SIZE;
std = KERNADDR(&dma, offs);
@@ -1465,15 +1465,14 @@ uhci_alloc_std(struct uhci_softc *sc)
std->link.std = sc->sc_freetds;
sc->sc_freetds = std;
}
- splx(s);
}
- s = splusb();
std = sc->sc_freetds;
sc->sc_freetds = std->link.std;
memset(&std->td, 0, sizeof(struct uhci_td));
- splx(s);
+out:
+ splx(s);
return (std);
}
@@ -1500,18 +1499,20 @@ uhci_free_std(struct uhci_softc *sc, struct uhci_soft_td *std)
struct uhci_soft_qh *
uhci_alloc_sqh(struct uhci_softc *sc)
{
- struct uhci_soft_qh *sqh;
+ struct uhci_soft_qh *sqh = NULL;
usbd_status err;
int i, offs;
struct usb_dma dma;
+ int s;
+ s = splusb();
if (sc->sc_freeqhs == NULL) {
DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n"));
err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK,
UHCI_QH_ALIGN, &dma);
if (err)
- return (0);
- for(i = 0; i < UHCI_SQH_CHUNK; i++) {
+ goto out;
+ for (i = 0; i < UHCI_SQH_CHUNK; i++) {
offs = i * UHCI_SQH_SIZE;
sqh = KERNADDR(&dma, offs);
sqh->physaddr = DMAADDR(&dma, offs);
@@ -1522,6 +1523,9 @@ uhci_alloc_sqh(struct uhci_softc *sc)
sqh = sc->sc_freeqhs;
sc->sc_freeqhs = sqh->hlink;
memset(&sqh->qh, 0, sizeof(struct uhci_qh));
+
+out:
+ splx(s);
return (sqh);
}