Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/nick-nhusb]: src/sys/dev/usb Restructure the xfer methods of ohci(4) so ...
details: https://anonhg.NetBSD.org/src/rev/fc7928a5b1ef
branches: nick-nhusb
changeset: 334328:fc7928a5b1ef
user: skrll <skrll%NetBSD.org@localhost>
date: Sun Dec 06 15:39:35 2015 +0000
description:
Restructure the xfer methods of ohci(4) so that minimal work in done in
softint context. Now all memory allocation is done in thread context.
Addresses kern/48308 for ohci(4), might fix some locking bugs around the
*TD free lists, and plugs some memory leaks on error conditions.
diffstat:
sys/dev/usb/ohci.c | 879 +++++++++++++++++++++++++++++++++++++------------
sys/dev/usb/ohcivar.h | 24 +-
2 files changed, 684 insertions(+), 219 deletions(-)
diffs (truncated from 1508 to 300 lines):
diff -r 3ca8bf9236c1 -r fc7928a5b1ef sys/dev/usb/ohci.c
--- a/sys/dev/usb/ohci.c Wed Dec 02 20:36:50 2015 +0000
+++ b/sys/dev/usb/ohci.c Sun Dec 06 15:39:35 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ohci.c,v 1.254.2.34 2015/12/02 20:36:50 skrll Exp $ */
+/* $NetBSD: ohci.c,v 1.254.2.35 2015/12/06 15:39:35 skrll Exp $ */
/*
* Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.34 2015/12/02 20:36:50 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.35 2015/12/06 15:39:35 skrll Exp $");
#include "opt_usb.h"
@@ -129,15 +129,19 @@
Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *);
Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *);
+Static void ohci_free_std_locked(ohci_softc_t *, ohci_soft_td_t *);
Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *);
Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *);
-
-Static void ohci_free_std_chain(ohci_softc_t *, ohci_soft_td_t *,
- ohci_soft_td_t *);
-Static usbd_status ohci_alloc_std_chain(struct ohci_pipe *,
- ohci_softc_t *, int, int, struct usbd_xfer *,
- ohci_soft_td_t *, ohci_soft_td_t **);
+Static void ohci_free_sitd_locked(ohci_softc_t *,
+ ohci_soft_itd_t *);
+
+Static usbd_status ohci_alloc_std_chain(ohci_softc_t *, struct usbd_xfer *,
+ int, int);
+Static void ohci_free_stds(ohci_softc_t *, struct ohci_xfer *);
+
+Static void ohci_reset_std_chain(ohci_softc_t *, struct usbd_xfer *,
+ int, int, ohci_soft_td_t *, ohci_soft_td_t **);
Static usbd_status ohci_open(struct usbd_pipe *);
Static void ohci_poll(struct usbd_bus *);
@@ -174,24 +178,32 @@
Static void ohci_root_intr_close(struct usbd_pipe *);
Static void ohci_root_intr_done(struct usbd_xfer *);
+Static int ohci_device_ctrl_init(struct usbd_xfer *);
+Static void ohci_device_ctrl_fini(struct usbd_xfer *);
Static usbd_status ohci_device_ctrl_transfer(struct usbd_xfer *);
Static usbd_status ohci_device_ctrl_start(struct usbd_xfer *);
Static void ohci_device_ctrl_abort(struct usbd_xfer *);
Static void ohci_device_ctrl_close(struct usbd_pipe *);
Static void ohci_device_ctrl_done(struct usbd_xfer *);
+Static int ohci_device_bulk_init(struct usbd_xfer *);
+Static void ohci_device_bulk_fini(struct usbd_xfer *);
Static usbd_status ohci_device_bulk_transfer(struct usbd_xfer *);
Static usbd_status ohci_device_bulk_start(struct usbd_xfer *);
Static void ohci_device_bulk_abort(struct usbd_xfer *);
Static void ohci_device_bulk_close(struct usbd_pipe *);
Static void ohci_device_bulk_done(struct usbd_xfer *);
+Static int ohci_device_intr_init(struct usbd_xfer *);
+Static void ohci_device_intr_fini(struct usbd_xfer *);
Static usbd_status ohci_device_intr_transfer(struct usbd_xfer *);
Static usbd_status ohci_device_intr_start(struct usbd_xfer *);
Static void ohci_device_intr_abort(struct usbd_xfer *);
Static void ohci_device_intr_close(struct usbd_pipe *);
Static void ohci_device_intr_done(struct usbd_xfer *);
+Static int ohci_device_isoc_init(struct usbd_xfer *);
+Static void ohci_device_isoc_fini(struct usbd_xfer *);
Static usbd_status ohci_device_isoc_transfer(struct usbd_xfer *);
Static usbd_status ohci_device_isoc_start(struct usbd_xfer *);
Static void ohci_device_isoc_abort(struct usbd_xfer *);
@@ -289,6 +301,8 @@
};
Static const struct usbd_pipe_methods ohci_device_ctrl_methods = {
+ .upm_init = ohci_device_ctrl_init,
+ .upm_fini = ohci_device_ctrl_fini,
.upm_transfer = ohci_device_ctrl_transfer,
.upm_start = ohci_device_ctrl_start,
.upm_abort = ohci_device_ctrl_abort,
@@ -298,6 +312,8 @@
};
Static const struct usbd_pipe_methods ohci_device_intr_methods = {
+ .upm_init = ohci_device_intr_init,
+ .upm_fini = ohci_device_intr_fini,
.upm_transfer = ohci_device_intr_transfer,
.upm_start = ohci_device_intr_start,
.upm_abort = ohci_device_intr_abort,
@@ -307,6 +323,8 @@
};
Static const struct usbd_pipe_methods ohci_device_bulk_methods = {
+ .upm_init = ohci_device_bulk_init,
+ .upm_fini = ohci_device_bulk_fini,
.upm_transfer = ohci_device_bulk_transfer,
.upm_start = ohci_device_bulk_start,
.upm_abort = ohci_device_bulk_abort,
@@ -316,6 +334,8 @@
};
Static const struct usbd_pipe_methods ohci_device_isoc_methods = {
+ .upm_init = ohci_device_isoc_init,
+ .upm_fini = ohci_device_isoc_fini,
.upm_transfer = ohci_device_isoc_transfer,
.upm_start = ohci_device_isoc_start,
.upm_abort = ohci_device_isoc_abort,
@@ -387,12 +407,17 @@
OHCIHIST_FUNC(); OHCIHIST_CALLED();
+ mutex_enter(&sc->sc_lock);
if (sc->sc_freeeds == NULL) {
DPRINTFN(2, "allocating chunk", 0, 0, 0, 0);
+ mutex_exit(&sc->sc_lock);
+
err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK,
OHCI_ED_ALIGN, &dma);
if (err)
return 0;
+
+ mutex_enter(&sc->sc_lock);
for (i = 0; i < OHCI_SED_CHUNK; i++) {
offs = i * OHCI_SED_SIZE;
sed = KERNADDR(&dma, offs);
@@ -405,16 +430,30 @@
}
sed = sc->sc_freeeds;
sc->sc_freeeds = sed->next;
+ mutex_exit(&sc->sc_lock);
+
memset(&sed->ed, 0, sizeof(ohci_ed_t));
sed->next = 0;
return sed;
}
+static inline void
+ohci_free_sed_locked(ohci_softc_t *sc, ohci_soft_ed_t *sed)
+{
+
+ KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+ sed->next = sc->sc_freeeds;
+ sc->sc_freeeds = sed;
+}
+
void
ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed)
{
- sed->next = sc->sc_freeeds;
- sc->sc_freeeds = sed;
+
+ mutex_enter(&sc->sc_lock);
+ ohci_free_sed_locked(sc, sed);
+ mutex_exit(&sc->sc_lock);
}
ohci_soft_td_t *
@@ -427,14 +466,17 @@
OHCIHIST_FUNC(); OHCIHIST_CALLED();
- KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
-
+ mutex_enter(&sc->sc_lock);
if (sc->sc_freetds == NULL) {
DPRINTFN(2, "allocating chunk", 0, 0, 0, 0);
+ mutex_exit(&sc->sc_lock);
+
err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK,
OHCI_TD_ALIGN, &dma);
if (err)
return NULL;
+
+ mutex_enter(&sc->sc_lock);
for(i = 0; i < OHCI_STD_CHUNK; i++) {
offs = i * OHCI_STD_SIZE;
std = KERNADDR(&dma, offs);
@@ -448,59 +490,79 @@
std = sc->sc_freetds;
sc->sc_freetds = std->nexttd;
+ mutex_exit(&sc->sc_lock);
+
memset(&std->td, 0, sizeof(ohci_td_t));
std->nexttd = NULL;
std->xfer = NULL;
- ohci_hash_add_td(sc, std);
return std;
}
void
+ohci_free_std_locked(ohci_softc_t *sc, ohci_soft_td_t *std)
+{
+
+ KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+ std->nexttd = sc->sc_freetds;
+ sc->sc_freetds = std;
+}
+
+void
ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std)
{
- KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
-
- ohci_hash_rem_td(sc, std);
- std->nexttd = sc->sc_freetds;
- sc->sc_freetds = std;
+ mutex_enter(&sc->sc_lock);
+ ohci_free_std_locked(sc, std);
+ mutex_exit(&sc->sc_lock);
}
-usbd_status
-ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
- int alen, int rd, struct usbd_xfer *xfer,
- ohci_soft_td_t *sp, ohci_soft_td_t **ep)
+Static usbd_status
+ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int alen, int rd)
{
+ struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer);
+ struct usbd_pipe *pipe = xfer->ux_pipe;
ohci_soft_td_t *next, *cur;
ohci_physaddr_t dataphys, dataphysend;
uint32_t tdflags;
- int len, curlen;
+ int len = alen;
+ int curlen;
usb_dma_t *dma = &xfer->ux_dmabuf;
uint16_t flags = xfer->ux_flags;
OHCIHIST_FUNC(); OHCIHIST_CALLED();
- DPRINTF("start len=%d", alen, 0, 0, 0);
-
- KASSERT(mutex_owned(&sc->sc_lock));
DPRINTFN(8, "addr=%d endpt=%d len=%d speed=%d",
- opipe->pipe.up_dev->ud_addr,
- UE_GET_ADDR(opipe->pipe.up_endpoint->ue_edesc->bEndpointAddress),
- alen, opipe->pipe.up_dev->ud_speed);
+ pipe->up_dev->ud_addr,
+ UE_GET_ADDR(pipe->up_endpoint->ue_edesc->bEndpointAddress),
+ alen, pipe->up_dev->ud_speed);
+
+ ASSERT_SLEEPABLE();
+
+ size_t nstd = (flags & USBD_FORCE_SHORT_XFER) ? 1 : 0;
+ nstd += ((len + OHCI_PAGE_SIZE - 1) / OHCI_PAGE_SIZE);
+ ox->ox_stds = kmem_zalloc(sizeof(ohci_soft_td_t *) * nstd,
+ KM_SLEEP);
+ ox->ox_nstd = nstd;
+ int mps = UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize);
+
+ DPRINTFN(8, "xfer %p nstd %d mps %d", xfer, nstd, mps, 0);
len = alen;
- cur = sp;
+ cur = ohci_alloc_std(sc);
+ if (cur == NULL)
+ goto nomem;
+
dataphys = DMAADDR(dma, 0);
dataphysend = OHCI_PAGE(dataphys + len - 1);
- usb_syncmem(dma, 0, len,
- rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
tdflags = HTOO32(
(rd ? OHCI_TD_IN : OHCI_TD_OUT) |
(flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) |
OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR);
- for (;;) {
+ for (size_t j = 0;;) {
+ ox->ox_stds[j++] = cur;
next = ohci_alloc_std(sc);
if (next == NULL)
goto nomem;
@@ -515,7 +577,7 @@
curlen = 2 * OHCI_PAGE_SIZE -
(dataphys & (OHCI_PAGE_SIZE-1));
/* the length must be a multiple of the max size */
- curlen -= curlen % UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize);
+ curlen -= curlen % mps;
KASSERT(curlen != 0);
}
DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x "
@@ -530,8 +592,7 @@
cur->len = curlen;
cur->flags = OHCI_ADD_LEN;
cur->xfer = xfer;
- usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td),
- BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
Home |
Main Index |
Thread Index |
Old Index