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@
-/* $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 $ */
/*
#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>
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);
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 *
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);
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);
}
-/* $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 $ */
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);
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);
}
-/* $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 $ */
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);
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);
}
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);
sqh = sc->sc_freeqhs;
sc->sc_freeqhs = sqh->hlink;
memset(&sqh->qh, 0, sizeof(struct uhci_qh));
+
+out:
+ splx(s);
return (sqh);
}