NetBSD-5.0.2/sys/arch/sun68k/sun68k/isr.c
/* $NetBSD: isr.c,v 1.23 2008/06/22 17:34:25 tsutsui 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.
*
* 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.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: isr.c,v 1.23 2008/06/22 17:34:25 tsutsui Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/vmmeter.h>
#include <sys/cpu.h>
#include <sys/intr.h>
#include <uvm/uvm_extern.h>
#include <net/netisr.h>
#include <machine/autoconf.h>
#include <machine/mon.h>
#include <sun68k/sun68k/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;
};
#if 0
#define _IPL_NSOFT (_IPL_SOFT_LEVEL_MAX - _IPL_SOFT_LEVEL_MIN + 1)
#endif
int idepth;
void set_vector_entry(int, void *);
void *get_vector_entry(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 (struct clockframe);
void isr_vectored(struct clockframe);
void
isr_add_custom(int level, void *handler)
{
set_vector_entry(AUTOVEC_BASE + level, handler);
}
static struct isr *isr_autovec_list[NUM_LEVELS];
/*
* This is called by the assembly routines
* for handling auto-vectored interrupts.
*/
void
isr_autovec(struct clockframe cf)
{
struct isr *isr;
int n, ipl, vec;
idepth++;
vec = (cf.cf_vo & 0xFFF) >> 2;
#ifdef DIAGNOSTIC
if ((vec < AUTOVEC_BASE) || (vec >= (AUTOVEC_BASE + NUM_LEVELS)))
panic("isr_autovec: bad vec");
#endif
ipl = vec - AUTOVEC_BASE;
n = intrcnt[ipl];
intrcnt[ipl] = n + 1;
uvmexp.intrs++;
isr = isr_autovec_list[ipl];
if (isr == NULL) {
if (n == 0)
printf("isr_autovec: ipl %d unexpected\n", ipl);
goto out;
}
/* Give all the handlers a chance. */
n = 0;
while (isr) {
n |= (*isr->isr_intr)(isr->isr_arg);
isr = isr->isr_next;
}
if (n == 0)
printf("isr_autovec: ipl %d not claimed\n", ipl);
out:
idepth--;
ATOMIC_CAS_CHECK(&cf);
}
/*
* Establish an interrupt handler.
* Called by driver attach functions.
*/
void
isr_add_autovect(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 = malloc(sizeof(struct isr), M_DEVBUF, M_NOWAIT);
if (new_isr == NULL)
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 interrupts.
*/
void
isr_vectored(struct clockframe cf)
{
struct vector_handler *vh;
int ipl, vec;
idepth++;
vec = (cf.cf_vo & 0xFFF) >> 2;
ipl = _getsr();
ipl = (ipl >> 8) & 7;
intrcnt[ipl]++;
uvmexp.intrs++;
#ifdef DIAGNOSTIC
if (vec < 64 || vec >= 256) {
printf("isr_vectored: vector=0x%x (invalid)\n", vec);
goto out;
}
#endif
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);
goto out;
}
/* OK, call the isr function. */
if ((*vh->func)(vh->arg) == 0)
printf("isr_vectored: vector=0x%x (not claimed)\n", vec);
out:
idepth--;
ATOMIC_CAS_CHECK(&cf);
}
/*
* Establish an interrupt handler.
* Called by driver attach functions.
*/
extern void _isr_vectored(void);
void
isr_add_vectored(isr_func_t func, void *arg, int level, int 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(int entry, void *handler)
{
if ((entry < 0) || (entry >= NVECTORS))
panic("set_vector_entry: setting vector too high or low");
vector_table[entry] = handler;
}
void *
get_vector_entry(int entry)
{
if ((entry < 0) || (entry >= NVECTORS))
panic("get_vector_entry: setting vector too high or low");
return (void *)vector_table[entry];
}
const uint16_t ipl2psl_table[NIPL] = {
[IPL_NONE] = PSL_S | PSL_IPL0,
[IPL_SOFTBIO] = PSL_S | PSL_IPL1,
[IPL_SOFTCLOCK] = PSL_S | PSL_IPL1,
[IPL_SOFTNET] = PSL_S | PSL_IPL1,
[IPL_SOFTSERIAL] = PSL_S | PSL_IPL3,
[IPL_VM] = PSL_S | PSL_IPL4,
[IPL_SCHED] = PSL_S | PSL_IPL6,
[IPL_HIGH] = PSL_S | PSL_IPL7,
};