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/a764619d236b
branches: nick-nhusb
changeset: 804454:a764619d236b
user: skrll <skrll%NetBSD.org@localhost>
date: Tue Nov 10 08:44:09 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 uhci(4), fixes a bunch of locking bugs around the
*TD free lists, and plugs some memory leaks on error conditions.
diffstat:
sys/dev/usb/uhci.c | 966 ++++++++++++++++++++++++++++++++++---------------
sys/dev/usb/uhcivar.h | 30 +-
2 files changed, 693 insertions(+), 303 deletions(-)
diffs (truncated from 1520 to 300 lines):
diff -r 0f432677b2fa -r a764619d236b sys/dev/usb/uhci.c
--- a/sys/dev/usb/uhci.c Mon Nov 09 08:35:23 2015 +0000
+++ b/sys/dev/usb/uhci.c Tue Nov 10 08:44:09 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: uhci.c,v 1.264.4.54 2015/11/09 08:35:23 skrll Exp $ */
+/* $NetBSD: uhci.c,v 1.264.4.55 2015/11/10 08:44:09 skrll Exp $ */
/*
* Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc.
@@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.54 2015/11/09 08:35:23 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.55 2015/11/10 08:44:09 skrll Exp $");
#include "opt_usb.h"
@@ -139,20 +139,17 @@
struct {
uhci_soft_qh_t *sqh;
usb_dma_t reqdma;
- uhci_soft_td_t *setup, *stat;
- u_int length;
+ uhci_soft_td_t *setup;
+ uhci_soft_td_t *stat;
} ctrl;
/* Interrupt pipe */
struct {
int npoll;
- int isread;
uhci_soft_qh_t **qhs;
} intr;
/* Bulk pipe */
struct {
uhci_soft_qh_t *sqh;
- u_int length;
- int isread;
} bulk;
/* Isochronous pipe */
struct isoc {
@@ -168,6 +165,7 @@
Static usbd_status uhci_run(uhci_softc_t *, int, int);
Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *);
Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *);
+Static void uhci_free_std_locked(uhci_softc_t *, uhci_soft_td_t *);
Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *);
Static void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *);
#if 0
@@ -176,11 +174,15 @@
Static void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *);
#endif
-Static void uhci_free_std_chain(uhci_softc_t *,
- uhci_soft_td_t *, uhci_soft_td_t *);
-Static usbd_status uhci_alloc_std_chain(struct uhci_pipe *,
- uhci_softc_t *, int, int, uint16_t, usb_dma_t *,
- uhci_soft_td_t **, uhci_soft_td_t **);
+Static void uhci_free_std_chain(uhci_softc_t *, uhci_soft_td_t *,
+ uhci_soft_td_t *);
+Static usbd_status uhci_alloc_std_chain(uhci_softc_t *, struct usbd_xfer *,
+ int, int, uhci_soft_td_t **, uhci_soft_td_t **);
+Static void uhci_free_stds(uhci_softc_t *, struct uhci_xfer *);
+
+Static void uhci_reset_std_chain(uhci_softc_t *, struct usbd_xfer *,
+ int, int, int *, uhci_soft_td_t *, uhci_soft_td_t **);
+
Static void uhci_poll_hub(void *);
Static void uhci_waitintr(uhci_softc_t *, struct usbd_xfer *);
Static void uhci_check_intr(uhci_softc_t *, struct uhci_xfer *);
@@ -209,24 +211,32 @@
Static int uhci_roothub_ctrl(struct usbd_bus *,
usb_device_request_t *, void *, int);
+Static int uhci_device_ctrl_init(struct usbd_xfer *);
+Static void uhci_device_ctrl_fini(struct usbd_xfer *);
Static usbd_status uhci_device_ctrl_transfer(struct usbd_xfer *);
Static usbd_status uhci_device_ctrl_start(struct usbd_xfer *);
Static void uhci_device_ctrl_abort(struct usbd_xfer *);
Static void uhci_device_ctrl_close(struct usbd_pipe *);
Static void uhci_device_ctrl_done(struct usbd_xfer *);
+Static int uhci_device_intr_init(struct usbd_xfer *);
+Static void uhci_device_intr_fini(struct usbd_xfer *);
Static usbd_status uhci_device_intr_transfer(struct usbd_xfer *);
Static usbd_status uhci_device_intr_start(struct usbd_xfer *);
Static void uhci_device_intr_abort(struct usbd_xfer *);
Static void uhci_device_intr_close(struct usbd_pipe *);
Static void uhci_device_intr_done(struct usbd_xfer *);
+Static int uhci_device_bulk_init(struct usbd_xfer *);
+Static void uhci_device_bulk_fini(struct usbd_xfer *);
Static usbd_status uhci_device_bulk_transfer(struct usbd_xfer *);
Static usbd_status uhci_device_bulk_start(struct usbd_xfer *);
Static void uhci_device_bulk_abort(struct usbd_xfer *);
Static void uhci_device_bulk_close(struct usbd_pipe *);
Static void uhci_device_bulk_done(struct usbd_xfer *);
+Static int uhci_device_isoc_init(struct usbd_xfer *);
+Static void uhci_device_isoc_fini(struct usbd_xfer *);
Static usbd_status uhci_device_isoc_transfer(struct usbd_xfer *);
Static usbd_status uhci_device_isoc_start(struct usbd_xfer *);
Static void uhci_device_isoc_abort(struct usbd_xfer *);
@@ -332,6 +342,8 @@
};
const struct usbd_pipe_methods uhci_device_ctrl_methods = {
+ .upm_init = uhci_device_ctrl_init,
+ .upm_fini = uhci_device_ctrl_fini,
.upm_transfer = uhci_device_ctrl_transfer,
.upm_start = uhci_device_ctrl_start,
.upm_abort = uhci_device_ctrl_abort,
@@ -341,6 +353,8 @@
};
const struct usbd_pipe_methods uhci_device_intr_methods = {
+ .upm_init = uhci_device_intr_init,
+ .upm_fini = uhci_device_intr_fini,
.upm_transfer = uhci_device_intr_transfer,
.upm_start = uhci_device_intr_start,
.upm_abort = uhci_device_intr_abort,
@@ -350,6 +364,8 @@
};
const struct usbd_pipe_methods uhci_device_bulk_methods = {
+ .upm_init = uhci_device_bulk_init,
+ .upm_fini = uhci_device_bulk_fini,
.upm_transfer = uhci_device_bulk_transfer,
.upm_start = uhci_device_bulk_start,
.upm_abort = uhci_device_bulk_abort,
@@ -359,6 +375,8 @@
};
const struct usbd_pipe_methods uhci_device_isoc_methods = {
+ .upm_init = uhci_device_isoc_init,
+ .upm_fini = uhci_device_isoc_fini,
.upm_transfer = uhci_device_isoc_transfer,
.upm_start = uhci_device_isoc_start,
.upm_abort = uhci_device_isoc_abort,
@@ -438,6 +456,10 @@
UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */
UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/
+ /* Initialise mutex early for uhci_alloc_* */
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
+
/*
* Allocate a TD, inactive, that hangs from the last QH.
* This is to avoid a bug in the PIIX that makes it run berserk
@@ -457,7 +479,7 @@
/* Allocate the dummy QH marking the end and used for looping the QHs.*/
lsqh = uhci_alloc_sqh(sc);
if (lsqh == NULL)
- return ENOMEM;
+ goto fail1;
lsqh->hlink = NULL;
lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */
lsqh->elink = std;
@@ -469,7 +491,7 @@
/* Allocate the dummy QH where bulk traffic will be queued. */
bsqh = uhci_alloc_sqh(sc);
if (bsqh == NULL)
- return ENOMEM;
+ goto fail2;
bsqh->hlink = lsqh;
bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH);
bsqh->elink = NULL;
@@ -481,7 +503,7 @@
/* Allocate dummy QH where high speed control traffic will be queued. */
chsqh = uhci_alloc_sqh(sc);
if (chsqh == NULL)
- return ENOMEM;
+ goto fail3;
chsqh->hlink = bsqh;
chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH);
chsqh->elink = NULL;
@@ -493,7 +515,7 @@
/* Allocate dummy QH where control traffic will be queued. */
clsqh = uhci_alloc_sqh(sc);
if (clsqh == NULL)
- return ENOMEM;
+ goto fail4;
clsqh->hlink = chsqh;
clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH);
clsqh->elink = NULL;
@@ -546,8 +568,6 @@
callout_init(&sc->sc_poll_handle, CALLOUT_MPSAFE);
- mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
- mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
cv_init(&sc->sc_softwake_cv, "uhciab");
/* Set up the bus struct. */
@@ -563,6 +583,17 @@
UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */
return err;
+
+fail4:
+ uhci_free_sqh(sc, chsqh);
+fail3:
+ uhci_free_sqh(sc, lsqh);
+fail2:
+ uhci_free_sqh(sc, lsqh);
+fail1:
+ uhci_free_std(sc, std);
+
+ return ENOMEM;
}
int
@@ -1385,7 +1416,7 @@
void
uhci_check_intr(uhci_softc_t *sc, struct uhci_xfer *ux)
{
- uhci_soft_td_t *std, *lstd;
+ uhci_soft_td_t *std, *fstd = NULL, *lstd = NULL;
uint32_t status;
UHCIHIST_FUNC(); UHCIHIST_CALLED();
@@ -1400,9 +1431,23 @@
return;
}
- if (ux->ux_stdstart == NULL)
+ switch (ux->ux_type) {
+ case UX_CTRL:
+ fstd = ux->ux_setup;
+ lstd = ux->ux_stat;
+ break;
+ case UX_BULK:
+ case UX_INTR:
+ case UX_ISOC:
+ fstd = ux->ux_stdstart;
+ lstd = ux->ux_stdend;
+ break;
+ default:
+ KASSERT(false);
+ break;
+ }
+ if (fstd == NULL)
return;
- lstd = ux->ux_stdend;
KASSERT(lstd != NULL);
@@ -1432,7 +1477,7 @@
* short packet (SPD and not ACTIVE).
*/
DPRINTFN(12, "active ux=%p", ux, 0, 0, 0);
- for (std = ux->ux_stdstart; std != lstd; std = std->link.std) {
+ for (std = fstd; std != lstd; std = std->link.std) {
usb_syncmem(&std->dma,
std->offs + offsetof(uhci_td_t, td_status),
sizeof(std->td.td_status),
@@ -1457,10 +1502,8 @@
* If the data phase of a control transfer is short, we need
* to complete the status stage
*/
- usb_endpoint_descriptor_t *ed = xfer->ux_pipe->up_endpoint->ue_edesc;
- uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
-
- if ((status & UHCI_TD_SPD) && xfertype == UE_CONTROL) {
+
+ if ((status & UHCI_TD_SPD) && ux->ux_type == UX_CTRL) {
struct uhci_pipe *upipe =
UHCI_PIPE2UPIPE(xfer->ux_pipe);
uhci_soft_qh_t *sqh = upipe->ctrl.sqh;
@@ -1802,12 +1845,17 @@
UHCIHIST_FUNC(); UHCIHIST_CALLED();
+ 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, UHCI_STD_SIZE * UHCI_STD_CHUNK,
UHCI_TD_ALIGN, &dma);
if (err)
return NULL;
+
+ mutex_enter(&sc->sc_lock);
for (i = 0; i < UHCI_STD_CHUNK; i++) {
offs = i * UHCI_STD_SIZE;
std = KERNADDR(&dma, offs);
@@ -1820,25 +1868,40 @@
}
std = sc->sc_freetds;
sc->sc_freetds = std->link.std;
+ mutex_exit(&sc->sc_lock);
+
memset(&std->td, 0, sizeof(uhci_td_t));
+
return std;
}
+#define TD_IS_FREE 0x12345678
Home |
Main Index |
Thread Index |
Old Index