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 so that (close...
details: https://anonhg.NetBSD.org/src/rev/b37a4a99edbf
branches: nick-nhusb
changeset: 334291:b37a4a99edbf
user: skrll <skrll%NetBSD.org@localhost>
date: Sun Oct 25 09:50:06 2015 +0000
description:
Restructure the xfer methods so that (close to) minimal work in done in softint
context. Now all memory allocation is done in thread context.
Addresses kern/48308 for ehci(4), fixes a bunch of locking bugs around the
*TD free lists, and plugs some memory leaks on error conditions.
XXX revisit for isoc caching models (4.7.2.1)
diffstat:
sys/dev/usb/ehci.c | 1685 ++++++++++++++++++++++++++++++------------------
sys/dev/usb/ehcivar.h | 27 +-
2 files changed, 1062 insertions(+), 650 deletions(-)
diffs (truncated from 2622 to 300 lines):
diff -r c273b99be3b1 -r b37a4a99edbf sys/dev/usb/ehci.c
--- a/sys/dev/usb/ehci.c Sun Oct 25 09:28:41 2015 +0000
+++ b/sys/dev/usb/ehci.c Sun Oct 25 09:50:06 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ehci.c,v 1.234.2.63 2015/10/25 09:28:41 skrll Exp $ */
+/* $NetBSD: ehci.c,v 1.234.2.64 2015/10/25 09:50:06 skrll Exp $ */
/*
* Copyright (c) 2004-2012 The NetBSD Foundation, Inc.
@@ -53,7 +53,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.63 2015/10/25 09:28:41 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.64 2015/10/25 09:50:06 skrll Exp $");
#include "ohci.h"
#include "uhci.h"
@@ -167,6 +167,7 @@
Static struct usbd_xfer *
ehci_allocx(struct usbd_bus *, unsigned int);
Static void ehci_freex(struct usbd_bus *, struct usbd_xfer *);
+
Static void ehci_get_lock(struct usbd_bus *, kmutex_t **);
Static int ehci_roothub_ctrl(struct usbd_bus *,
usb_device_request_t *, void *, int);
@@ -177,30 +178,40 @@
Static void ehci_root_intr_close(struct usbd_pipe *);
Static void ehci_root_intr_done(struct usbd_xfer *);
+Static int ehci_device_ctrl_init(struct usbd_xfer *);
+Static void ehci_device_ctrl_fini(struct usbd_xfer *);
Static usbd_status ehci_device_ctrl_transfer(struct usbd_xfer *);
Static usbd_status ehci_device_ctrl_start(struct usbd_xfer *);
Static void ehci_device_ctrl_abort(struct usbd_xfer *);
Static void ehci_device_ctrl_close(struct usbd_pipe *);
Static void ehci_device_ctrl_done(struct usbd_xfer *);
+Static int ehci_device_bulk_init(struct usbd_xfer *);
+Static void ehci_device_bulk_fini(struct usbd_xfer *);
Static usbd_status ehci_device_bulk_transfer(struct usbd_xfer *);
Static usbd_status ehci_device_bulk_start(struct usbd_xfer *);
Static void ehci_device_bulk_abort(struct usbd_xfer *);
Static void ehci_device_bulk_close(struct usbd_pipe *);
Static void ehci_device_bulk_done(struct usbd_xfer *);
+Static int ehci_device_intr_init(struct usbd_xfer *);
+Static void ehci_device_intr_fini(struct usbd_xfer *);
Static usbd_status ehci_device_intr_transfer(struct usbd_xfer *);
Static usbd_status ehci_device_intr_start(struct usbd_xfer *);
Static void ehci_device_intr_abort(struct usbd_xfer *);
Static void ehci_device_intr_close(struct usbd_pipe *);
Static void ehci_device_intr_done(struct usbd_xfer *);
+Static int ehci_device_isoc_init(struct usbd_xfer *);
+Static void ehci_device_isoc_fini(struct usbd_xfer *);
Static usbd_status ehci_device_isoc_transfer(struct usbd_xfer *);
Static usbd_status ehci_device_isoc_start(struct usbd_xfer *);
Static void ehci_device_isoc_abort(struct usbd_xfer *);
Static void ehci_device_isoc_close(struct usbd_pipe *);
Static void ehci_device_isoc_done(struct usbd_xfer *);
+Static int ehci_device_fs_isoc_init(struct usbd_xfer *);
+Static void ehci_device_fs_isoc_fini(struct usbd_xfer *);
Static usbd_status ehci_device_fs_isoc_transfer(struct usbd_xfer *);
Static usbd_status ehci_device_fs_isoc_start(struct usbd_xfer *);
Static void ehci_device_fs_isoc_abort(struct usbd_xfer *);
@@ -217,25 +228,37 @@
Static ehci_soft_qtd_t *ehci_alloc_sqtd(ehci_softc_t *);
Static void ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *);
-Static usbd_status ehci_alloc_sqtd_chain(struct ehci_pipe *,
- ehci_softc_t *, int, int, struct usbd_xfer *,
- ehci_soft_qtd_t **, ehci_soft_qtd_t **);
-Static void ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qtd_t *,
- ehci_soft_qtd_t *);
+Static usbd_status ehci_alloc_sqtd_chain(ehci_softc_t *, struct usbd_xfer *,
+ int, int, ehci_soft_qtd_t **, ehci_soft_qtd_t **);
+Static void ehci_free_sqtds(ehci_softc_t *, struct ehci_xfer *);
+
+Static void ehci_reset_sqtd_chain(ehci_softc_t *, struct usbd_xfer *,
+ int, int, int *, ehci_soft_qtd_t *, ehci_soft_qtd_t **);
Static ehci_soft_itd_t *ehci_alloc_itd(ehci_softc_t *);
Static ehci_soft_sitd_t *
ehci_alloc_sitd(ehci_softc_t *);
-Static void ehci_free_itd(ehci_softc_t *, ehci_soft_itd_t *);
-Static void ehci_free_sitd(ehci_softc_t *, ehci_soft_sitd_t *);
-Static void ehci_rem_free_itd_chain(ehci_softc_t *,
- struct ehci_xfer *);
-Static void ehci_rem_free_sitd_chain(ehci_softc_t *,
- struct ehci_xfer *);
-Static void ehci_abort_isoc_xfer(struct usbd_xfer *,
- usbd_status);
-
-Static usbd_status ehci_device_request(struct usbd_xfer *);
+
+Static void ehci_remove_itd_chain(ehci_softc_t *, ehci_soft_itd_t *);
+Static void ehci_remove_sitd_chain(ehci_softc_t *, ehci_soft_sitd_t *);
+Static void ehci_free_itd_chain(ehci_softc_t *, ehci_soft_itd_t *);
+Static void ehci_free_sitd_chain(ehci_softc_t *, ehci_soft_sitd_t *);
+
+static inline void
+ehci_free_itd_locked(ehci_softc_t *sc, ehci_soft_itd_t *itd)
+{
+
+ LIST_INSERT_HEAD(&sc->sc_freeitds, itd, free_list);
+}
+
+static inline void
+ehci_free_sitd_locked(ehci_softc_t *sc, ehci_soft_sitd_t *sitd)
+{
+
+ LIST_INSERT_HEAD(&sc->sc_freesitds, sitd, free_list);
+}
+
+Static void ehci_abort_isoc_xfer(struct usbd_xfer *, usbd_status);
Static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *,
int);
@@ -262,6 +285,7 @@
Static void ehci_dump_qtd(ehci_qtd_t *);
Static void ehci_dump_sqh(ehci_soft_qh_t *);
Static void ehci_dump_sitd(struct ehci_soft_itd *);
+Static void ehci_dump_itds(ehci_soft_itd_t *);
Static void ehci_dump_itd(struct ehci_soft_itd *);
Static void ehci_dump_exfer(struct ehci_xfer *);
#endif
@@ -297,6 +321,8 @@
};
Static const struct usbd_pipe_methods ehci_device_ctrl_methods = {
+ .upm_init = ehci_device_ctrl_init,
+ .upm_fini = ehci_device_ctrl_fini,
.upm_transfer = ehci_device_ctrl_transfer,
.upm_start = ehci_device_ctrl_start,
.upm_abort = ehci_device_ctrl_abort,
@@ -306,6 +332,8 @@
};
Static const struct usbd_pipe_methods ehci_device_intr_methods = {
+ .upm_init = ehci_device_intr_init,
+ .upm_fini = ehci_device_intr_fini,
.upm_transfer = ehci_device_intr_transfer,
.upm_start = ehci_device_intr_start,
.upm_abort = ehci_device_intr_abort,
@@ -315,6 +343,8 @@
};
Static const struct usbd_pipe_methods ehci_device_bulk_methods = {
+ .upm_init = ehci_device_bulk_init,
+ .upm_fini = ehci_device_bulk_fini,
.upm_transfer = ehci_device_bulk_transfer,
.upm_start = ehci_device_bulk_start,
.upm_abort = ehci_device_bulk_abort,
@@ -324,6 +354,8 @@
};
Static const struct usbd_pipe_methods ehci_device_isoc_methods = {
+ .upm_init = ehci_device_isoc_init,
+ .upm_fini = ehci_device_isoc_fini,
.upm_transfer = ehci_device_isoc_transfer,
.upm_start = ehci_device_isoc_start,
.upm_abort = ehci_device_isoc_abort,
@@ -333,6 +365,8 @@
};
Static const struct usbd_pipe_methods ehci_device_fs_isoc_methods = {
+ .upm_init = ehci_device_fs_isoc_init,
+ .upm_fini = ehci_device_fs_isoc_fini,
.upm_transfer = ehci_device_fs_isoc_transfer,
.upm_start = ehci_device_fs_isoc_start,
.upm_abort = ehci_device_fs_isoc_abort,
@@ -783,22 +817,27 @@
Static void
ehci_check_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
{
- struct usbd_device *dev = ex->ex_xfer.ux_pipe->up_dev;
- int attr;
USBHIST_FUNC(); USBHIST_CALLED(ehcidebug);
USBHIST_LOG(ehcidebug, "ex = %p", ex, 0, 0, 0);
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
- attr = ex->ex_xfer.ux_pipe->up_endpoint->ue_edesc->bmAttributes;
- if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS) {
- if (dev->ud_speed == USB_SPEED_HIGH)
- ehci_check_itd_intr(sc, ex);
- else
- ehci_check_sitd_intr(sc, ex);
- } else
+ switch (ex->ex_type) {
+ case EX_CTRL:
+ case EX_BULK:
+ case EX_INTR:
ehci_check_qh_intr(sc, ex);
+ break;
+ case EX_ISOC:
+ ehci_check_itd_intr(sc, ex);
+ break;
+ case EX_FS_ISOC:
+ ehci_check_sitd_intr(sc, ex);
+ break;
+ default:
+ KASSERT(false);
+ }
return;
}
@@ -806,25 +845,23 @@
Static void
ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
{
- ehci_soft_qtd_t *sqtd, *lsqtd;
+ ehci_soft_qtd_t *sqtd, *fsqtd, *lsqtd;
uint32_t status;
USBHIST_FUNC(); USBHIST_CALLED(ehcidebug);
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
- if (ex->ex_sqtdstart == NULL) {
- printf("ehci_check_qh_intr: not valid sqtd\n");
- return;
+ if (ex->ex_type == EX_CTRL) {
+ fsqtd = ex->ex_setup;
+ lsqtd = ex->ex_status;
+ } else {
+ fsqtd = ex->ex_sqtdstart;
+ lsqtd = ex->ex_sqtdend;
}
-
- lsqtd = ex->ex_sqtdend;
-#ifdef DIAGNOSTIC
- if (lsqtd == NULL) {
- printf("ehci_check_qh_intr: lsqtd==0\n");
- return;
- }
-#endif
+ KASSERTMSG(fsqtd != NULL && lsqtd != NULL,
+ "xfer %p xt %d fsqtd %p lsqtd %p", ex, ex->ex_type, fsqtd, lsqtd);
+
/*
* If the last TD is still active we need to check whether there
* is an error somewhere in the middle, or whether there was a
@@ -840,8 +877,7 @@
sizeof(lsqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD);
if (status & EHCI_QTD_ACTIVE) {
USBHIST_LOGN(ehcidebug, 10, "active ex=%p", ex, 0, 0, 0);
- for (sqtd = ex->ex_sqtdstart; sqtd != lsqtd;
- sqtd = sqtd->nextqtd) {
+ for (sqtd = fsqtd; sqtd != lsqtd; sqtd = sqtd->nextqtd) {
usb_syncmem(&sqtd->dma,
sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
sizeof(sqtd->qtd.qtd_status),
@@ -858,11 +894,6 @@
goto done;
/* Handle short packets */
if (EHCI_QTD_GET_BYTES(status) != 0) {
- struct usbd_pipe *pipe = ex->ex_xfer.ux_pipe;
- usb_endpoint_descriptor_t *ed =
- pipe->up_endpoint->ue_edesc;
- uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes);
-
/*
* If we get here for a control transfer then
* we need to let the hardware complete the
@@ -871,7 +902,7 @@
*
* Otherwise, we're done.
*/
- if (xt == UE_CONTROL) {
+ if (ex->ex_type == EX_CTRL) {
break;
}
goto done;
@@ -907,18 +938,10 @@
if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue))
return;
- if (ex->ex_itdstart == NULL) {
- printf("ehci_check_itd_intr: not valid itd\n");
- return;
- }
+ KASSERTMSG(ex->ex_itdstart != NULL && ex->ex_itdend != NULL,
+ "xfer %p fitd %p litd %p", ex, ex->ex_itdstart, ex->ex_itdend);
itd = ex->ex_itdend;
-#ifdef DIAGNOSTIC
- if (itd == NULL) {
- printf("ehci_check_itd_intr: itdend == 0\n");
- return;
- }
-#endif
/*
* check no active transfers in last itd, meaning we're finished
@@ -961,18 +984,10 @@
if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue))
Home |
Main Index |
Thread Index |
Old Index