Implement what in Intel-speech is known as "bandwidth reclamation".
It means that we continously poll USB devices that have a pending transfer instead of polling just once every ms. This speeds up some transfers at the expense of using more PCI bandwidth.
This commit is contained in:
parent
d2e1f953ef
commit
4f325f2674
@ -6,9 +6,6 @@ High priority:
|
||||
|
||||
On a short control transfer the status phase needs to be executed anyway.
|
||||
|
||||
Do bandwidth reclamation while we have outstanding bulk transfers.
|
||||
(Use an inactive TD on last QH to avoid PIIX bug.)
|
||||
|
||||
Allow interrupt out endpoints. (USB 1.1)
|
||||
|
||||
Fix flow control in ucom (copy from com driver).
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: uhci.c,v 1.122 2000/08/08 19:51:47 tv Exp $ */
|
||||
/* $NetBSD: uhci.c,v 1.123 2000/08/13 16:18:09 augustss Exp $ */
|
||||
/* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */
|
||||
|
||||
/*
|
||||
@ -158,9 +158,9 @@ Static void uhci_busreset(uhci_softc_t *);
|
||||
Static void uhci_shutdown(void *v);
|
||||
Static void uhci_power(int, void *);
|
||||
Static usbd_status uhci_run(uhci_softc_t *, int run);
|
||||
Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *);
|
||||
Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *);
|
||||
Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *);
|
||||
Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_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
|
||||
Static void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *,
|
||||
@ -181,11 +181,15 @@ Static void uhci_idone(uhci_intr_info_t *);
|
||||
Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status);
|
||||
|
||||
Static void uhci_timeout(void *);
|
||||
Static void uhci_add_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
|
||||
Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
|
||||
Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
|
||||
Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *);
|
||||
Static void uhci_remove_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
|
||||
Static void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
|
||||
Static void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
|
||||
Static void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *);
|
||||
Static int uhci_str(usb_string_descriptor_t *, int, char *);
|
||||
Static void uhci_add_loop(uhci_softc_t *sc);
|
||||
Static void uhci_rem_loop(uhci_softc_t *sc);
|
||||
|
||||
Static usbd_status uhci_setup_isoc(usbd_pipe_handle pipe);
|
||||
Static void uhci_device_isoc_enter(usbd_xfer_handle);
|
||||
@ -379,7 +383,7 @@ uhci_init(uhci_softc_t *sc)
|
||||
{
|
||||
usbd_status err;
|
||||
int i, j;
|
||||
uhci_soft_qh_t *csqh, *bsqh, *sqh;
|
||||
uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh;
|
||||
uhci_soft_td_t *std;
|
||||
|
||||
DPRINTFN(1,("uhci_init: start\n"));
|
||||
@ -406,25 +410,59 @@ uhci_init(uhci_softc_t *sc)
|
||||
UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */
|
||||
UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma)); /* set frame list*/
|
||||
|
||||
/*
|
||||
* Allocate a TD, inactive, that hangs from the last QH.
|
||||
* This is to avoid a bug in the PIIX that makes it run berserk
|
||||
* otherwise.
|
||||
*/
|
||||
std = uhci_alloc_std(sc);
|
||||
if (std == NULL)
|
||||
return (USBD_NOMEM);
|
||||
std->link.std = NULL;
|
||||
std->td.td_link = htole32(UHCI_PTR_T);
|
||||
std->td.td_status = htole32(0); /* inactive */
|
||||
std->td.td_token = htole32(0);
|
||||
std->td.td_buffer = htole32(0);
|
||||
|
||||
/* Allocate the dummy QH marking the end and used for looping the QHs.*/
|
||||
lsqh = uhci_alloc_sqh(sc);
|
||||
if (lsqh == NULL)
|
||||
return (USBD_NOMEM);
|
||||
lsqh->hlink = NULL;
|
||||
lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */
|
||||
lsqh->elink = std;
|
||||
lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD);
|
||||
sc->sc_last_qh = lsqh;
|
||||
|
||||
/* Allocate the dummy QH where bulk traffic will be queued. */
|
||||
bsqh = uhci_alloc_sqh(sc);
|
||||
if (bsqh == NULL)
|
||||
return (USBD_NOMEM);
|
||||
bsqh->hlink = NULL;
|
||||
bsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */
|
||||
bsqh->hlink = lsqh;
|
||||
bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH);
|
||||
bsqh->elink = NULL;
|
||||
bsqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
||||
sc->sc_bulk_start = sc->sc_bulk_end = bsqh;
|
||||
|
||||
/* Allocate the dummy QH where control traffic will be queued. */
|
||||
csqh = uhci_alloc_sqh(sc);
|
||||
if (csqh == NULL)
|
||||
/* Allocate dummy QH where high speed control traffic will be queued. */
|
||||
chsqh = uhci_alloc_sqh(sc);
|
||||
if (chsqh == NULL)
|
||||
return (USBD_NOMEM);
|
||||
csqh->hlink = bsqh;
|
||||
csqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH);
|
||||
csqh->elink = NULL;
|
||||
csqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
||||
sc->sc_ctl_start = sc->sc_ctl_end = csqh;
|
||||
chsqh->hlink = bsqh;
|
||||
chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH);
|
||||
chsqh->elink = NULL;
|
||||
chsqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
||||
sc->sc_hctl_start = sc->sc_hctl_end = chsqh;
|
||||
|
||||
/* Allocate dummy QH where control traffic will be queued. */
|
||||
clsqh = uhci_alloc_sqh(sc);
|
||||
if (clsqh == NULL)
|
||||
return (USBD_NOMEM);
|
||||
clsqh->hlink = bsqh;
|
||||
clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH);
|
||||
clsqh->elink = NULL;
|
||||
clsqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
||||
sc->sc_lctl_start = sc->sc_lctl_end = clsqh;
|
||||
|
||||
/*
|
||||
* Make all (virtual) frame list pointers point to the interrupt
|
||||
@ -441,8 +479,8 @@ uhci_init(uhci_softc_t *sc)
|
||||
std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
|
||||
std->td.td_token = htole32(0);
|
||||
std->td.td_buffer = htole32(0);
|
||||
sqh->hlink = csqh;
|
||||
sqh->qh.qh_hlink = htole32(csqh->physaddr | UHCI_PTR_QH);
|
||||
sqh->hlink = clsqh;
|
||||
sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH);
|
||||
sqh->elink = NULL;
|
||||
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
|
||||
sc->sc_vframes[i].htd = std;
|
||||
@ -777,7 +815,7 @@ uhci_dump_all(uhci_softc_t *sc)
|
||||
uhci_dumpregs(sc);
|
||||
printf("intrs=%d\n", sc->sc_bus.no_intrs);
|
||||
/*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/
|
||||
uhci_dump_qh(sc->sc_ctl_start);
|
||||
uhci_dump_qh(sc->sc_lctl_start);
|
||||
}
|
||||
|
||||
|
||||
@ -931,37 +969,96 @@ uhci_root_ctrl_done(usbd_xfer_handle xfer)
|
||||
{
|
||||
}
|
||||
|
||||
/* Add control QH, called at splusb(). */
|
||||
/*
|
||||
* Let the last QH loop back to the high speed control transfer QH.
|
||||
* This is what intel calls "bandwidth reclamation" and improves
|
||||
* USB performance a lot for some devices.
|
||||
* If we are already looping, just count it.
|
||||
*/
|
||||
void
|
||||
uhci_add_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
||||
uhci_add_loop(uhci_softc_t *sc) {
|
||||
if (++sc->sc_loops == 1) {
|
||||
DPRINTFN(10,("uhci_start_loop: add\n"));
|
||||
/* Note, we don't loop back the soft pointer. */
|
||||
sc->sc_last_qh->qh.qh_hlink =
|
||||
htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uhci_rem_loop(uhci_softc_t *sc) {
|
||||
if (--sc->sc_loops == 0) {
|
||||
DPRINTFN(5,("uhci_end_loop: remove\n"));
|
||||
sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add high speed control QH, called at splusb(). */
|
||||
void
|
||||
uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
||||
{
|
||||
uhci_soft_qh_t *eqh;
|
||||
|
||||
SPLUSBCHECK;
|
||||
|
||||
DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh));
|
||||
eqh = sc->sc_ctl_end;
|
||||
eqh = sc->sc_hctl_end;
|
||||
sqh->hlink = eqh->hlink;
|
||||
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
|
||||
eqh->hlink = sqh;
|
||||
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
|
||||
sc->sc_ctl_end = sqh;
|
||||
sc->sc_hctl_end = sqh;
|
||||
uhci_add_loop(sc);
|
||||
}
|
||||
|
||||
/* Remove control QH, called at splusb(). */
|
||||
/* Remove high speed control QH, called at splusb(). */
|
||||
void
|
||||
uhci_remove_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
||||
uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
||||
{
|
||||
uhci_soft_qh_t *pqh;
|
||||
|
||||
SPLUSBCHECK;
|
||||
|
||||
DPRINTFN(10, ("uhci_remove_ctrl: sqh=%p\n", sqh));
|
||||
pqh = uhci_find_prev_qh(sc->sc_ctl_start, sqh);
|
||||
DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh));
|
||||
uhci_rem_loop(sc);
|
||||
pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh);
|
||||
pqh->hlink = sqh->hlink;
|
||||
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
|
||||
if (sc->sc_ctl_end == sqh)
|
||||
sc->sc_ctl_end = pqh;
|
||||
if (sc->sc_hctl_end == sqh)
|
||||
sc->sc_hctl_end = pqh;
|
||||
}
|
||||
|
||||
/* Add low speed control QH, called at splusb(). */
|
||||
void
|
||||
uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
||||
{
|
||||
uhci_soft_qh_t *eqh;
|
||||
|
||||
SPLUSBCHECK;
|
||||
|
||||
DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh));
|
||||
eqh = sc->sc_lctl_end;
|
||||
sqh->hlink = eqh->hlink;
|
||||
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
|
||||
eqh->hlink = sqh;
|
||||
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
|
||||
sc->sc_lctl_end = sqh;
|
||||
}
|
||||
|
||||
/* Remove low speed control QH, called at splusb(). */
|
||||
void
|
||||
uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
||||
{
|
||||
uhci_soft_qh_t *pqh;
|
||||
|
||||
SPLUSBCHECK;
|
||||
|
||||
DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh));
|
||||
pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh);
|
||||
pqh->hlink = sqh->hlink;
|
||||
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
|
||||
if (sc->sc_lctl_end == sqh)
|
||||
sc->sc_lctl_end = pqh;
|
||||
}
|
||||
|
||||
/* Add bulk QH, called at splusb(). */
|
||||
@ -979,6 +1076,7 @@ uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
||||
eqh->hlink = sqh;
|
||||
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
|
||||
sc->sc_bulk_end = sqh;
|
||||
uhci_add_loop(sc);
|
||||
}
|
||||
|
||||
/* Remove bulk QH, called at splusb(). */
|
||||
@ -990,6 +1088,7 @@ uhci_remove_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
|
||||
SPLUSBCHECK;
|
||||
|
||||
DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh));
|
||||
uhci_rem_loop(sc);
|
||||
pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh);
|
||||
pqh->hlink = sqh->hlink;
|
||||
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
|
||||
@ -2004,7 +2103,10 @@ uhci_device_request(usbd_xfer_handle xfer)
|
||||
sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
|
||||
|
||||
s = splusb();
|
||||
uhci_add_ctrl(sc, sqh);
|
||||
if (dev->lowspeed)
|
||||
uhci_add_ls_ctrl(sc, sqh);
|
||||
else
|
||||
uhci_add_hs_ctrl(sc, sqh);
|
||||
uhci_add_intr_info(sc, ii);
|
||||
#ifdef UHCI_DEBUG
|
||||
if (uhcidebug > 12) {
|
||||
@ -2441,7 +2543,10 @@ uhci_device_ctrl_done(usbd_xfer_handle xfer)
|
||||
|
||||
uhci_del_intr_info(ii); /* remove from active list */
|
||||
|
||||
uhci_remove_ctrl(sc, upipe->u.ctl.sqh);
|
||||
if (upipe->pipe.device->lowspeed)
|
||||
uhci_remove_ls_ctrl(sc, upipe->u.ctl.sqh);
|
||||
else
|
||||
uhci_remove_hs_ctrl(sc, upipe->u.ctl.sqh);
|
||||
|
||||
if (upipe->u.ctl.length != 0)
|
||||
uhci_free_std_chain(sc, ii->stdstart->link.std, ii->stdend);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: uhcivar.h,v 1.31 2000/06/01 14:28:59 augustss Exp $ */
|
||||
/* $NetBSD: uhcivar.h,v 1.32 2000/08/13 16:18:09 augustss Exp $ */
|
||||
/* $FreeBSD: src/sys/dev/usb/uhcivar.h,v 1.14 1999/11/17 22:33:42 n_hibma Exp $ */
|
||||
|
||||
/*
|
||||
@ -140,10 +140,14 @@ typedef struct uhci_softc {
|
||||
usb_dma_t sc_dma;
|
||||
struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT];
|
||||
|
||||
uhci_soft_qh_t *sc_ctl_start; /* dummy QH for control */
|
||||
uhci_soft_qh_t *sc_ctl_end; /* last control QH */
|
||||
uhci_soft_qh_t *sc_lctl_start; /* dummy QH for low speed control */
|
||||
uhci_soft_qh_t *sc_lctl_end; /* last control QH */
|
||||
uhci_soft_qh_t *sc_hctl_start; /* dummy QH for high speed control */
|
||||
uhci_soft_qh_t *sc_hctl_end; /* last control QH */
|
||||
uhci_soft_qh_t *sc_bulk_start; /* dummy QH for bulk */
|
||||
uhci_soft_qh_t *sc_bulk_end; /* last bulk transfer */
|
||||
uhci_soft_qh_t *sc_last_qh; /* dummy QH at the end */
|
||||
u_int32_t sc_loops; /* number of QHs that wants looping */
|
||||
|
||||
uhci_soft_td_t *sc_freetds; /* TD free list */
|
||||
uhci_soft_qh_t *sc_freeqhs; /* QH free list */
|
||||
|
Loading…
x
Reference in New Issue
Block a user