With the new IPL world, things are easier for us: if we can get the

nell hardware interrupt handler run at IPL_VM, we can call the socket
drivers interrupt handler directly.
This is always possible on sparc64, but on sparc we might have to fall
back to the old softint bounce. Since this uses arbitrary IPLs, we
can not use the new softint_* for this - we'll have to use the old
sparc_softintr_* functions.
This commit is contained in:
martin 2008-01-06 02:29:58 +00:00
parent 0c0de8072e
commit 258a4b78cf
1 changed files with 84 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: stp4020.c,v 1.52 2007/10/19 12:01:12 ad Exp $ */
/* $NetBSD: stp4020.c,v 1.53 2008/01/06 02:29:58 martin Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: stp4020.c,v 1.52 2007/10/19 12:01:12 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: stp4020.c,v 1.53 2008/01/06 02:29:58 martin Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -105,8 +105,10 @@ struct stp4020_socket {
int sock; /* Socket number (0 or 1) */
int sbus_intno; /* Do we use first (0) or second (1)
interrupt? */
#ifndef SUN4U
int int_enable; /* ICR0 value for interrupt enabled */
int int_disable; /* ICR0 value for interrupt disabled */
#endif
bus_space_tag_t tag; /* socket control io */
bus_space_handle_t regs; /* space */
bus_space_tag_t pcmciat; /* io space for pcmcia */
@ -114,7 +116,9 @@ struct stp4020_socket {
int (*intrhandler) /* Card driver interrupt handler */
(void *);
void *intrarg; /* Card interrupt handler argument */
#ifndef SUN4U
void *softint; /* cookie for the softintr */
#endif
struct {
bus_space_handle_t winaddr;/* this window's address */
@ -131,6 +135,9 @@ struct stp4020_softc {
SIMPLEQ_HEAD(, stp4020_event) events; /* Pending events for thread */
struct stp4020_socket sc_socks[STP4020_NSOCK];
#ifndef SUN4U
bool sc_use_softint;
#endif
};
@ -140,7 +147,9 @@ static void stp4020attach(struct device *, struct device *, void *);
static int stp4020_intr(void *);
static void stp4020_map_window(struct stp4020_socket *h, int win, int speed);
static void stp4020_calc_speed(int bus_speed, int ns, int *length, int *cmd_delay);
#ifndef SUN4U
static void stp4020_intr_dispatch(void *arg);
#endif
CFATTACH_DECL(nell, sizeof(struct stp4020_softc),
stp4020match, stp4020attach, NULL, NULL);
@ -366,13 +375,9 @@ stp4020attach(parent, self, aux)
struct sbus_attach_args *sa = aux;
struct stp4020_softc *sc = (void *)self;
bus_space_tag_t tag;
int rev;
int i, sbus_intno;
int rev, i, sbus_intno, hw_ipl;
bus_space_handle_t bh;
/* lsb of our config flags decides which interrupt we use */
sbus_intno = device_cfdata(&sc->sc_dev)->cf_flags & 1;
/* Transfer bus tags */
#ifdef SUN4U
tag = sa->sa_bustag;
@ -390,6 +395,46 @@ stp4020attach(parent, self, aux)
tag->sparc_write_8 = stp4020_write_8;
#endif /* SUN4U */
/* check interrupt options, decide if we need a softint */
#ifdef SUN4U
/*
* On sparc64 the hardware interrupt priority does not restrict
* the IPL we run our interrupt handler on, so we can always just
* use the first interrupt and reqest the handler to run at
* IPL_VM.
*/
sbus_intno = 0;
hw_ipl = IPL_VM;
#else
/*
* We need to check if one of the available interrupts has
* a priority that allows us to establish a handler at IPL_VM.
* If not (hard to imagine), use a soft interrupt.
*/
sbus_intno = -1;
for (i = 0; i < sa->sa_nintr; i++) {
struct sbus_softc *bus =
(struct sbus_softc *) sa->sa_bustag->cookie;
int ipl = bus->sc_intr2ipl[sa->sa_intr[i].oi_pri];
if (ipl <= IPL_VM) {
sbus_intno = i;
sc->sc_use_softint = false;
hw_ipl = IPL_VM;
break;
}
}
if (sbus_intno == -1) {
/*
* We have not found a usable hardware interrupt - so
* use a softint to bounce to the proper IPL.
*/
printf("no usable HW interrupt found, using softint\n");
sbus_intno = 0;
sc->sc_use_softint = true;
hw_ipl = IPL_NONE;
}
#endif
/* Set up per-socket static initialization */
sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc;
sc->sc_socks[0].tag = sc->sc_socks[1].tag = sa->sa_bustag;
@ -460,7 +505,7 @@ stp4020attach(parent, self, aux)
if (sa->sa_nintr > sbus_intno) {
bus_intr_establish(sa->sa_bustag,
sa->sa_intr[sbus_intno].oi_pri,
IPL_NONE, stp4020_intr, sc);
hw_ipl, stp4020_intr, sc);
}
rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
@ -503,9 +548,11 @@ stp4020_attach_socket(h, speed)
/* no interrupt handlers yet */
h->intrhandler = NULL;
h->intrarg = NULL;
#ifndef SUN4U
h->softint = NULL;
h->int_enable = 0;
h->int_disable = 0;
#endif
/* Map all three windows */
stp4020_map_window(h, STP_WIN_ATTR, speed);
@ -623,6 +670,7 @@ stp4020_queue_event(sc, sock, event)
wakeup(&sc->events);
}
#ifndef SUN4U
/*
* Softinterrupt called to invoke the real driver interrupt handler.
*/
@ -641,17 +689,23 @@ stp4020_intr_dispatch(arg)
stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable);
splx(s);
}
#endif
int
stp4020_intr(arg)
void *arg;
{
struct stp4020_softc *sc = arg;
int i, s, r = 0, cd_change = 0;
#ifndef SUN4U
int s;
#endif
int i, r = 0, cd_change = 0;
#ifndef SUN4U
/* protect hardware access by splhigh against softint */
s = splhigh();
#endif
/*
* Check each socket for pending requests.
@ -710,17 +764,21 @@ stp4020_intr(arg)
continue;
}
#ifndef SUN4U
/*
* Schedule softint to invoke driver interrupt
* handler
*/
if (h->softint != NULL)
softint_schedule(h->softint);
sparc_softintr_schedule(h->softint);
/*
* Disable this sbus interrupt, until the soft-int
* handler had a chance to run
*/
stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_disable);
#else
(*h->intrhandler)(h->intrarg);
#endif
}
/* informational messages */
@ -762,7 +820,9 @@ stp4020_intr(arg)
printf("stp4020[%d]: unhandled interrupt: 0x%x\n", h->sock, v);
}
#ifndef SUN4U
splx(s);
#endif
return (r);
}
@ -1022,12 +1082,16 @@ stp4020_chip_socket_settype(pch, type)
|STP4020_ICR0_SPKREN;
v |= h->sbus_intno ? STP4020_ICR0_IOILVL_SB1
: STP4020_ICR0_IOILVL_SB0;
#ifndef SUN4U
h->int_enable = v;
h->int_disable = v & ~STP4020_ICR0_IOIE;
#endif
DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname));
} else {
v |= STP4020_ICR0_IFTYPE_MEM;
#ifndef SUN4U
h->int_enable = h->int_disable = v;
#endif
DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname));
DPRINTF(("%s: configuring card for MEM ONLY useage\n", h->sc->sc_dev.dv_xname));
}
@ -1073,8 +1137,13 @@ stp4020_chip_intr_establish(pch, pf, ipl, handler, arg)
h->intrhandler = handler;
h->intrarg = arg;
h->softint = softint_establish(ipl, stp4020_intr_dispatch, h);
return h->softint;
#ifndef SUN4U
if (h->sc->sc_use_softint) {
h->softint = sparc_softintr_establish(ipl, stp4020_intr_dispatch, h);
return h->softint;
}
#endif
return h;
}
void
@ -1086,10 +1155,12 @@ stp4020_chip_intr_disestablish(pch, ih)
h->intrhandler = NULL;
h->intrarg = NULL;
#ifndef SUN4U
if (h->softint) {
softint_disestablish(h->softint);
sparc_softintr_disestablish(h->softint);
h->softint = NULL;
}
#endif
}
/*