Restructure interrupt handling a little:
* Only futz with the done list in the soft interrupt handler. In the hard interrupt handler, do nothing except mask WDH and queue the soft interrupt. This simplifies a bunch of code, removes two O(n^2) queue manipulations, and gets rid of some really sketchy stuff around the queue head access. * Use the auto-masking code at the end of the interrupt handler for both WDH and RHSC interrupts. Again, this reduces the code a little, and avoids multiple writebacks to the chip registers.
This commit is contained in:
parent
7dfa1d8cf7
commit
e63d9a6eae
@ -1,13 +1,15 @@
|
||||
/* $NetBSD: ohci.c,v 1.156 2005/03/02 11:37:27 mycroft Exp $ */
|
||||
/* $NetBSD: ohci.c,v 1.157 2005/03/11 19:25:22 mycroft Exp $ */
|
||||
/* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
|
||||
* Copyright (c) 1998, 2004, 2005 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Lennart Augustsson (lennart@augustsson.net) at
|
||||
* Carlstedt Research & Technology.
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Charles M. Hannum.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -46,7 +48,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.156 2005/03/02 11:37:27 mycroft Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.157 2005/03/11 19:25:22 mycroft Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -143,7 +145,6 @@ Static usbd_status ohci_open(usbd_pipe_handle);
|
||||
Static void ohci_poll(struct usbd_bus *);
|
||||
Static void ohci_softintr(void *);
|
||||
Static void ohci_waitintr(ohci_softc_t *, usbd_xfer_handle);
|
||||
Static void ohci_add_done(ohci_softc_t *, ohci_physaddr_t);
|
||||
Static void ohci_rhsc(ohci_softc_t *, usbd_xfer_handle);
|
||||
|
||||
Static usbd_status ohci_device_request(usbd_xfer_handle xfer);
|
||||
@ -208,7 +209,6 @@ Static int ohci_str(usb_string_descriptor_t *, int, const char *);
|
||||
|
||||
Static void ohci_timeout(void *);
|
||||
Static void ohci_timeout_task(void *);
|
||||
Static void ohci_rhsc_able(ohci_softc_t *, int);
|
||||
Static void ohci_rhsc_enable(void *);
|
||||
|
||||
Static void ohci_close_pipe(usbd_pipe_handle, ohci_soft_ed_t *);
|
||||
@ -1124,7 +1124,6 @@ Static int
|
||||
ohci_intr1(ohci_softc_t *sc)
|
||||
{
|
||||
u_int32_t intrs, eintrs;
|
||||
ohci_physaddr_t done;
|
||||
|
||||
DPRINTFN(14,("ohci_intr1: enter\n"));
|
||||
|
||||
@ -1136,22 +1135,11 @@ ohci_intr1(ohci_softc_t *sc)
|
||||
return (0);
|
||||
}
|
||||
|
||||
intrs = 0;
|
||||
done = le32toh(sc->sc_hcca->hcca_done_head);
|
||||
if (done != 0) {
|
||||
if (done & ~OHCI_DONE_INTRS)
|
||||
intrs = OHCI_WDH;
|
||||
if (done & OHCI_DONE_INTRS)
|
||||
intrs |= OREAD4(sc, OHCI_INTERRUPT_STATUS);
|
||||
sc->sc_hcca->hcca_done_head = 0;
|
||||
} else
|
||||
intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & ~OHCI_WDH;
|
||||
|
||||
intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS);
|
||||
if (!intrs)
|
||||
return (0);
|
||||
|
||||
intrs &= ~OHCI_MIE;
|
||||
OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs); /* Acknowledge */
|
||||
OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs & ~(OHCI_MIE|OHCI_WDH)); /* Acknowledge */
|
||||
eintrs = intrs & sc->sc_eintrs;
|
||||
if (!eintrs)
|
||||
return (0);
|
||||
@ -1173,9 +1161,11 @@ ohci_intr1(ohci_softc_t *sc)
|
||||
eintrs &= ~OHCI_SO;
|
||||
}
|
||||
if (eintrs & OHCI_WDH) {
|
||||
ohci_add_done(sc, done &~ OHCI_DONE_INTRS);
|
||||
/*
|
||||
* We block the interrupt below, and reenable it later from
|
||||
* ohci_softintr().
|
||||
*/
|
||||
usb_schedsoftintr(&sc->sc_bus);
|
||||
eintrs &= ~OHCI_WDH;
|
||||
}
|
||||
if (eintrs & OHCI_RD) {
|
||||
printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev));
|
||||
@ -1188,43 +1178,28 @@ ohci_intr1(ohci_softc_t *sc)
|
||||
/* XXX what else */
|
||||
}
|
||||
if (eintrs & OHCI_RHSC) {
|
||||
ohci_rhsc(sc, sc->sc_intrxfer);
|
||||
/*
|
||||
* Disable RHSC interrupt for now, because it will be
|
||||
* on until the port has been reset.
|
||||
* We block the interrupt below, and reenable it later from
|
||||
* a timeout.
|
||||
*/
|
||||
ohci_rhsc_able(sc, 0);
|
||||
ohci_rhsc(sc, sc->sc_intrxfer);
|
||||
/* Do not allow RHSC interrupts > 1 per second */
|
||||
usb_callout(sc->sc_tmo_rhsc, hz, ohci_rhsc_enable, sc);
|
||||
eintrs &= ~OHCI_RHSC;
|
||||
}
|
||||
|
||||
sc->sc_bus.intr_context--;
|
||||
|
||||
if (eintrs != 0) {
|
||||
/* Block unprocessed interrupts. XXX */
|
||||
/* Block unprocessed interrupts. */
|
||||
OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs);
|
||||
sc->sc_eintrs &= ~eintrs;
|
||||
printf("%s: blocking intrs 0x%x\n",
|
||||
USBDEVNAME(sc->sc_bus.bdev), eintrs);
|
||||
DPRINTFN(1, ("%s: blocking intrs 0x%x\n",
|
||||
USBDEVNAME(sc->sc_bus.bdev), eintrs));
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
ohci_rhsc_able(ohci_softc_t *sc, int on)
|
||||
{
|
||||
DPRINTFN(4, ("ohci_rhsc_able: on=%d\n", on));
|
||||
if (on) {
|
||||
sc->sc_eintrs |= OHCI_RHSC;
|
||||
OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC);
|
||||
} else {
|
||||
sc->sc_eintrs &= ~OHCI_RHSC;
|
||||
OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ohci_rhsc_enable(void *v_sc)
|
||||
{
|
||||
@ -1232,7 +1207,8 @@ ohci_rhsc_enable(void *v_sc)
|
||||
int s;
|
||||
|
||||
s = splhardusb();
|
||||
ohci_rhsc_able(sc, 1);
|
||||
sc->sc_eintrs |= OHCI_RHSC;
|
||||
OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
@ -1258,10 +1234,28 @@ char *ohci_cc_strs[] = {
|
||||
#endif
|
||||
|
||||
void
|
||||
ohci_add_done(ohci_softc_t *sc, ohci_physaddr_t done)
|
||||
ohci_softintr(void *v)
|
||||
{
|
||||
ohci_soft_itd_t *sitd, *sidone, **ip;
|
||||
ohci_soft_td_t *std, *sdone, **p;
|
||||
ohci_softc_t *sc = v;
|
||||
ohci_soft_itd_t *sitd, *sidone, *sitdnext;
|
||||
ohci_soft_td_t *std, *sdone, *stdnext;
|
||||
usbd_xfer_handle xfer;
|
||||
struct ohci_pipe *opipe;
|
||||
int len, cc, s;
|
||||
int i, j, actlen, iframes, uedir;
|
||||
ohci_physaddr_t done;
|
||||
|
||||
DPRINTFN(10,("ohci_softintr: enter\n"));
|
||||
|
||||
sc->sc_bus.intr_context++;
|
||||
|
||||
s = splhardusb();
|
||||
done = le32toh(sc->sc_hcca->hcca_done_head) & ~OHCI_DONE_INTRS;
|
||||
sc->sc_hcca->hcca_done_head = 0;
|
||||
OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_WDH);
|
||||
sc->sc_eintrs |= OHCI_WDH;
|
||||
OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_WDH);
|
||||
splx(s);
|
||||
|
||||
/* Reverse the done list. */
|
||||
for (sdone = NULL, sidone = NULL; done != 0; ) {
|
||||
@ -1281,41 +1275,9 @@ ohci_add_done(ohci_softc_t *sc, ohci_physaddr_t done)
|
||||
DPRINTFN(5,("add ITD %p\n", sitd));
|
||||
continue;
|
||||
}
|
||||
panic("ohci_add_done: addr 0x%08lx not found", (u_long)done);
|
||||
panic("ohci_softintr: addr 0x%08lx not found", (u_long)done);
|
||||
}
|
||||
|
||||
/* sdone & sidone now hold the done lists. */
|
||||
/* Put them on the already processed lists. */
|
||||
for (p = &sc->sc_sdone; *p != NULL; p = &(*p)->dnext)
|
||||
;
|
||||
*p = sdone;
|
||||
for (ip = &sc->sc_sidone; *ip != NULL; ip = &(*ip)->dnext)
|
||||
;
|
||||
*ip = sidone;
|
||||
}
|
||||
|
||||
void
|
||||
ohci_softintr(void *v)
|
||||
{
|
||||
ohci_softc_t *sc = v;
|
||||
ohci_soft_itd_t *sitd, *sidone, *sitdnext;
|
||||
ohci_soft_td_t *std, *sdone, *stdnext;
|
||||
usbd_xfer_handle xfer;
|
||||
struct ohci_pipe *opipe;
|
||||
int len, cc, s;
|
||||
int i, j, actlen, iframes, uedir;
|
||||
|
||||
DPRINTFN(10,("ohci_softintr: enter\n"));
|
||||
|
||||
sc->sc_bus.intr_context++;
|
||||
|
||||
s = splhardusb();
|
||||
sdone = sc->sc_sdone;
|
||||
sc->sc_sdone = NULL;
|
||||
sidone = sc->sc_sidone;
|
||||
sc->sc_sidone = NULL;
|
||||
splx(s);
|
||||
|
||||
DPRINTFN(10,("ohci_softintr: sdone=%p sidone=%p\n", sdone, sidone));
|
||||
|
||||
#ifdef OHCI_DEBUG
|
||||
@ -2564,7 +2526,7 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
|
||||
case UHF_C_PORT_RESET:
|
||||
/* Enable RHSC interrupt if condition is cleared. */
|
||||
if ((OREAD4(sc, port) >> 16) == 0)
|
||||
ohci_rhsc_able(sc, 1);
|
||||
ohci_rhsc_enable(sc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ohcivar.h,v 1.35 2005/01/11 07:45:34 imp Exp $ */
|
||||
/* $NetBSD: ohcivar.h,v 1.36 2005/03/11 19:25:22 mycroft Exp $ */
|
||||
/* $FreeBSD: src/sys/dev/usb/ohcivar.h,v 1.13 1999/11/17 22:33:41 n_hibma Exp $ */
|
||||
|
||||
/*
|
||||
@ -118,9 +118,6 @@ typedef struct ohci_softc {
|
||||
|
||||
usbd_xfer_handle sc_intrxfer;
|
||||
|
||||
ohci_soft_itd_t *sc_sidone;
|
||||
ohci_soft_td_t *sc_sdone;
|
||||
|
||||
char sc_vendor[16];
|
||||
int sc_id_vendor;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user