Interrupt overhaul:

- Allocate interrupt handles dynamically from a pool(9) to reduce the
   number of TLB misses during interrupt dispatch.
 - Fully support evcnt(9) in all interrupt dispatchers.
This commit is contained in:
scw 2002-10-14 14:19:27 +00:00
parent 041aef4bee
commit 89612efe30
9 changed files with 370 additions and 219 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: superio.c,v 1.9 2002/10/02 05:33:54 thorpej Exp $ */
/* $NetBSD: superio.c,v 1.10 2002/10/14 14:19:29 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -59,6 +59,7 @@
#include <dev/ic/smc91cxxreg.h>
#if NCOM > 0
#include <evbsh5/evbsh5/machdep.h>
#include <evbsh5/dev/sysfpgareg.h>
#endif
@ -571,8 +572,12 @@ isa_attach_hook(struct device *parent, struct device *self,
const struct evcnt *
isa_intr_evcnt(isa_chipset_tag_t ic, int irq)
{
int inum, dummy;
return (sysfpga_intr_evcnt(SYSFPGA_IGROUP_SUPERIO));
if ((inum = superio_isa_irq_to_inum(irq, &dummy)) < 0)
return (NULL);
return (sysfpga_intr_evcnt(SYSFPGA_IGROUP_SUPERIO, inum));
}
int
@ -668,8 +673,8 @@ superio_console_tag(bus_space_tag_t bt, int port,
bus_addr_t base;
u_int8_t reg;
if (bus_space_map(bt, SYSFPGA_OFFSET_SUPERIO, SUPERIO_REG_SZ, 0,
&sc.sc_bush))
if (bus_space_subregion(bt, _evbsh5_bh_sysfpga,
SYSFPGA_OFFSET_SUPERIO, SUPERIO_REG_SZ, &sc.sc_bush))
return (-1);
sc.sc_bust = bt;

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysfpga.c,v 1.11 2002/10/05 12:18:58 scw Exp $ */
/* $NetBSD: sysfpga.c,v 1.12 2002/10/14 14:19:29 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -121,14 +121,24 @@ static int sysfpga_intr_handler_irl2(void *);
static int sysfpga_intr_handler_irl3(void *);
#endif
static int sysfpga_intr_dispatch(struct sysfpga_softc *,
struct sysfpga_ihandler *, int);
static int sysfpga_intr_dispatch(const struct sysfpga_ihandler *, int, int);
static const char *sysfpga_cpuclksel[] = {
"400/200/100MHz", "400/200/66MHz", "400/200/50MHz", "<invalid>"
};
#if NSUPERIO > 0
static const char *sysfpga_superio_intr_names[SYSFPGA_SUPERIO_NINTR] = {
"dcd0", "lan", "keyboard", "uart2", "uart1", "lpt", "mouse", "ide"
};
static struct evcnt sysfpga_superio_intr_events[SYSFPGA_SUPERIO_NINTR];
#endif
#if NSH5PCI > 0
static struct evcnt sysfpga_pci1_intr_events;
static struct evcnt sysfpga_pci2_intr_events;
#endif
static struct sysfpga_softc *sysfpga_sc;
@ -152,6 +162,10 @@ sysfpgaattach(struct device *parent, struct device *self, void *args)
struct sysfpga_attach_args sa;
u_int32_t reg;
int i;
#if (NSUPERIO > 0) || (NSH5PCI > 0)
struct evcnt *ev;
static const char sysfpga_intr[] = "sysfpga intr";
#endif
sysfpga_sc = sc;
@ -194,6 +208,14 @@ sysfpgaattach(struct device *parent, struct device *self, void *args)
if (sc->sc_ih[SYSFPGA_IGROUP_SUPERIO] == NULL)
panic("sysfpga: failed to register superio isr");
ev = sh5_intr_evcnt(sc->sc_ih[SYSFPGA_IGROUP_SUPERIO]);
for (i = 0; i < SYSFPGA_SUPERIO_NINTR; i++) {
evcnt_attach_dynamic(&sysfpga_superio_intr_events[i],
EVCNT_TYPE_INTR, ev,
(i >= SYSFPGA_SUPERIO_INUM_KBD) ? "isa intr" : sysfpga_intr,
sysfpga_superio_intr_names[i]);
}
#endif
#if NSH5PCI > 0
@ -203,6 +225,7 @@ sysfpgaattach(struct device *parent, struct device *self, void *args)
sc->sc_ih[SYSFPGA_IGROUP_PCI1] =
sh5_intr_establish(INTC_INTEVT_IRL2, IST_LEVEL, IPL_SH5PCI,
sysfpga_intr_handler_irl2, sc);
sc->sc_ih[SYSFPGA_IGROUP_PCI2] =
sh5_intr_establish(INTC_INTEVT_IRL3, IST_LEVEL, IPL_SH5PCI,
sysfpga_intr_handler_irl3, sc);
@ -210,6 +233,14 @@ sysfpgaattach(struct device *parent, struct device *self, void *args)
if (sc->sc_ih[SYSFPGA_IGROUP_PCI1] == NULL ||
sc->sc_ih[SYSFPGA_IGROUP_PCI2] == NULL)
panic("sysfpga: failed to register pci isr");
ev = sh5_intr_evcnt(sc->sc_ih[SYSFPGA_IGROUP_PCI1]);
evcnt_attach_dynamic(&sysfpga_pci1_intr_events,
EVCNT_TYPE_INTR, ev, sysfpga_intr, "pci1");
ev = sh5_intr_evcnt(sc->sc_ih[SYSFPGA_IGROUP_PCI2]);
evcnt_attach_dynamic(&sysfpga_pci2_intr_events,
EVCNT_TYPE_INTR, ev, sysfpga_intr, "pci2");
#endif
#ifdef DEBUG
@ -278,6 +309,7 @@ sysfpga_intr_handler_irl1(void *arg)
{
struct sysfpga_softc *sc = arg;
struct sysfpga_ihandler *ih;
struct evcnt *events = sysfpga_superio_intr_events;
u_int8_t intsr, intmr;
int sr_reg, h = 0;
@ -289,33 +321,47 @@ sysfpga_intr_handler_irl1(void *arg)
(intsr &= intmr) != 0;
intsr = sysfpga_reg_read(sc, sr_reg)) {
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_UART1))
h |= sysfpga_intr_dispatch(sc, ih,
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_UART1)) {
h |= sysfpga_intr_dispatch(ih, IPL_SUPERIO,
SYSFPGA_SUPERIO_INUM_UART1);
events[SYSFPGA_SUPERIO_INUM_UART1].ev_count++;
}
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_UART2))
h |= sysfpga_intr_dispatch(sc, ih,
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_UART2)) {
h |= sysfpga_intr_dispatch(ih, IPL_SUPERIO,
SYSFPGA_SUPERIO_INUM_UART2);
events[SYSFPGA_SUPERIO_INUM_UART2].ev_count++;
}
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_MOUSE))
h |= sysfpga_intr_dispatch(sc, ih,
SYSFPGA_SUPERIO_INUM_MOUSE);
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_KBD))
h |= sysfpga_intr_dispatch(sc, ih,
SYSFPGA_SUPERIO_INUM_KBD);
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_LAN))
h |= sysfpga_intr_dispatch(sc, ih,
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_LAN)) {
h |= sysfpga_intr_dispatch(ih, IPL_SUPERIO,
SYSFPGA_SUPERIO_INUM_LAN);
events[SYSFPGA_SUPERIO_INUM_LAN].ev_count++;
}
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_IDE))
h |= sysfpga_intr_dispatch(sc, ih,
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_MOUSE)) {
h |= sysfpga_intr_dispatch(ih, IPL_SUPERIO,
SYSFPGA_SUPERIO_INUM_MOUSE);
events[SYSFPGA_SUPERIO_INUM_MOUSE].ev_count++;
}
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_KBD)) {
h |= sysfpga_intr_dispatch(ih, IPL_SUPERIO,
SYSFPGA_SUPERIO_INUM_KBD);
events[SYSFPGA_SUPERIO_INUM_KBD].ev_count++;
}
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_IDE)) {
h |= sysfpga_intr_dispatch(ih, IPL_SUPERIO,
SYSFPGA_SUPERIO_INUM_IDE);
events[SYSFPGA_SUPERIO_INUM_IDE].ev_count++;
}
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_LPT))
h |= sysfpga_intr_dispatch(sc, ih,
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_LPT)) {
h |= sysfpga_intr_dispatch(ih, IPL_SUPERIO,
SYSFPGA_SUPERIO_INUM_LPT);
events[SYSFPGA_SUPERIO_INUM_LPT].ev_count++;
}
if (h == 0)
panic("sysfpga: unclaimed IRL1 interrupt: 0x%02x",
@ -344,20 +390,26 @@ sysfpga_intr_handler_irl2(void *arg)
intsr = sysfpga_reg_read(sc, sr_reg)) {
if (intsr & (1 << SYSFPGA_PCI1_INTA))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI1_INTA);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI1_INTA);
if (intsr & (1 << SYSFPGA_PCI1_INTB))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI1_INTB);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI1_INTB);
if (intsr & (1 << SYSFPGA_PCI1_INTC))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI1_INTC);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI1_INTC);
if (intsr & (1 << SYSFPGA_PCI1_INTD))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI1_INTD);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI1_INTD);
if (h == 0)
panic("sysfpga: unclaimed IRL2 interrupt: 0x%02x",
intsr);
sysfpga_pci1_intr_events.ev_count++;
}
return (h);
@ -380,32 +432,42 @@ sysfpga_intr_handler_irl3(void *arg)
intsr = sysfpga_reg_read(sc, sr_reg)) {
if (intsr & (1 << SYSFPGA_PCI2_INTA))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTA);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI2_INTA);
if (intsr & (1 << SYSFPGA_PCI2_INTB))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTB);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI2_INTB);
if (intsr & (1 << SYSFPGA_PCI2_INTC))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTC);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI2_INTC);
if (intsr & (1 << SYSFPGA_PCI2_INTD))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTD);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI2_INTD);
if (intsr & (1 << SYSFPGA_PCI2_FAL))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_FAL);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI2_FAL);
if (intsr & (1 << SYSFPGA_PCI2_DEG))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_DEG);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI2_DEG);
if (intsr & (1 << SYSFPGA_PCI2_INTP))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTP);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI2_INTP);
if (intsr & (1 << SYSFPGA_PCI2_INTS))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTS);
h |= sysfpga_intr_dispatch(ih, IPL_SH5PCI,
SYSFPGA_PCI2_INTS);
if (h == 0)
panic("sysfpga: unclaimed IRL3 interrupt: 0x%02x",
intsr);
sysfpga_pci2_intr_events.ev_count++;
}
return (h);
@ -413,8 +475,7 @@ sysfpga_intr_handler_irl3(void *arg)
#endif
static int
sysfpga_intr_dispatch(struct sysfpga_softc *sc, struct sysfpga_ihandler *ih,
int hnum)
sysfpga_intr_dispatch(const struct sysfpga_ihandler *ih, int level, int hnum)
{
int h, s;
@ -429,22 +490,41 @@ sysfpga_intr_dispatch(struct sysfpga_softc *sc, struct sysfpga_ihandler *ih,
* This splraise() is fine since sysfpga's interrupt handler
* runs at a lower ipl than anything the child drivers could request.
*/
s = splraise(ih->ih_level);
s = (ih->ih_level > level) ? splraise(ih->ih_level) : -1;
h = (*ih->ih_func)(ih->ih_arg);
splx(s);
if (s >= 0)
splx(s);
return (h);
}
struct evcnt *
sysfpga_intr_evcnt(int group)
sysfpga_intr_evcnt(int group, int inum)
{
struct sysfpga_softc *sc = sysfpga_sc;
struct evcnt *ev = NULL;
KDASSERT(group < SYSFPGA_NGROUPS);
KDASSERT(sc->sc_ih[group] != NULL);
return (sh5_intr_evcnt(sc->sc_ih[group]));
switch (group) {
case SYSFPGA_IGROUP_SUPERIO:
KDASSERT(inum >= 0 && inum < SYSFPGA_SUPERIO_NINTR);
ev = &sysfpga_superio_intr_events[inum];
break;
case SYSFPGA_IGROUP_PCI1:
ev = &sysfpga_pci1_intr_events;
break;
case SYSFPGA_IGROUP_PCI2:
ev = &sysfpga_pci2_intr_events;
break;
}
return (ev);
}
void *

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysfpgavar.h,v 1.5 2002/10/05 10:59:10 scw Exp $ */
/* $NetBSD: sysfpgavar.h,v 1.6 2002/10/14 14:19:29 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -92,9 +92,9 @@ struct sysfpga_attach_args {
#define SYSFPGA_PCI2_NINTR 8
struct evcnt;
extern struct evcnt *sysfpga_intr_evcnt(int);
extern void *sysfpga_intr_establish(int, int, int, int (*)(void *), void *);
extern void sysfpga_intr_disestablish(void *);
extern struct evcnt *sysfpga_intr_evcnt(int, int);
extern void sysfpga_nmi_clear(void);
extern void sysfpga_sreset(void);

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore.S,v 1.7 2002/10/08 15:52:02 scw Exp $ */
/* $NetBSD: locore.S,v 1.8 2002/10/14 14:19:29 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -381,8 +381,8 @@ GLOBAL(intrnames)
.asciz "softclock"
.asciz "softnet"
.asciz "irq4"
.asciz "isa-lan"
.asciz "pci"
.asciz "irq5"
.asciz "irq6"
.asciz "irq7"
.asciz "irq8"
.asciz "irq9"

View File

@ -1,4 +1,4 @@
/* $NetBSD: pci_intr_machdep.c,v 1.1 2002/09/28 11:16:39 scw Exp $ */
/* $NetBSD: pci_intr_machdep.c,v 1.2 2002/10/14 14:19:29 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -51,12 +51,13 @@
* XXX: Right now, assume no other PCI-PCI bridges are present on the
* primary and secondary buses (they would mess up the bus numbers, and
* confuse the code). The solution to this will be to scan the bus
* heirarchy to check subordinate bus numbers...
* hierarchy to check subordinate bus numbers...
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <dev/pci/pcireg.h>
@ -95,13 +96,11 @@ struct sh5pci_intr_hooks cayman_pci_hooks = {
struct cayman_intr_softc {
void *sc_ct;
struct sh5pci_ihead sc_primary[PCI_INTERRUPT_PIN_MAX];
struct sh5pci_ihead sc_p1[PCI_INTERRUPT_PIN_MAX];
struct sh5pci_ihead sc_p2[PCI_INTERRUPT_PIN_MAX];
struct sh5pci_ihead *sc_primary[PCI_INTERRUPT_PIN_MAX];
struct sh5pci_ihead *sc_p1[PCI_INTERRUPT_PIN_MAX];
struct sh5pci_ihead *sc_p2[PCI_INTERRUPT_PIN_MAX];
};
static struct cayman_intr_softc softc;
/*
* Magick values stuffed into the interrupt line to identify which
* interrupt controller the pin is routed to.
@ -139,10 +138,12 @@ cayman_intr_init(struct sh5_pci_chipset_tag *ct,
void **ih_serr, int (*fn_serr)(void *), void *arg_serr,
void **ih_err, int (*fn_err)(void *), void *arg_err)
{
struct cayman_intr_softc *sc = &softc;
struct sh5pci_ihead *ih;
struct cayman_intr_softc *sc;
int i;
if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL)
return (NULL);
/*
* Hook the ERR and SERR interrupts from the bridge, if required.
*/
@ -159,45 +160,13 @@ cayman_intr_init(struct sh5_pci_chipset_tag *ct,
}
/*
* Initialise the sh5pci_ihead structures for the PCI INT[A-D] pins
* Initialise the sh5pci_ihead structures for the PCI INT[A-D] pins.
* We lazy-allocate the ihead stuctures as they are required.
*/
for (i = 0; i < PCI_INTERRUPT_PIN_MAX; i++) {
ih = &sc->sc_primary[i];
SLIST_INIT(&ih->ih_handlers);
ih->ih_cookie = NULL;
ih->ih_evcnt = NULL;
ih->ih_level = 0;
switch (i) {
case 0: ih->ih_intevt = INTC_INTEVT_PCI_INTA;
break;
case 1: ih->ih_intevt = INTC_INTEVT_PCI_INTB;
break;
case 2: ih->ih_intevt = INTC_INTEVT_PCI_INTC;
break;
case 3: ih->ih_intevt = INTC_INTEVT_PCI_INTD;
break;
}
}
for (i = 0; i < PCI_INTERRUPT_PIN_MAX; i++) {
ih = &sc->sc_p1[i];
SLIST_INIT(&ih->ih_handlers);
ih->ih_cookie = NULL;
ih->ih_evcnt = NULL;
ih->ih_level = 0;
ih->ih_intevt = INTC_INTEVT_IRL2;
}
for (i = 0; i < PCI_INTERRUPT_PIN_MAX; i++) {
ih = &sc->sc_p2[i];
SLIST_INIT(&ih->ih_handlers);
ih->ih_cookie = NULL;
ih->ih_evcnt = NULL;
ih->ih_level = 0;
ih->ih_intevt = INTC_INTEVT_IRL3;
sc->sc_primary[i] = NULL;
sc->sc_p1[i] = NULL;
sc->sc_p2[i] = NULL;
}
sc->sc_ct = ct;
@ -236,70 +205,158 @@ cayman_intr_conf(void *arg, int bus, int dev, int pin, int swiz, int *line)
/*ARGSUSED*/
static int
cayman_intr_map(void *arg, struct pci_attach_args *pa, pci_intr_handle_t *ih)
cayman_intr_map(void *arg, struct pci_attach_args *pa, pci_intr_handle_t *hp)
{
*ih = SH5PCI_IH_CREATE(pa->pa_intrline, pa->pa_intrpin, 0);
*hp = SH5PCI_IH_CREATE(pa->pa_intrline, pa->pa_intrpin, 0);
return (0);
}
static struct sh5pci_ihead *
cayman_intr_ihead(void *arg, pci_intr_handle_t ih)
cayman_intr_ihead(void *arg, pci_intr_handle_t handle)
{
struct cayman_intr_softc *sc = arg;
int pin;
struct sh5pci_ihead *ih, **ihp;
int pin, evt;
if (SH5PCI_IH_PIN(ih) == PCI_INTERRUPT_PIN_NONE ||
SH5PCI_IH_PIN(ih) > PCI_INTERRUPT_PIN_MAX)
pin = SH5PCI_IH_PIN(handle);
if (pin == PCI_INTERRUPT_PIN_NONE || pin > PCI_INTERRUPT_PIN_MAX)
return (NULL);
pin = SH5PCI_IH_PIN(ih) - 1;
pin -= 1;
if (CAYMAN_INTR_IS_PRIMARY(ih))
return (&sc->sc_primary[pin]);
if (CAYMAN_INTR_IS_PRIMARY(handle)) {
ihp = &sc->sc_primary[pin];
switch (pin) {
case 0: evt = INTC_INTEVT_PCI_INTA;
break;
case 1: evt = INTC_INTEVT_PCI_INTB;
break;
case 2: evt = INTC_INTEVT_PCI_INTC;
break;
case 3: evt = INTC_INTEVT_PCI_INTD;
break;
}
} else
if (CAYMAN_INTR_IS_P1(handle)) {
ihp = &sc->sc_p1[pin];
evt = INTC_INTEVT_IRL2;
} else
if (CAYMAN_INTR_IS_P2(handle)) {
ihp = &sc->sc_p2[pin];
evt = INTC_INTEVT_IRL3;
} else
return (NULL);
if (CAYMAN_INTR_IS_P1(ih))
return (&sc->sc_p1[pin]);
if (*ihp)
return (*ihp);
if (CAYMAN_INTR_IS_P2(ih))
return (&sc->sc_p2[pin]);
if ((ih = sh5_intr_alloc_handle(sizeof(*ih))) == NULL)
return (NULL);
return (NULL);
SLIST_INIT(&ih->ih_handlers);
ih->ih_cookie = NULL;
ih->ih_evcnt = NULL;
ih->ih_level = 0;
ih->ih_intevt = evt;
*ihp = ih;
return (ih);
}
/*ARGSUSED*/
static void *
cayman_intr_establish(void *arg, pci_intr_handle_t ih,
cayman_intr_establish(void *arg, pci_intr_handle_t handle,
int level, int (*func)(void *), void *fnarg)
{
struct sh5pci_ihead *ihead;
int inum, group;
struct evcnt *evcnt, *parent_evcnt;
int pin, inum, group;
void *cookie;
const char *ename, *gname;
if ((ihead = cayman_intr_ihead(arg, ih)) == NULL)
if ((ihead = cayman_intr_ihead(arg, handle)) == NULL)
return (NULL);
if (CAYMAN_INTR_IS_PRIMARY(ih)) {
return (sh5_intr_establish(ihead->ih_intevt, IST_LEVEL, level,
func, fnarg));
pin = (SH5PCI_IH_PIN(handle) - 1) & 3;
switch (pin) {
case 0: ename = "INTA"; break;
case 1: ename = "INTB"; break;
case 2: ename = "INTC"; break;
case 3: ename = "INTD"; break;
}
inum = SH5PCI_IH_LINE(ih) & 0x03;
if (CAYMAN_INTR_IS_PRIMARY(handle)) {
cookie = sh5_intr_establish(ihead->ih_intevt, IST_LEVEL, level,
func, fnarg);
parent_evcnt = sh5_intr_evcnt(cookie);
gname = "pci0";
} else {
inum = SH5PCI_IH_LINE(handle) & 0x03;
if (CAYMAN_INTR_IS_P1(ih))
group = SYSFPGA_IGROUP_PCI1;
else
group = SYSFPGA_IGROUP_PCI2;
if (CAYMAN_INTR_IS_P1(handle)) {
group = SYSFPGA_IGROUP_PCI1;
gname = "pci1";
} else {
group = SYSFPGA_IGROUP_PCI2;
gname = "pci2";
}
return (sysfpga_intr_establish(group, level, inum, func, fnarg));
cookie = sysfpga_intr_establish(group, level, inum, func,
fnarg);
parent_evcnt = sysfpga_intr_evcnt(group, inum);
}
if (ihead->ih_evcnt == NULL &&
(evcnt = sh5_intr_alloc_handle(sizeof(*ihead->ih_evcnt))) != NULL) {
evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR, parent_evcnt,
gname, ename);
ihead->ih_evcnt = evcnt;
}
return (cookie);
}
/*ARGSUSED*/
static void
cayman_intr_disestablish(void *arg, pci_intr_handle_t ih, void *cookie)
cayman_intr_disestablish(void *arg, pci_intr_handle_t handle, void *cookie)
{
struct cayman_intr_softc *sc = arg;
struct sh5pci_ihead **ihp;
int pin;
if (CAYMAN_INTR_IS_PRIMARY(ih))
if (CAYMAN_INTR_IS_PRIMARY(handle))
sh5_intr_disestablish(cookie);
else
sysfpga_intr_disestablish(cookie);
pin = SH5PCI_IH_PIN(handle);
if (pin == PCI_INTERRUPT_PIN_NONE || pin > PCI_INTERRUPT_PIN_MAX)
return; /* XXX: Should probably panic */
pin -= 1;
if (CAYMAN_INTR_IS_PRIMARY(handle))
ihp = &sc->sc_primary[pin];
else
if (CAYMAN_INTR_IS_P1(handle))
ihp = &sc->sc_p1[pin];
else
if (CAYMAN_INTR_IS_P2(handle))
ihp = &sc->sc_p2[pin];
else
return; /* XXX: Should probably panic */
if (*ihp == NULL)
return; /* XXX: Should probably panic */
if ((*ihp)->ih_evcnt) {
evcnt_detach((*ihp)->ih_evcnt);
sh5_intr_free_handle((*ihp)->ih_evcnt);
}
sh5_intr_free_handle(*ihp);
*ihp = NULL;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: intc.c,v 1.7 2002/10/02 15:52:36 thorpej Exp $ */
/* $NetBSD: intc.c,v 1.8 2002/10/14 14:19:27 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -159,7 +159,7 @@ intcattach(struct device *parent, struct device *self, void *args)
intc_reg_write(sc, INTC_REG_ICR_CLEAR, INTC_ICR_CLEAR_IRL_MODE_LEVEL);
#endif
sh5_intr_init(31, intc_enable, intc_disable, sc);
sh5_intr_init(intc_enable, intc_disable, sc);
printf(": Interrupt Controller\n");
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.h,v 1.4 2002/10/01 21:07:31 scw Exp $ */
/* $NetBSD: intr.h,v 1.5 2002/10/14 14:19:28 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -99,8 +99,10 @@ extern struct evcnt *sh5_intr_evcnt(void *);
/* Internal use only */
extern void softintr_dispatch(u_int, u_int);
extern void softintr_init(void);
extern void sh5_intr_init(int, void (*)(void *, u_int, int, int),
extern void sh5_intr_init(void (*)(void *, u_int, int, int),
void (*)(void *, u_int), void *);
extern void *sh5_intr_alloc_handle(size_t);
extern void sh5_intr_free_handle(void *);
extern struct evcnt _sh5_intr_events[];
extern void _cpu_intr_set(u_int);
extern void _cpu_intr_resume(u_int);

View File

@ -1,4 +1,4 @@
/* $NetBSD: sh5_pci.c,v 1.6 2002/10/04 10:22:24 scw Exp $ */
/* $NetBSD: sh5_pci.c,v 1.7 2002/10/14 14:19:28 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -771,13 +771,13 @@ sh5pci_intr_establish(void *arg, pci_intr_handle_t ih,
if (ihead == NULL)
return (NULL);
if ((ic = malloc(sizeof(*ic), M_DEVBUF, M_NOWAIT)) == NULL)
if ((ic = sh5_intr_alloc_handle(sizeof(*ic))) == NULL)
return (NULL);
s = splhigh();
if (ihead->ih_cookie != NULL && ihead->ih_level != level) {
splx(s);
free(ic, M_DEVBUF);
sh5_intr_free_handle(ic);
printf("sh5pci_intr_establish: shared level mismatch");
return (NULL);
}
@ -821,17 +821,19 @@ sh5pci_intr_disestablish(void *arg, void *cookie)
SLIST_REMOVE(&ihead->ih_handlers, ic, sh5pci_icookie, ic_next);
/*
* If we're removing the last handler, unhook the interrupt
* If we're removing the last handler, unhook the interrupt.
*/
if (SLIST_EMPTY(&ihead->ih_handlers)) {
(*sc->sc_intr->ih_intr_disestablish)(sc->sc_intr_arg,
ic->ic_ih, ihead->ih_cookie);
ihead->ih_cookie = NULL;
ihead->ih_level = 0;
/*
* Note that ihead is likely to be invalid now if the back-end
* does lazy-allocation of the sh5pci_ihead structures...
*/
}
splx(s);
free(ic, M_DEVBUF);
sh5_intr_free_handle(ic);
}
static int
@ -845,8 +847,13 @@ sh5pci_intr_dispatch(void *arg)
* Call all the handlers registered for a particular interrupt pin
* and accumulate their "handled" status.
*/
SLIST_FOREACH(ic, &ihead->ih_handlers, ic_next)
rv |= (*ic->ic_func)(ic->ic_arg);
SLIST_FOREACH(ic, &ihead->ih_handlers, ic_next) {
if ((*ic->ic_func)(ic->ic_arg)) {
if (ihead->ih_evcnt)
ihead->ih_evcnt->ev_count++;
rv++;
}
}
return (rv);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: interrupt.c,v 1.5 2002/10/08 15:55:07 scw Exp $ */
/* $NetBSD: interrupt.c,v 1.6 2002/10/14 14:19:28 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -72,34 +72,49 @@
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/pool.h>
#include <sys/device.h>
#include <uvm/uvm_extern.h> /* uvmexp.intrs */
#include <machine/intr.h>
#include <machine/cacheops.h>
/*
* INTEVT to intrhand mapper.
* SH5 interrupt handlers are tracked using instances of the following
* structure.
*/
static int8_t intevt_to_ih[256];
struct intrhand {
int (*ih_func)(void *);
void *ih_arg;
int ih_type;
int ih_level;
u_int ih_intevt;
int ih_idx;
};
static struct intrhand *intrhand;
static int szintrhand;
/*
* The list of all possible interrupt handlers, indexed by INTEVT
*/
static struct intrhand *intrhand[256];
#define INTEVT_TO_IH_INDEX(x) ((int)((x) >> 5) & 0xff)
#define INTEVT_IH(x) (intrhand[INTEVT_TO_IH_INDEX(x)])
/*
* Pool of interrupt handles.
* This is used by all native SH5 interrupt drivers. It ensures the
* handle is allocated from KSEG0, which avoids taking multiple TLB
* before the real interrupt handler is even called.
*/
static struct pool intrhand_pool;
/*
* By default, each interrupt handle is 64-bytes in size. This allows
* some room for future growth.
*/
#define INTRHAND_SIZE 64
#define INTEVT_TO_MAP_INDEX(x) ((x) >> 5)
#define INTEVT_TO_IH_INDEX(x) intevt_to_ih[INTEVT_TO_MAP_INDEX(x)]
#define INTEVT_IH(x) (&intrhand[INTEVT_TO_IH_INDEX(x)])
static void (*intr_enable)(void *, u_int, int, int);
static void (*intr_disable)(void *, u_int);
@ -109,42 +124,22 @@ struct evcnt _sh5_intr_events[NIPL];
extern const char intrnames[]; /* Defined in port-specific code */
void sh5_intr_dispatch(struct intrframe *);
static struct intrhand *alloc_ih(void);
static void free_ih(struct intrhand *);
static int spurious_interrupt(void *);
/*
* SH5 Interrupt support.
*/
void
sh5_intr_init(int nhandles,
void (*int_enable)(void *, u_int, int, int),
sh5_intr_init(void (*int_enable)(void *, u_int, int, int),
void (*int_disable)(void *, u_int),
void *arg)
{
struct intrhand *ih;
const char *iname;
int i;
ih = malloc(sizeof(*ih) * (nhandles + 1), M_DEVBUF, M_NOWAIT);
if (ih == NULL)
panic("sh5_intr_init: Out of memory");
pool_init(&intrhand_pool, INTRHAND_SIZE, SH5_CACHELINE_SIZE,
0, 0, NULL, NULL);
memset(ih, 0, sizeof(*ih) * (nhandles + 1));
intrhand = ih;
szintrhand = nhandles + 1;
intr_enable = int_enable;
intr_disable = int_disable;
intr_arg = arg;
ih->ih_func = spurious_interrupt;
ih->ih_arg = NULL;
ih->ih_idx = 0;
ih->ih_level = 0;
ih->ih_intevt = 0;
ih->ih_type = IST_NONE;
iname = intrnames;
for (i = 0; i < NIPL; i++) {
evcnt_attach_dynamic(&_sh5_intr_events[i], EVCNT_TYPE_INTR,
@ -158,11 +153,20 @@ sh5_intr_establish(int intevt, int trigger, int level,
int (*ih_func)(void *), void *ih_arg)
{
struct intrhand *ih;
int idx;
KDASSERT(szintrhand != 0);
KDASSERT(intr_enable != NULL);
KDASSERT(level > 0 && level < NIPL);
ih = alloc_ih();
idx = INTEVT_TO_IH_INDEX(intevt);
KDASSERT(idx < (sizeof(intrhand) / sizeof(struct intrhand *)));
if (intrhand[idx] != NULL)
return (NULL); /* Perhaps panic? */
if ((ih = sh5_intr_alloc_handle(sizeof(*ih))) == NULL)
return (NULL);
ih->ih_func = ih_func;
ih->ih_arg = ih_arg;
ih->ih_level = level;
@ -170,7 +174,7 @@ sh5_intr_establish(int intevt, int trigger, int level,
ih->ih_type = trigger;
/* Map interrupt handler */
INTEVT_TO_IH_INDEX(intevt) = ih->ih_idx;
intrhand[idx] = ih;
(*intr_enable)(intr_arg, intevt, trigger, level);
@ -181,13 +185,18 @@ void
sh5_intr_disestablish(void *cookie)
{
struct intrhand *ih = cookie;
int idx;
idx = INTEVT_TO_IH_INDEX(ih->ih_intevt);
KDASSERT(idx < (sizeof(intrhand) / sizeof(struct intrhand *)));
KDASSERT(intrhand[idx] == ih);
(*intr_disable)(intr_arg, ih->ih_intevt);
/* Unmap interrupt handler */
INTEVT_TO_IH_INDEX(ih->ih_intevt) = 0;
intrhand[idx] = NULL;
free_ih(ih);
sh5_intr_free_handle(ih);
}
struct evcnt *
@ -198,17 +207,43 @@ sh5_intr_evcnt(void *cookie)
return (&_sh5_intr_events[ih->ih_level]);
}
void *
sh5_intr_alloc_handle(size_t size)
{
if (size > INTRHAND_SIZE)
panic("sh5_intr_alloc_handle: size > %d", INTRHAND_SIZE);
return (pool_get(&intrhand_pool, 0));
}
void
sh5_intr_free_handle(void *handle)
{
pool_put(&intrhand_pool, handle);
}
void
sh5_intr_dispatch(struct intrframe *fr)
{
extern u_long intrcnt[];
struct intrhand *ih;
int idx;
KDASSERT(INTEVT_TO_MAP_INDEX(fr->if_state.sf_intevt) < 0x100);
idx = INTEVT_TO_IH_INDEX(fr->if_state.sf_intevt);
KDASSERT(idx < (sizeof(intrhand) / sizeof(struct intrhand *)));
ih = INTEVT_IH(fr->if_state.sf_intevt);
KDASSERT(ih->ih_func != NULL);
if ((ih = intrhand[idx]) == NULL) {
int level;
__asm __volatile("getcon sr, %0" : "=r"(level));
printf(
"sh5_intr_dispatch: spurious level %d irq: intevt 0x%lx\n",
(level >> SH5_CONREG_SR_IMASK_SHIFT) &
SH5_CONREG_SR_IMASK_MASK,
(unsigned long)fr->if_state.sf_intevt);
return;
}
_sh5_intr_events[ih->ih_level].ev_count++;
intrcnt[ih->ih_level]++;
@ -221,47 +256,12 @@ sh5_intr_dispatch(struct intrframe *fr)
/*NOTREACHED*/
}
#if 0
/* We don't support Edge or Pulse triggered interrupts at this time */
printf("sh5_intr_dispatch: Unclaimed %s-triggered interrupt...\n",
(ih->ih_type == IST_PULSE) ? "Pulse" : "Edge");
printf("sh5_intr_dispatch: INTEVT=0x%x, level=%d\n",
(int) fr->if_state.sf_intevt, ih->ih_level);
}
/*
* Interrupt handle allocator.
*/
static struct intrhand *
alloc_ih()
{
/* #0 is reserved for unregistered interrupt. */
struct intrhand *ih = &intrhand[1];
int i;
for (i = 1; i < szintrhand; i++, ih++)
if (ih->ih_idx == 0) { /* no driver use this. */
ih->ih_idx = i; /* register myself */
return (ih);
}
panic("intc_alloc_ih: Out of interrupt handles!");
return (NULL);
}
static void
free_ih(struct intrhand *ih)
{
memset(ih, 0, sizeof(*ih));
}
static int
spurious_interrupt(void *arg)
{
struct intrframe *fr = arg;
printf("Spurious Interrupt: INTEVT=0x%x\n",
(int) fr->if_state.sf_intevt);
panic("oops");
/* NOTREACHED */
return (0);
printf("sh5_intr_dispatch: INTEVT=0x%lx, level=%d\n",
(unsigned long) fr->if_state.sf_intevt, ih->ih_level);
#endif
}