summaryrefslogtreecommitdiff
path: root/sys/dev
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 /sys/dev
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@
Diffstat (limited to 'sys/dev')
-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);
}