Call interrupt handlers from a soft interrupt to decouple them from the

(sometimes excessive) SPL assigned by the firmware to the sbus interrupt.
Protect access to hardware by splhigh().
This commit is contained in:
martin 2003-01-02 20:01:57 +00:00
parent 606c1fd1c5
commit 12da8a0066
1 changed files with 67 additions and 26 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: stp4020.c,v 1.30 2003/01/01 00:10:24 thorpej Exp $ */
/* $NetBSD: stp4020.c,v 1.31 2003/01/02 20:01:57 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.30 2003/01/01 00:10:24 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: stp4020.c,v 1.31 2003/01/02 20:01:57 martin Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -106,13 +106,16 @@ struct stp4020_socket {
int sock; /* Socket number (0 or 1) */
int sbus_intno; /* Do we use first (0) or second (1)
interrupt? */
int int_enable; /* ICR0 value for interrupt enabled */
int int_disable; /* ICR0 value for interrupt disabled */
bus_space_tag_t tag; /* socket control space */
bus_space_handle_t regs; /* */
struct device *pcmcia; /* Associated PCMCIA device */
int (*intrhandler) /* Card driver interrupt handler */
__P((void *));
void *intrarg; /* Card interrupt handler argument */
int ipl; /* Interrupt level suggested by card */
void *softint; /* cookie for the softintr */
struct {
bus_space_handle_t winaddr;/* this window's address */
} windows[STP4020_NWIN];
@ -139,6 +142,7 @@ static void stp4020attach __P((struct device *, struct device *, void *));
static int stp4020_intr __P((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 *delay);
static void stp4020_intr_dispatch(void *arg);
CFATTACH_DECL(nell, sizeof(struct stp4020_softc),
stp4020match, stp4020attach, NULL, NULL);
@ -280,12 +284,10 @@ stp4020attach(parent, self, aux)
{
struct sbus_attach_args *sa = aux;
struct stp4020_softc *sc = (void *)self;
int node, rev;
int rev;
int i, sbus_intno;
bus_space_handle_t bh;
node = sa->sa_node;
/* lsb of our config flags decides which interrupt we use */
sbus_intno = sc->sc_dev.dv_cfdata->cf_flags & 1;
@ -394,6 +396,13 @@ stp4020_attach_socket(h, speed)
struct pcmciabus_attach_args paa;
int v;
/* no interrupt handlers yet */
h->intrhandler = NULL;
h->intrarg = NULL;
h->softint = NULL;
h->int_enable = 0;
h->int_disable = 0;
/* Map all three windows */
stp4020_map_window(h, STP_WIN_ATTR, speed);
stp4020_map_window(h, STP_WIN_MEM, speed);
@ -525,12 +534,35 @@ stp4020_queue_event(sc, sock, event)
wakeup(&sc->events);
}
/*
* Softinterrupt called to invoke the real driver interrupt handler.
*/
static void
stp4020_intr_dispatch(arg)
void *arg;
{
struct stp4020_socket *h = arg;
int s;
/* invoke driver handler */
h->intrhandler(h->intrarg);
/* enable SBUS interrupts for pcmcia interrupts again */
s = splhigh();
stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable);
splx(s);
}
int
stp4020_intr(arg)
void *arg;
{
struct stp4020_softc *sc = arg;
int i, r = 0, cd_change = 0;
int i, s, r = 0, cd_change = 0;
/* protect hardware access by splhigh against softint */
s = splhigh();
/*
* Check each socket for pending requests.
@ -540,10 +572,12 @@ stp4020_intr(arg)
int v;
h = &sc->sc_socks[i];
v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
/* Ack all interrupts at once */
stp4020_wr_sockctl(h, STP4020_ISR0_IDX, STP4020_ISR0_ALL_STATUS_IRQ);
/* Ack all interrupts at once. */
stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
STP4020_ISR0_ALL_STATUS_IRQ);
#ifdef STP4020_DEBUG
if (stp4020_debug != 0) {
@ -581,27 +615,24 @@ stp4020_intr(arg)
card driver says. */
r = 1;
/* ack interrupt */
stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
/* It's a card interrupt */
if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
printf("stp4020[%d]: spurious interrupt?\n",
h->sock);
continue;
}
/* Call card handler, if any */
if (h->intrhandler != NULL) {
/*
* Called without handling of it's requested
* protection level (h->ipl), since we have
* no general queuing mechanism available
* right now and we know for sure we are
* running at a higher protection level
* right now.
*/
(*h->intrhandler)(h->intrarg);
}
/*
* Schedule softint to invoke driver interrupt
* handler
*/
if (h->softint != NULL)
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);
}
/* informational messages */
@ -635,6 +666,7 @@ stp4020_intr(arg)
}
}
splx(s);
return (r);
}
@ -872,6 +904,8 @@ stp4020_chip_socket_enable(pch)
|STP4020_ICR0_SPKREN;
v |= h->sbus_intno ? STP4020_ICR0_IOILVL_SB1
: STP4020_ICR0_IOILVL_SB0;
h->int_enable = v;
h->int_disable = v & ~STP4020_ICR0_IOIE;
DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname));
} else {
v &= ~(STP4020_ICR0_IOILVL|STP4020_ICR0_IFTYPE
@ -915,10 +949,13 @@ stp4020_chip_intr_establish(pch, pf, ipl, handler, arg)
{
struct stp4020_socket *h = (struct stp4020_socket *)pch;
/* only one interrupt handler per slot */
if (h->intrhandler != NULL) return NULL;
h->intrhandler = handler;
h->intrarg = arg;
h->ipl = ipl;
return h;
h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h);
return h->softint;
}
void
@ -930,6 +967,10 @@ stp4020_chip_intr_disestablish(pch, ih)
h->intrhandler = NULL;
h->intrarg = NULL;
if (h->softint) {
softintr_disestablish(h->softint);
h->softint = NULL;
}
}
/*