309 lines
7.1 KiB
C
309 lines
7.1 KiB
C
/* $NetBSD: isr.c,v 1.32 1997/04/28 21:48:25 gwr Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 1996 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Adam Glass and Gordon W. Ross.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the NetBSD
|
|
* Foundation, Inc. and its contributors.
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* This handles multiple attach of autovectored interrupts,
|
|
* and the handy software interrupt request register.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/device.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/vmmeter.h>
|
|
|
|
#include <net/netisr.h>
|
|
|
|
#include <machine/autoconf.h>
|
|
#include <machine/cpu.h>
|
|
#include <machine/mon.h>
|
|
#include <machine/obio.h>
|
|
#include <machine/machdep.h>
|
|
|
|
#include <sun3/sun3/vector.h>
|
|
|
|
extern int intrcnt[]; /* statistics */
|
|
|
|
#define NUM_LEVELS 8
|
|
|
|
struct isr {
|
|
struct isr *isr_next;
|
|
isr_func_t isr_intr;
|
|
void *isr_arg;
|
|
int isr_ipl;
|
|
};
|
|
|
|
void set_vector_entry __P((int, void *));
|
|
void * get_vector_entry __P((int));
|
|
|
|
/*
|
|
* These are called from locore. The "struct clockframe" arg
|
|
* is really just the normal H/W interrupt frame format.
|
|
* (kern_clock really wants it to be named that...)
|
|
*/
|
|
void isr_autovec __P((struct clockframe));
|
|
void isr_vectored __P((struct clockframe));
|
|
|
|
|
|
void
|
|
isr_add_custom(level, handler)
|
|
int level;
|
|
void *handler;
|
|
{
|
|
set_vector_entry(AUTOVEC_BASE + level, handler);
|
|
}
|
|
|
|
|
|
/*
|
|
* netisr junk...
|
|
* XXX - This really belongs in some common file,
|
|
* i.e. src/sys/net/netisr.c
|
|
* Also, should use an array of chars instead of
|
|
* a bitmask to avoid atomicity locking issues.
|
|
*/
|
|
|
|
#include "ether.h" /* for NETHER */
|
|
#include "ppp.h"
|
|
|
|
/*
|
|
* Declarations for the netisr functions...
|
|
* They are in the header files, but that's not
|
|
* really a good reason to drag all those in.
|
|
*/
|
|
void arpintr __P((void));
|
|
void ipintr __P((void));
|
|
void atintr __P((void));
|
|
void nsintr __P((void));
|
|
void clnlintr __P((void));
|
|
void ccittintr __P((void));
|
|
void pppintr __P((void));
|
|
|
|
void netintr()
|
|
{
|
|
int n, s;
|
|
|
|
s = splhigh();
|
|
n = netisr;
|
|
netisr = 0;
|
|
splx(s);
|
|
|
|
#if NETHER > 0
|
|
if (n & (1 << NETISR_ARP))
|
|
arpintr();
|
|
#endif
|
|
#ifdef INET
|
|
if (n & (1 << NETISR_IP))
|
|
ipintr();
|
|
#endif
|
|
#ifdef NETATALK
|
|
if (n & (1 << NETISR_ATALK))
|
|
atintr();
|
|
#endif
|
|
#ifdef NS
|
|
if (n & (1 << NETISR_NS))
|
|
nsintr();
|
|
#endif
|
|
#ifdef ISO
|
|
if (n & (1 << NETISR_ISO))
|
|
clnlintr();
|
|
#endif
|
|
#ifdef CCITT
|
|
if (n & (1 << NETISR_CCITT)) {
|
|
ccittintr();
|
|
}
|
|
#endif
|
|
#if NPPP > 0
|
|
if (n & (1 << NETISR_PPP)) {
|
|
pppintr();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
static struct isr *isr_autovec_list[NUM_LEVELS];
|
|
|
|
/*
|
|
* This is called by the assembly routines
|
|
* for handling auto-vectored interupts.
|
|
*/
|
|
void isr_autovec(cf)
|
|
struct clockframe cf;
|
|
{
|
|
struct isr *isr;
|
|
register int n, ipl, vec;
|
|
|
|
vec = (cf.cf_vo & 0xFFF) >> 2;
|
|
if ((vec < AUTOVEC_BASE) || (vec >= (AUTOVEC_BASE+8)))
|
|
panic("isr_autovec: bad vec");
|
|
ipl = vec - AUTOVEC_BASE;
|
|
|
|
n = intrcnt[ipl];
|
|
intrcnt[ipl] = n+1;
|
|
cnt.v_intr++;
|
|
|
|
isr = isr_autovec_list[ipl];
|
|
if (isr == NULL) {
|
|
if (n == 0)
|
|
printf("isr_autovec: ipl %d unexpected\n", ipl);
|
|
return;
|
|
}
|
|
|
|
/* Give all the handlers a chance. */
|
|
n = 0;
|
|
while (isr) {
|
|
n |= isr->isr_intr(isr->isr_arg);
|
|
isr = isr->isr_next;
|
|
}
|
|
if (!n)
|
|
printf("isr_autovec: ipl %d not claimed\n", ipl);
|
|
}
|
|
|
|
/*
|
|
* Establish an interrupt handler.
|
|
* Called by driver attach functions.
|
|
*/
|
|
void isr_add_autovect(handler, arg, level)
|
|
isr_func_t handler;
|
|
void *arg;
|
|
int level;
|
|
{
|
|
struct isr *new_isr;
|
|
|
|
if ((level < 0) || (level >= NUM_LEVELS))
|
|
panic("isr_add: bad level=%d", level);
|
|
new_isr = (struct isr *)
|
|
malloc(sizeof(struct isr), M_DEVBUF, M_NOWAIT);
|
|
if (!new_isr)
|
|
panic("isr_add: malloc failed");
|
|
|
|
new_isr->isr_intr = handler;
|
|
new_isr->isr_arg = arg;
|
|
new_isr->isr_ipl = level;
|
|
new_isr->isr_next = isr_autovec_list[level];
|
|
isr_autovec_list[level] = new_isr;
|
|
}
|
|
|
|
struct vector_handler {
|
|
isr_func_t func;
|
|
void *arg;
|
|
};
|
|
static struct vector_handler isr_vector_handlers[192];
|
|
|
|
/*
|
|
* This is called by the assembly glue
|
|
* for handling vectored interupts.
|
|
*/
|
|
void
|
|
isr_vectored(cf)
|
|
struct clockframe cf;
|
|
{
|
|
struct vector_handler *vh;
|
|
register int ipl, vec;
|
|
|
|
vec = (cf.cf_vo & 0xFFF) >> 2;
|
|
ipl = getsr();
|
|
ipl = (ipl >> 8) & 7;
|
|
|
|
intrcnt[ipl]++;
|
|
cnt.v_intr++;
|
|
|
|
if (vec < 64 || vec >= 256) {
|
|
printf("isr_vectored: vector=0x%x (invalid)\n", vec);
|
|
return;
|
|
}
|
|
vh = &isr_vector_handlers[vec - 64];
|
|
if (vh->func == NULL) {
|
|
printf("isr_vectored: vector=0x%x (nul func)\n", vec);
|
|
set_vector_entry(vec, (void *)badtrap);
|
|
return;
|
|
}
|
|
|
|
/* OK, call the isr function. */
|
|
if (vh->func(vh->arg) == 0)
|
|
printf("isr_vectored: vector=0x%x (not claimed)\n", vec);
|
|
}
|
|
|
|
/*
|
|
* Establish an interrupt handler.
|
|
* Called by driver attach functions.
|
|
*/
|
|
extern void _isr_vectored __P((void));
|
|
void
|
|
isr_add_vectored(func, arg, level, vec)
|
|
isr_func_t func;
|
|
void *arg;
|
|
int level, vec;
|
|
{
|
|
struct vector_handler *vh;
|
|
|
|
if (vec < 64 || vec >= 256) {
|
|
printf("isr_add_vectored: vect=0x%x (invalid)\n", vec);
|
|
return;
|
|
}
|
|
vh = &isr_vector_handlers[vec - 64];
|
|
if (vh->func) {
|
|
printf("isr_add_vectored: vect=0x%x (in use)\n", vec);
|
|
return;
|
|
}
|
|
vh->func = func;
|
|
vh->arg = arg;
|
|
set_vector_entry(vec, (void *)_isr_vectored);
|
|
}
|
|
|
|
/*
|
|
* XXX - could just kill these...
|
|
*/
|
|
void
|
|
set_vector_entry(entry, handler)
|
|
int entry;
|
|
void *handler;
|
|
{
|
|
if ((entry <0) || (entry >= NVECTORS))
|
|
panic("set_vector_entry: setting vector too high or low\n");
|
|
vector_table[entry] = handler;
|
|
}
|
|
|
|
void *
|
|
get_vector_entry(entry)
|
|
int entry;
|
|
{
|
|
if ((entry <0) || (entry >= NVECTORS))
|
|
panic("get_vector_entry: setting vector too high or low\n");
|
|
return ((void *) vector_table[entry]);
|
|
}
|