arm32 kernel source restructure
- These files are IOMD specific and as such are moving to the IOMD specific directory arch/arm32/iomd
This commit is contained in:
parent
16ef9e8936
commit
a18400067c
@ -1,378 +0,0 @@
|
||||
/* $NetBSD: clock.c,v 1.13 1997/07/31 01:08:01 mark Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1996 Mark Brinicombe.
|
||||
* Copyright (c) 1994 Brini.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software written for Brini by Mark Brinicombe
|
||||
*
|
||||
* 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 Brini.
|
||||
* 4. The name of the company nor the name of the author may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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.
|
||||
*
|
||||
* RiscBSD kernel project
|
||||
*
|
||||
* clock.c
|
||||
*
|
||||
* Timer related machine specific code
|
||||
*
|
||||
* Created : 29/09/94
|
||||
*/
|
||||
|
||||
/* Include header files */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/time.h>
|
||||
#include <dev/clock_subr.h>
|
||||
|
||||
#include <machine/katelib.h>
|
||||
#include <machine/iomd.h>
|
||||
#include <machine/irqhandler.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/rtc.h>
|
||||
|
||||
#include "rtc.h"
|
||||
|
||||
#if NRTC == 0
|
||||
#error "Need at least one RTC device for timeofday management"
|
||||
#endif
|
||||
|
||||
#define TIMER0_COUNT 20000 /* 100Hz */
|
||||
#define TIMER_FREQUENCY 2000000 /* 2MHz clock */
|
||||
#define TICKS_PER_MICROSECOND (TIMER_FREQUENCY / 1000000)
|
||||
|
||||
static irqhandler_t clockirq;
|
||||
static irqhandler_t statclockirq;
|
||||
|
||||
|
||||
/*
|
||||
* int clockhandler(struct clockframe *frame)
|
||||
*
|
||||
* Function called by timer 0 interrupts. This just calls
|
||||
* hardclock(). Eventually the irqhandler can call hardclock() directly
|
||||
* but for now we use this function so that we can debug IRQ's
|
||||
*/
|
||||
|
||||
int
|
||||
clockhandler(frame)
|
||||
struct clockframe *frame;
|
||||
{
|
||||
#ifdef RC7500
|
||||
extern void setleds();
|
||||
static int leds = 0;
|
||||
|
||||
setleds(1 << leds);
|
||||
leds++;
|
||||
if (leds >> 3)
|
||||
leds = 0;
|
||||
#endif /* RC7500 */
|
||||
|
||||
hardclock(frame);
|
||||
return(0); /* Pass the interrupt on down the chain */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* int statclockhandler(struct clockframe *frame)
|
||||
*
|
||||
* Function called by timer 1 interrupts. This just calls
|
||||
* statclock(). Eventually the irqhandler can call statclock() directly
|
||||
* but for now we use this function so that we can debug IRQ's
|
||||
*/
|
||||
|
||||
int
|
||||
statclockhandler(frame)
|
||||
struct clockframe *frame;
|
||||
{
|
||||
statclock(frame);
|
||||
return(0); /* Pass the interrupt on down the chain */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void setstatclockrate(int hz)
|
||||
*
|
||||
* Set the stat clock rate. The stat clock uses timer1
|
||||
*/
|
||||
|
||||
void
|
||||
setstatclockrate(hz)
|
||||
int hz;
|
||||
{
|
||||
int count;
|
||||
|
||||
count = TIMER_FREQUENCY / hz;
|
||||
|
||||
printf("Setting statclock to %dHz (%d ticks)\n", hz, count);
|
||||
|
||||
WriteByte(IOMD_T1LOW, (count >> 0) & 0xff);
|
||||
WriteByte(IOMD_T1HIGH, (count >> 8) & 0xff);
|
||||
|
||||
/* reload the counter */
|
||||
|
||||
WriteByte(IOMD_T1GO, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void cpu_initclocks(void)
|
||||
*
|
||||
* Initialise the clocks.
|
||||
* This sets up the two timers in the IOMD and installs the IRQ handlers
|
||||
*
|
||||
* NOTE: Currently only timer 0 is setup and the IRQ handler is not installed
|
||||
*/
|
||||
|
||||
void
|
||||
cpu_initclocks()
|
||||
{
|
||||
int count;
|
||||
|
||||
/*
|
||||
* Load timer 0 with count down value
|
||||
* This timer generates 100Hz interrupts for the system clock
|
||||
*/
|
||||
|
||||
printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
|
||||
|
||||
count = TIMER_FREQUENCY / hz;
|
||||
WriteByte(IOMD_T0LOW, (count >> 0) & 0xff);
|
||||
WriteByte(IOMD_T0HIGH, (count >> 8) & 0xff);
|
||||
|
||||
/* reload the counter */
|
||||
|
||||
WriteByte(IOMD_T0GO, 0);
|
||||
|
||||
clockirq.ih_func = clockhandler;
|
||||
clockirq.ih_arg = 0;
|
||||
clockirq.ih_level = IPL_CLOCK;
|
||||
clockirq.ih_name = "TMR0 hard clk";
|
||||
if (irq_claim(IRQ_TIMER0, &clockirq) == -1)
|
||||
panic("Cannot installer timer 0 IRQ handler\n");
|
||||
|
||||
if (stathz) {
|
||||
setstatclockrate(stathz);
|
||||
|
||||
statclockirq.ih_func = statclockhandler;
|
||||
statclockirq.ih_arg = 0;
|
||||
statclockirq.ih_level = IPL_CLOCK;
|
||||
if (irq_claim(IRQ_TIMER1, &clockirq) == -1)
|
||||
panic("Cannot installer timer 1 IRQ handler\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void microtime(struct timeval *tvp)
|
||||
*
|
||||
* Fill in the specified timeval struct with the current time
|
||||
* accurate to the microsecond.
|
||||
*/
|
||||
|
||||
void
|
||||
microtime(tvp)
|
||||
struct timeval *tvp;
|
||||
{
|
||||
int s;
|
||||
int tm;
|
||||
int deltatm;
|
||||
static int oldtm;
|
||||
static struct timeval oldtv;
|
||||
|
||||
s = splhigh();
|
||||
|
||||
/*
|
||||
* Latch the current value of the timer and then read it.
|
||||
* This garentees an atmoic reading of the time.
|
||||
*/
|
||||
|
||||
WriteByte(IOMD_T0LATCH, 0);
|
||||
tm = ReadByte(IOMD_T0LOW) + (ReadByte(IOMD_T0HIGH) << 8);
|
||||
deltatm = tm - oldtm;
|
||||
if (deltatm < 0) deltatm += TIMER0_COUNT;
|
||||
if (deltatm < 0) {
|
||||
printf("opps deltatm < 0 tm=%d oldtm=%d deltatm=%d\n",
|
||||
tm, oldtm, deltatm);
|
||||
}
|
||||
oldtm = tm;
|
||||
|
||||
/* Fill in the timeval struct */
|
||||
|
||||
*tvp = time;
|
||||
#ifdef HIGHLY_DUBIOUS
|
||||
tvp->tv_usec += (deltatm / TICKS_PER_MICROSECOND);
|
||||
#else
|
||||
tvp->tv_usec += (tm / TICKS_PER_MICROSECOND);
|
||||
#endif
|
||||
|
||||
/* Make sure the micro seconds don't overflow. */
|
||||
|
||||
while (tvp->tv_usec > 1000000) {
|
||||
tvp->tv_usec -= 1000000;
|
||||
++tvp->tv_sec;
|
||||
}
|
||||
|
||||
/* Make sure the time has advanced. */
|
||||
|
||||
if (tvp->tv_sec == oldtv.tv_sec &&
|
||||
tvp->tv_usec <= oldtv.tv_usec) {
|
||||
tvp->tv_usec = oldtv.tv_usec + 1;
|
||||
if (tvp->tv_usec > 1000000) {
|
||||
tvp->tv_usec -= 1000000;
|
||||
++tvp->tv_sec;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
oldtv = *tvp;
|
||||
(void)splx(s);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
need_proftick(p)
|
||||
struct proc *p;
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Machine-dependent clock routines.
|
||||
*
|
||||
* Inittodr initializes the time of day hardware which provides
|
||||
* date functions.
|
||||
*
|
||||
* Resettodr restores the time of day hardware after a time change.
|
||||
*/
|
||||
|
||||
static int timeset = 0;
|
||||
|
||||
/*
|
||||
* Write back the time of day to the rtc
|
||||
*/
|
||||
|
||||
void
|
||||
resettodr()
|
||||
{
|
||||
struct clock_ymdhms dt;
|
||||
int s;
|
||||
rtc_t rtc;
|
||||
|
||||
if (!timeset)
|
||||
return;
|
||||
|
||||
/* Convert from secs to ymdhms fields */
|
||||
clock_secs_to_ymdhms(time.tv_sec - (rtc_offset * 60), &dt);
|
||||
|
||||
/* Fill out an RTC structure */
|
||||
rtc.rtc_cen = dt.dt_year / 100;
|
||||
rtc.rtc_year = dt.dt_year % 100;
|
||||
rtc.rtc_mon = dt.dt_mon;
|
||||
rtc.rtc_day = dt.dt_day;
|
||||
rtc.rtc_hour = dt.dt_hour;
|
||||
rtc.rtc_min = dt.dt_min;
|
||||
rtc.rtc_sec = dt.dt_sec;
|
||||
rtc.rtc_centi = 0;
|
||||
rtc.rtc_micro = 0;
|
||||
|
||||
/* printf("resettod: %d/%d/%d%d %d:%d:%d\n", rtc.rtc_day,
|
||||
rtc.rtc_mon, rtc.rtc_cen, rtc.rtc_year, rtc.rtc_hour,
|
||||
rtc.rtc_min, rtc.rtc_sec);*/
|
||||
|
||||
/* Pass the time to the todclock device */
|
||||
s = splclock();
|
||||
rtc_write(&rtc);
|
||||
(void)splx(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the time of day register, based on the time base which is, e.g.
|
||||
* from a filesystem.
|
||||
*/
|
||||
|
||||
void
|
||||
inittodr(base)
|
||||
time_t base;
|
||||
{
|
||||
struct clock_ymdhms dt;
|
||||
time_t diff;
|
||||
int s;
|
||||
int days;
|
||||
rtc_t rtc;
|
||||
|
||||
/*
|
||||
* Get the time from the todclock device
|
||||
*/
|
||||
|
||||
s = splclock();
|
||||
if (rtc_read(&rtc) == 0) {
|
||||
(void)splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
(void)splx(s);
|
||||
|
||||
/* Convert to clock_ymdhms structure */
|
||||
dt.dt_sec = rtc.rtc_sec;
|
||||
dt.dt_min = rtc.rtc_min;
|
||||
dt.dt_hour = rtc.rtc_hour;
|
||||
dt.dt_day = rtc.rtc_day;
|
||||
dt.dt_mon = rtc.rtc_mon;
|
||||
dt.dt_year = rtc.rtc_year + (rtc.rtc_cen * 100);
|
||||
|
||||
/* Convert to seconds */
|
||||
time.tv_sec = clock_ymdhms_to_secs(&dt) + (rtc_offset * 60);
|
||||
time.tv_usec = 0;
|
||||
|
||||
/* timeset is used to ensure the time is valid before a resettodr() */
|
||||
|
||||
timeset = 1;
|
||||
|
||||
/* If the base was 0 then no time so keep quiet */
|
||||
|
||||
if (base) {
|
||||
printf("inittodr: %02d:%02d:%02d %02d/%02d/%04d\n",
|
||||
dt.dt_hour, dt.dt_min, dt.dt_sec, dt.dt_day,
|
||||
dt.dt_mon, dt.dt_year);
|
||||
|
||||
diff = time.tv_sec - base;
|
||||
if (diff < 0)
|
||||
diff = - diff;
|
||||
|
||||
if (diff > 60) {
|
||||
days = diff / 86400;
|
||||
printf("Clock has %s %d day%c %ld hours %ld minutes %ld secs\n",
|
||||
((time.tv_sec - base) > 0) ? "gained" : "lost",
|
||||
days, ((days == 1) ? 0 : 's'), (diff / 3600) % 24,
|
||||
(diff / 60) % 60, diff % 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* End of clock.c */
|
@ -1,500 +0,0 @@
|
||||
/* $NetBSD: irq.S,v 1.13 1997/02/10 03:50:56 mark Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1997 Mark Brinicombe.
|
||||
* Copyright (c) 1994 Brini.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software written for Brini by Mark Brinicombe
|
||||
*
|
||||
* 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 Brini.
|
||||
* 4. The name of the company nor the name of the author may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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.
|
||||
*
|
||||
* RiscBSD kernel project
|
||||
*
|
||||
* irq.S
|
||||
*
|
||||
* Low level irq and fiq handlers
|
||||
*
|
||||
* Created : 27/09/94
|
||||
*/
|
||||
|
||||
#include "assym.h"
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/iomd.h>
|
||||
|
||||
sp .req r13
|
||||
lr .req r14
|
||||
pc .req r15
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
*
|
||||
* irq_entry
|
||||
*
|
||||
* Main entry point for the IRQ vector
|
||||
*
|
||||
* This function reads the irq request bits in the IOMD registers
|
||||
* IRQRQA, IRQRQB and DMARQ
|
||||
* It then calls an installed handler for each bit that is set.
|
||||
* The function stray_irqhandler is called if a handler is not defined
|
||||
* for a particular interrupt.
|
||||
* If a interrupt handler is found then it is called with r0 containing
|
||||
* the argument defined in the handler structure. If the field ih_arg
|
||||
* is zero then a pointer to the IRQ frame on the stack is passed instead.
|
||||
*/
|
||||
|
||||
Ldisabled_mask:
|
||||
.word _disabled_mask
|
||||
|
||||
Lcurrent_spl_level:
|
||||
.word _current_spl_level
|
||||
|
||||
Lcurrent_intr_depth:
|
||||
.word _current_intr_depth
|
||||
|
||||
.text
|
||||
.global irq_entry
|
||||
|
||||
/*
|
||||
* Regsister usage
|
||||
*
|
||||
* r6 - Address of current handler
|
||||
* r7 - Pointer to handler pointer list
|
||||
* r8 - Current IRQ requests.
|
||||
* r9 - Used to count through possible IRQ bits.
|
||||
* r10 - Base address of IOMD
|
||||
*/
|
||||
|
||||
irq_entry:
|
||||
sub lr, lr, #0x00000004 /* Adjust the lr */
|
||||
|
||||
PUSHFRAMEINSVC /* Push an interrupt frame */
|
||||
|
||||
/* mov r11, #0x00000000*/ /* Trace back stops here */
|
||||
|
||||
/* Load r8 with the IOMD interrupt requests */
|
||||
|
||||
mov r10, #(IOMD_BASE) /* Point to the IOMD */
|
||||
ldrb r8, [r10, #(IOMD_IRQRQA - IOMD_BASE)] /* Get IRQ request A */
|
||||
ldrb r9, [r10, #(IOMD_IRQRQB - IOMD_BASE)] /* Get IRQ request B */
|
||||
orr r8, r8, r9, lsl #8
|
||||
#ifdef CPU_ARM7500
|
||||
ldrb r9, [r10, #(IOMD_IRQRQC - IOMD_BASE)] /* Get IRQ request C */
|
||||
orr r8, r8, r9, lsl #16
|
||||
ldrb r9, [r10, #(IOMD_IRQRQD - IOMD_BASE)] /* Get IRQ request D */
|
||||
orr r8, r8, r9, lsl #24
|
||||
ldrb r9, [r10, #(IOMD_DMARQ - IOMD_BASE)] /* Get DMA Request */
|
||||
tst r9, #0x10
|
||||
orrne r8, r8, r9, lsl #27
|
||||
#else
|
||||
ldrb r9, [r10, #(IOMD_DMARQ - IOMD_BASE)] /* Get DMA Request */
|
||||
orr r8, r8, r9, lsl #16
|
||||
#endif /* CPU_ARM7500 */
|
||||
|
||||
and r0, r8, #0x7d /* Clear IOMD IRQA bits */
|
||||
strb r0, [r10, #(IOMD_IRQRQA - IOMD_BASE)]
|
||||
|
||||
/*
|
||||
* Note that we have entered the IRQ handler.
|
||||
* We are in SVC mode so we cannot use the processor mode
|
||||
* to determine if we are in an IRQ. Instead we will count the
|
||||
* each time the interrupt handler is nested.
|
||||
*/
|
||||
|
||||
ldr r0, Lcurrent_intr_depth
|
||||
ldr r1, [r0]
|
||||
add r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
/* Block the current requested interrupts */
|
||||
|
||||
ldr r1, Ldisabled_mask
|
||||
ldr r0, [r1]
|
||||
stmfd sp!, {r0}
|
||||
orr r0, r0, r8
|
||||
str r0, [r1]
|
||||
|
||||
/*
|
||||
* Need to block all interrupts at the IPL or lower for
|
||||
* all asserted interrupts.
|
||||
* This basically emulates hardware interrupt priority levels.
|
||||
* Means we need to go through the interrupt mask and for
|
||||
* every asserted interrupt we need to mask out all other
|
||||
* interrupts at the same or lower IPL.
|
||||
* If only we could wait until the main loop but we need to sort
|
||||
* this out first so interrupts can be re-enabled.
|
||||
*
|
||||
* This would benefit from a special ffs type routine
|
||||
*/
|
||||
|
||||
mov r9, #0x00000001
|
||||
ldr r7, Lirqblock
|
||||
|
||||
emulate_hwipl_loop:
|
||||
tst r8, r9
|
||||
ldrne r6, [r7]
|
||||
orrne r0, r0, r6
|
||||
|
||||
add r7, r7, #4
|
||||
mov r9, r9, lsl #1 /* move on to next bit */
|
||||
#ifdef CPU_ARM7500
|
||||
teq r9, #0 /* done the last bit ? */
|
||||
#else
|
||||
teq r9, #(1 << 24) /* done the last bit ? */
|
||||
#endif /* CPU_ARM7500 */
|
||||
bne emulate_hwipl_loop /* no - loop back. */
|
||||
|
||||
str r0, [r1]
|
||||
|
||||
/* Update the IOMD irq masks */
|
||||
|
||||
bl _irq_setmasks
|
||||
|
||||
mrs r0, cpsr_all /* Enable IRQ's */
|
||||
bic r0, r0, #I32_bit
|
||||
msr cpsr_all, r0
|
||||
|
||||
ldr r7, [pc, #irqhandlers - . - 8]
|
||||
mov r9, #0x00000001
|
||||
|
||||
stmfd sp!, {r8}
|
||||
|
||||
irqloop:
|
||||
/* This would benefit from a special ffs type routine */
|
||||
tst r8, r9 /* Is a bit set ? */
|
||||
beq nextirq /* No ? try next bit */
|
||||
|
||||
ldr r6, [r7] /* Get address of first handler structure */
|
||||
|
||||
teq r6, #0x00000000 /* Do we have a handler */
|
||||
moveq r0, r8 /* IRQ requests as arg 0 */
|
||||
beq _stray_irqhandler /* call special handler */
|
||||
|
||||
ldr r0, Lcnt
|
||||
ldr r1, [r0, #(V_INTR)]
|
||||
add r1, r1, #0x00000001
|
||||
str r1, [r0, #(V_INTR)]
|
||||
|
||||
irqchainloop:
|
||||
add lr, pc, #nextinchain - . - 8 /* return address */
|
||||
|
||||
/*
|
||||
* XXX: Should stats be accumlated for every interrupt routine called
|
||||
* or for every physical interrupt that is serviced.
|
||||
*/
|
||||
|
||||
#ifdef IRQSTATS
|
||||
ldr r0, Lintrcnt
|
||||
ldr r1, [r6, #(IH_NUM)]
|
||||
|
||||
add r0, r0, r1, lsl #2
|
||||
ldr r1, [r0]
|
||||
add r1, r1, #0x00000001
|
||||
str r1, [r0]
|
||||
#endif /* IRQSTATS */
|
||||
|
||||
ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */
|
||||
teq r0, #0x00000000 /* If arg is zero pass stack frame */
|
||||
addeq r0, sp, #8 /* ... stack frame */
|
||||
ldr pc, [r6, #(IH_FUNC)] /* Call handler */
|
||||
|
||||
nextinchain:
|
||||
teq r0, #0x00000001 /* Was the irq serviced ? */
|
||||
beq irqdone
|
||||
|
||||
ldr r6, [r6, #(IH_NEXT)]
|
||||
teq r6, #0x00000000
|
||||
bne irqchainloop
|
||||
|
||||
irqdone:
|
||||
nextirq:
|
||||
add r7, r7, #0x00000004 /* update pointer to handlers */
|
||||
mov r9, r9, lsl #1 /* move on to next bit */
|
||||
#ifdef CPU_ARM7500
|
||||
teq r9, #0 /* done the last bit ? */
|
||||
#else
|
||||
teq r9, #(1 << 24) /* done the last bit ? */
|
||||
#endif /* CPU_ARM7500 */
|
||||
bne irqloop /* no - loop back. */
|
||||
|
||||
ldmfd sp!, {r8}
|
||||
|
||||
/* Restore previous disabled mask */
|
||||
ldmfd sp!, {r2}
|
||||
ldr r1, Ldisabled_mask
|
||||
str r2, [r1]
|
||||
bl _irq_setmasks
|
||||
|
||||
bl _dosoftints /* Handle the soft interrupts */
|
||||
|
||||
/* Manage AST's. Maybe this should be done as a soft interrupt ? */
|
||||
|
||||
ldr r0, [sp] /* Get the SPSR from stack */
|
||||
|
||||
and r0, r0, #(PSR_MODE) /* Test for USR32 mode before the IRQ */
|
||||
teq r0, #(PSR_USR32_MODE)
|
||||
ldreq r0, Lastpending /* Do we have an AST pending ? */
|
||||
ldreq r1, [r0]
|
||||
teqeq r1, #0x00000001
|
||||
|
||||
beq irqast /* call the AST handler */
|
||||
|
||||
/* Kill IRQ's in preparation for exit */
|
||||
|
||||
mrs r0, cpsr_all
|
||||
orr r0, r0, #(I32_bit)
|
||||
msr cpsr_all, r0
|
||||
|
||||
/* Decrement the nest count */
|
||||
|
||||
ldr r0, Lcurrent_intr_depth
|
||||
ldr r1, [r0]
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
|
||||
movs pc, lr /* Exit */
|
||||
|
||||
/*
|
||||
* Ok, snag with current intr depth ...
|
||||
* If ast() calls mi_sleep() the current_intr_depth will not be
|
||||
* decremented until the process is woken up. This can result
|
||||
* in the system believing it is still in the interrupt handler.
|
||||
* If we are calling ast() then correct the current_intr_depth
|
||||
* before the call.
|
||||
*/
|
||||
irqast:
|
||||
mov r1, #0x00000000 /* Clear ast_pending */
|
||||
str r1, [r0]
|
||||
|
||||
/* Kill IRQ's so we atomically decrement current_intr_depth */
|
||||
|
||||
mrs r2, cpsr_all
|
||||
orr r3, r2, #(I32_bit)
|
||||
msr cpsr_all, r3
|
||||
|
||||
/* Decrement the nest count */
|
||||
|
||||
ldr r0, Lcurrent_intr_depth
|
||||
ldr r1, [r0]
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
/* Restore IRQ's */
|
||||
msr cpsr_all, r2
|
||||
|
||||
mov r0, sp
|
||||
bl _ast
|
||||
|
||||
/* Kill IRQ's in preparation for exit */
|
||||
|
||||
mrs r0, cpsr_all
|
||||
orr r0, r0, #(I32_bit)
|
||||
msr cpsr_all, r0
|
||||
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
|
||||
movs pc, lr /* Exit */
|
||||
|
||||
|
||||
Lspl_mask:
|
||||
.word _spl_mask /* irq's allowed at current spl level */
|
||||
|
||||
Lcurrent_mask:
|
||||
.word _current_mask /* irq's that are usable */
|
||||
|
||||
Lirqblock:
|
||||
.word _irqblock
|
||||
|
||||
.global _irq_setmasks
|
||||
|
||||
_irq_setmasks:
|
||||
/* Disable interrupts */
|
||||
mrs r3, cpsr_all
|
||||
orr r1, r3, #(I32_bit)
|
||||
msr cpsr_all, r1
|
||||
|
||||
/* Calculate IOMD interrupt mask */
|
||||
ldr r1, Lcurrent_mask /* All the enabled interrupts */
|
||||
ldr r1, [r1]
|
||||
ldr r2, Lspl_mask /* Block due to current spl level */
|
||||
ldr r2, [r2]
|
||||
and r1, r1, r2
|
||||
ldr r2, Ldisabled_mask /* Block due to active interrupts */
|
||||
ldr r2, [r2]
|
||||
bic r1, r1, r2
|
||||
|
||||
mov r0, #(IOMD_BASE) /* Point to the IOMD */
|
||||
strb r1, [r0, #(IOMD_IRQMSKA - IOMD_BASE)] /* Set IRQ mask A */
|
||||
mov r1, r1, lsr #8
|
||||
strb r1, [r0, #(IOMD_IRQMSKB - IOMD_BASE)] /* Set IRQ mask B */
|
||||
mov r1, r1, lsr #8
|
||||
#ifdef CPU_ARM7500
|
||||
strb r1, [r0, #(IOMD_IRQMSKC - IOMD_BASE)]
|
||||
mov r1, r1, lsr #8
|
||||
and r2, r1, #0xef
|
||||
strb r2, [r0, #(IOMD_IRQMSKD - IOMD_BASE)]
|
||||
mov r1, r1, lsr #3
|
||||
and r2, r1, #0x10
|
||||
strb r2, [r0, #(IOMD_DMAMSK - IOMD_BASE)] /* Set DMA mask */
|
||||
#else
|
||||
strb r1, [r0, #(IOMD_DMAMSK - IOMD_BASE)] /* Set DMA mask */
|
||||
#endif /* CPU_ARM7500 */
|
||||
|
||||
/* Restore old cpsr and exit */
|
||||
msr cpsr_all, r3
|
||||
mov pc, lr
|
||||
|
||||
|
||||
Lcnt:
|
||||
.word _cnt
|
||||
|
||||
Lintrcnt:
|
||||
.word _intrcnt
|
||||
|
||||
|
||||
irqhandlers:
|
||||
.word _irqhandlers /* Pointer to array of irqhandlers */
|
||||
|
||||
Lastpending:
|
||||
.word _astpending
|
||||
|
||||
#ifdef IRQSTATS
|
||||
/* These symbols are used by vmstat */
|
||||
|
||||
.text
|
||||
.global __intrnames
|
||||
__intrnames:
|
||||
.word _intrnames
|
||||
|
||||
.data
|
||||
|
||||
.globl _intrnames, _eintrnames, _intrcnt, _eintrcnt
|
||||
_intrnames:
|
||||
.asciz "interrupt 0 "
|
||||
.asciz "softnet " /* reserved0 */
|
||||
.asciz "interrupt 2 "
|
||||
.asciz "interrupt 3 "
|
||||
.asciz "interrupt 4 "
|
||||
.asciz "interrupt 5 "
|
||||
.asciz "interrupt 6 "
|
||||
.asciz "softclock " /* reserved1 */
|
||||
.asciz "softplip " /* reserved2 */
|
||||
.asciz "interrupt 9 "
|
||||
.asciz "interrupt 10 "
|
||||
.asciz "interrupt 11 "
|
||||
.asciz "interrupt 12 "
|
||||
.asciz "interrupt 13 "
|
||||
.asciz "interrupt 14 "
|
||||
.asciz "interrupt 15 "
|
||||
.asciz "dma channel 0"
|
||||
.asciz "dma channel 1"
|
||||
.asciz "dma channel 2"
|
||||
.asciz "dma channel 3"
|
||||
.asciz "interrupt 20 "
|
||||
.asciz "interrupt 21 "
|
||||
.asciz "reserved 3 "
|
||||
.asciz "reserved 4 "
|
||||
.asciz "exp card 0 "
|
||||
.asciz "exp card 1 "
|
||||
.asciz "exp card 2 "
|
||||
.asciz "exp card 3 "
|
||||
.asciz "exp card 4 "
|
||||
.asciz "exp card 5 "
|
||||
.asciz "exp card 6 "
|
||||
.asciz "exp card 7 "
|
||||
_eintrnames:
|
||||
|
||||
.bss
|
||||
.align 0
|
||||
_intrcnt:
|
||||
.space 32*4 /* XXX Should be linked to number of interrupts */
|
||||
_eintrcnt:
|
||||
|
||||
#else /* IRQSTATS */
|
||||
/* Dummy entries to keep vmstat happy */
|
||||
|
||||
.text
|
||||
.globl _intrnames, _eintrnames, _intrcnt, _eintrcnt
|
||||
_intrnames:
|
||||
.long 0
|
||||
_eintrnames:
|
||||
|
||||
_intrcnt:
|
||||
.long 0
|
||||
_eintrcnt:
|
||||
#endif /* IRQSTATS */
|
||||
|
||||
/* FIQ code */
|
||||
|
||||
.text
|
||||
.align 0
|
||||
.global _fiq_setregs /* Sets up the FIQ handler */
|
||||
|
||||
_fiq_setregs:
|
||||
mrs r2, cpsr_all
|
||||
mov r3, r2
|
||||
bic r2, r2, #(PSR_MODE)
|
||||
orr r2, r2, #(PSR_FIQ32_MODE)
|
||||
msr cpsr_all, r2
|
||||
|
||||
ldr r8, [r0, #FH_R8] /* Update FIQ registers*/
|
||||
ldr r9, [r0, #FH_R9]
|
||||
ldr r10, [r0, #FH_R10]
|
||||
ldr r11, [r0, #FH_R11]
|
||||
ldr r12, [r0, #FH_R12]
|
||||
ldr r13, [r0, #FH_R13]
|
||||
|
||||
msr cpsr_all, r3 /* Back to old mode */
|
||||
|
||||
mov pc, lr /* Exit */
|
||||
|
||||
.global _fiq_getregs /* Gets the FIQ registers */
|
||||
|
||||
_fiq_getregs:
|
||||
mrs r2, cpsr_all
|
||||
mov r3, r2
|
||||
bic r2, r2, #(PSR_MODE)
|
||||
orr r2, r2, #(PSR_FIQ32_MODE)
|
||||
msr cpsr_all, r2
|
||||
|
||||
str r8, [r0, #FH_R8] /* Update FIQ registers*/
|
||||
str r9, [r0, #FH_R9]
|
||||
str r10, [r0, #FH_R10]
|
||||
str r11, [r0, #FH_R11]
|
||||
str r12, [r0, #FH_R12]
|
||||
str r13, [r0, #FH_R13]
|
||||
|
||||
msr cpsr_all, r3 /* Back to old mode */
|
||||
|
||||
mov pc, lr /* Exit */
|
||||
|
||||
/* End of irq.S */
|
@ -1,758 +0,0 @@
|
||||
/* $NetBSD: irqhandler.c,v 1.14 1997/04/02 21:52:19 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1996 Mark Brinicombe.
|
||||
* Copyright (c) 1994 Brini.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software written for Brini by Mark Brinicombe
|
||||
*
|
||||
* 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 Brini.
|
||||
* 4. The name of the company nor the name of the author may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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.
|
||||
*
|
||||
* RiscBSD kernel project
|
||||
*
|
||||
* irqhandler.c
|
||||
*
|
||||
* IRQ/FIQ initialisation, claim, release and handler routines
|
||||
*
|
||||
* Created : 30/09/94
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <vm/vm.h>
|
||||
#include <net/netisr.h>
|
||||
|
||||
#include <machine/irqhandler.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/iomd.h>
|
||||
#include <machine/katelib.h>
|
||||
|
||||
#include "podulebus.h"
|
||||
|
||||
irqhandler_t *irqhandlers[NIRQS];
|
||||
fiqhandler_t *fiqhandlers;
|
||||
|
||||
int current_intr_depth = 0;
|
||||
u_int irqmasks[IRQ_LEVELS];
|
||||
u_int current_mask;
|
||||
u_int actual_mask;
|
||||
u_int disabled_mask = 0;
|
||||
u_int spl_mask;
|
||||
u_int soft_interrupts;
|
||||
extern u_int intrcnt[];
|
||||
|
||||
u_int irqblock[NIRQS];
|
||||
|
||||
typedef struct {
|
||||
vm_offset_t physical;
|
||||
vm_offset_t virtual;
|
||||
} pv_addr_t;
|
||||
|
||||
extern pv_addr_t systempage;
|
||||
extern char *_intrnames;
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
int podule_irqhandler __P((void));
|
||||
extern void zero_page_readonly __P((void));
|
||||
extern void zero_page_readwrite __P((void));
|
||||
extern int fiq_setregs __P((fiqhandler_t *));
|
||||
extern int fiq_getregs __P((fiqhandler_t *));
|
||||
extern void set_spl_masks __P((void));
|
||||
|
||||
extern void arpintr __P((void));
|
||||
extern void ipintr __P((void));
|
||||
extern void atintr __P((void));
|
||||
extern void pppintr __P((void));
|
||||
extern void plipintr __P((void));
|
||||
|
||||
/*
|
||||
* void irq_init(void)
|
||||
*
|
||||
* Initialise the IRQ/FIQ sub system
|
||||
*/
|
||||
|
||||
void
|
||||
irq_init()
|
||||
{
|
||||
int loop;
|
||||
|
||||
/* Clear all the IRQ handlers and the irq block masks */
|
||||
|
||||
for (loop = 0; loop < NIRQS; ++loop) {
|
||||
irqhandlers[loop] = NULL;
|
||||
irqblock[loop] = 0;
|
||||
}
|
||||
|
||||
/* Clear the FIQ handler */
|
||||
|
||||
fiqhandlers = NULL;
|
||||
|
||||
/* Clear the IRQ/FIQ masks in the IOMD */
|
||||
|
||||
WriteByte(IOMD_IRQMSKA, 0x00);
|
||||
WriteByte(IOMD_IRQMSKB, 0x00);
|
||||
|
||||
#ifdef CPU_ARM7500
|
||||
WriteByte(IOMD_IRQMSKC, 0x00);
|
||||
WriteByte(IOMD_IRQMSKD, 0x00);
|
||||
#endif /* CPU_ARM7500 */
|
||||
|
||||
WriteByte(IOMD_FIQMSK, 0x00);
|
||||
WriteByte(IOMD_DMAMSK, 0x00);
|
||||
|
||||
/*
|
||||
* Setup the irqmasks for the different Interrupt Priority Levels
|
||||
* We will start with no bits set and these will be updated as handlers
|
||||
* are installed at different IPL's.
|
||||
*/
|
||||
|
||||
irqmasks[IPL_BIO] = 0x00000000;
|
||||
irqmasks[IPL_NET] = 0x00000000;
|
||||
irqmasks[IPL_TTY] = 0x00000000;
|
||||
irqmasks[IPL_CLOCK] = 0x00000000;
|
||||
irqmasks[IPL_IMP] = 0x00000000;
|
||||
irqmasks[IPL_NONE] = 0x00000000;
|
||||
|
||||
current_mask = 0x00000000;
|
||||
actual_mask = 0x00000000;
|
||||
spl_mask = 0x00000000;
|
||||
soft_interrupts = 0x00000000;
|
||||
|
||||
set_spl_masks();
|
||||
|
||||
/* Enable IRQ's and FIQ's */
|
||||
|
||||
enable_interrupts(I32_bit | F32_bit);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* int irq_claim(int irq, irqhandler_t *handler)
|
||||
*
|
||||
* Enable an IRQ and install a handler for it.
|
||||
*/
|
||||
|
||||
int
|
||||
irq_claim(irq, handler)
|
||||
int irq;
|
||||
irqhandler_t *handler;
|
||||
{
|
||||
int level;
|
||||
int loop;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/* Sanity check */
|
||||
if (handler == NULL)
|
||||
panic("NULL interrupt handler\n");
|
||||
if (handler->ih_func == NULL)
|
||||
panic("Interrupt handler does not have a function\n");
|
||||
#endif /* DIAGNOSTIC */
|
||||
|
||||
/*
|
||||
* IRQ_INSTRUCT indicates that we should get the irq number
|
||||
* from the irq structure
|
||||
*/
|
||||
|
||||
if (irq == IRQ_INSTRUCT)
|
||||
irq = handler->ih_num;
|
||||
|
||||
/* Make sure the irq number is valid */
|
||||
|
||||
if (irq < 0 || irq >= NIRQS)
|
||||
return(-1);
|
||||
|
||||
/* Attach handler at top of chain */
|
||||
|
||||
handler->ih_next = irqhandlers[irq];
|
||||
irqhandlers[irq] = handler;
|
||||
|
||||
/*
|
||||
* Reset the flags for this handler.
|
||||
* As the handler is now in the chain mark it as active.
|
||||
*/
|
||||
handler->ih_flags = 0 | IRQ_FLAG_ACTIVE;
|
||||
|
||||
/*
|
||||
* Record the interrupt number for accounting.
|
||||
* Done here as the accounting number may not be the same as the IRQ number
|
||||
* though for the moment they are
|
||||
*/
|
||||
|
||||
handler->ih_num = irq;
|
||||
|
||||
#ifdef IRQSTATS
|
||||
/* Get the interrupt name from the head of the list */
|
||||
|
||||
if (handler->ih_name) {
|
||||
char *ptr = _intrnames + (irq * 14);
|
||||
strcpy(ptr, " ");
|
||||
strncpy(ptr, handler->ih_name,
|
||||
min(strlen(handler->ih_name), 13));
|
||||
} else {
|
||||
char *ptr = _intrnames + (irq * 14);
|
||||
sprintf(ptr, "irq %2d ", irq);
|
||||
}
|
||||
#endif /* IRQSTATS */
|
||||
|
||||
/*
|
||||
* Update the irq masks.
|
||||
* Find the lowest interrupt priority on the irq chain.
|
||||
* Interrupt is allowable at priorities lower than this.
|
||||
* If ih_level is out of range then don't bother to update
|
||||
* the masks.
|
||||
*/
|
||||
|
||||
if (handler->ih_level >= 0 && handler->ih_level < IRQ_LEVELS) {
|
||||
irqhandler_t *ptr;
|
||||
|
||||
ptr = irqhandlers[irq];
|
||||
if (ptr) {
|
||||
level = ptr->ih_level - 1;
|
||||
while (ptr) {
|
||||
if (ptr->ih_level - 1 < level)
|
||||
level = ptr->ih_level - 1;
|
||||
ptr = ptr->ih_next;
|
||||
}
|
||||
while (level >= 0) {
|
||||
irqmasks[level] |= (1 << irq);
|
||||
--level;
|
||||
}
|
||||
}
|
||||
|
||||
#include "sl.h"
|
||||
#include "ppp.h"
|
||||
#if NSL > 0 || NPPP > 0
|
||||
/* In the presence of SLIP or PPP, splimp > spltty. */
|
||||
irqmasks[IPL_NET] &= irqmasks[IPL_TTY];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* We now need to update the irqblock array. This array indicates
|
||||
* what other interrupts should be blocked when interrupt is asserted
|
||||
* This basically emulates hardware interrupt priorities e.g. by blocking
|
||||
* all other IPL_BIO interrupts with an IPL_BIO interrupt is asserted.
|
||||
* For each interrupt we find the highest IPL and set the block mask to
|
||||
* the interrupt mask for that level.
|
||||
*/
|
||||
|
||||
for (loop = 0; loop < NIRQS; ++loop) {
|
||||
irqhandler_t *ptr;
|
||||
|
||||
ptr = irqhandlers[loop];
|
||||
if (ptr) {
|
||||
/* There is at least 1 handler so scan the chain */
|
||||
level = ptr->ih_level;
|
||||
while (ptr) {
|
||||
if (ptr->ih_level > level)
|
||||
level = ptr->ih_level;
|
||||
ptr = ptr->ih_next;
|
||||
}
|
||||
irqblock[loop] = ~irqmasks[level];
|
||||
} else
|
||||
/* No handlers for this irq so nothing to block */
|
||||
irqblock[loop] = 0;
|
||||
}
|
||||
|
||||
#if NPODULEBUS > 0
|
||||
/*
|
||||
* Is this an expansion card IRQ and is there a PODULE IRQ handler
|
||||
* installed ?
|
||||
* If not panic as the podulebus irq handler should have been installed
|
||||
* when the podulebus was attached.
|
||||
*
|
||||
* The podule IRQ's need to be fixed ASAP
|
||||
*/
|
||||
|
||||
if (irq >= IRQ_EXPCARD0 && irqhandlers[IRQ_PODULE] == NULL)
|
||||
panic("Podule IRQ %d claimed but no podulebus handler installed\n",
|
||||
irq);
|
||||
#endif /* NPODULEBUS */
|
||||
|
||||
enable_irq(irq);
|
||||
set_spl_masks();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* int irq_release(int irq, irqhandler_t *handler)
|
||||
*
|
||||
* Disable an IRQ and remove a handler for it.
|
||||
*/
|
||||
|
||||
int
|
||||
irq_release(irq, handler)
|
||||
int irq;
|
||||
irqhandler_t *handler;
|
||||
{
|
||||
int level;
|
||||
int loop;
|
||||
irqhandler_t *irqhand;
|
||||
irqhandler_t **prehand;
|
||||
extern char *_intrnames;
|
||||
|
||||
/*
|
||||
* IRQ_INSTRUCT indicates that we should get the irq number
|
||||
* from the irq structure
|
||||
*/
|
||||
|
||||
if (irq == IRQ_INSTRUCT)
|
||||
irq = handler->ih_num;
|
||||
|
||||
/* Make sure the irq number is valid */
|
||||
|
||||
if (irq < 0 || irq >= NIRQS)
|
||||
return(-1);
|
||||
|
||||
|
||||
/* Locate the handler */
|
||||
|
||||
irqhand = irqhandlers[irq];
|
||||
prehand = &irqhandlers[irq];
|
||||
|
||||
while (irqhand && handler != irqhand) {
|
||||
prehand = &irqhand;
|
||||
irqhand = irqhand->ih_next;
|
||||
}
|
||||
|
||||
/* Remove the handler if located */
|
||||
|
||||
if (irqhand)
|
||||
*prehand = irqhand->ih_next;
|
||||
else
|
||||
return(-1);
|
||||
|
||||
|
||||
/* Now the handler has been removed from the chain mark is as inactive */
|
||||
|
||||
irqhand->ih_flags &= ~IRQ_FLAG_ACTIVE;
|
||||
|
||||
/* Make sure the head of the handler list is active */
|
||||
|
||||
if (irqhandlers[irq])
|
||||
irqhandlers[irq]->ih_flags |= IRQ_FLAG_ACTIVE;
|
||||
|
||||
#ifdef IRQSTATS
|
||||
/* Get the interrupt name from the head of the list */
|
||||
if (irqhandlers[irq] && irqhandlers[irq]->ih_name) {
|
||||
char *ptr = _intrnames + (irq * 14);
|
||||
strcpy(ptr, " ");
|
||||
strncpy(ptr, irqhandlers[irq]->ih_name,
|
||||
min(strlen(irqhandlers[irq]->ih_name), 13));
|
||||
} else {
|
||||
char *ptr = _intrnames + (irq * 14);
|
||||
sprintf(ptr, "irq %2d ", irq);
|
||||
}
|
||||
#endif /* IRQSTATS */
|
||||
|
||||
/*
|
||||
* Update the irq masks.
|
||||
* If ih_level is out of range then don't bother to update
|
||||
* the masks.
|
||||
*/
|
||||
|
||||
if (handler->ih_level >= 0 && handler->ih_level < IRQ_LEVELS) {
|
||||
irqhandler_t *ptr;
|
||||
|
||||
/* Clean the bit from all the masks */
|
||||
|
||||
for (level = 0; level < IRQ_LEVELS; ++level)
|
||||
irqmasks[level] &= ~(1 << irq);
|
||||
|
||||
/*
|
||||
* Find the lowest interrupt priority on the irq chain.
|
||||
* Interrupt is allowable at priorities lower than this.
|
||||
*/
|
||||
|
||||
ptr = irqhandlers[irq];
|
||||
if (ptr) {
|
||||
level = ptr->ih_level - 1;
|
||||
while (ptr) {
|
||||
if (ptr->ih_level - 1 < level)
|
||||
level = ptr->ih_level - 1;
|
||||
ptr = ptr->ih_next;
|
||||
}
|
||||
while (level >= 0) {
|
||||
irqmasks[level] |= (1 << irq);
|
||||
--level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We now need to update the irqblock array. This array indicates
|
||||
* what other interrupts should be blocked when interrupt is asserted
|
||||
* This basically emulates hardware interrupt priorities e.g. by blocking
|
||||
* all other IPL_BIO interrupts with an IPL_BIO interrupt is asserted.
|
||||
* For each interrupt we find the highest IPL and set the block mask to
|
||||
* the interrupt mask for that level.
|
||||
*/
|
||||
|
||||
for (loop = 0; loop < NIRQS; ++loop) {
|
||||
irqhandler_t *ptr;
|
||||
|
||||
ptr = irqhandlers[loop];
|
||||
if (ptr) {
|
||||
/* There is at least 1 handler so scan the chain */
|
||||
level = ptr->ih_level;
|
||||
while (ptr) {
|
||||
if (ptr->ih_level > level)
|
||||
level = ptr->ih_level;
|
||||
ptr = ptr->ih_next;
|
||||
}
|
||||
irqblock[loop] = ~irqmasks[level];
|
||||
} else
|
||||
/* No handlers for this irq so nothing to block */
|
||||
irqblock[loop] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable the appropriate mask bit if there are no handlers left for
|
||||
* this IRQ.
|
||||
*/
|
||||
|
||||
if (irqhandlers[irq] == NULL)
|
||||
disable_irq(irq);
|
||||
|
||||
set_spl_masks();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
intr_claim(irq, level, name, ih_func, ih_arg)
|
||||
int irq;
|
||||
int level;
|
||||
const char *name;
|
||||
int (*ih_func) __P((void *));
|
||||
void *ih_arg;
|
||||
{
|
||||
irqhandler_t *ih;
|
||||
|
||||
ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
|
||||
if (!ih)
|
||||
panic("intr_claim(): Cannot malloc handler memory\n");
|
||||
|
||||
ih->ih_level = level;
|
||||
ih->ih_name = name;
|
||||
ih->ih_func = ih_func;
|
||||
ih->ih_arg = ih_arg;
|
||||
ih->ih_flags = 0;
|
||||
|
||||
if (irq_claim(irq, ih) != 0)
|
||||
return(NULL);
|
||||
return(ih);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
intr_release(arg)
|
||||
void *arg;
|
||||
{
|
||||
irqhandler_t *ih = (irqhandler_t *)arg;
|
||||
|
||||
if (irq_release(ih->ih_num, ih) == 0)
|
||||
free(ih, M_DEVBUF);
|
||||
}
|
||||
|
||||
|
||||
u_int
|
||||
disable_interrupts(mask)
|
||||
u_int mask;
|
||||
{
|
||||
register u_int cpsr;
|
||||
|
||||
cpsr = SetCPSR(mask, mask);
|
||||
return(cpsr);
|
||||
}
|
||||
|
||||
|
||||
u_int
|
||||
restore_interrupts(old_cpsr)
|
||||
u_int old_cpsr;
|
||||
{
|
||||
register int mask = I32_bit | F32_bit;
|
||||
return(SetCPSR(mask, old_cpsr & mask));
|
||||
}
|
||||
|
||||
|
||||
u_int
|
||||
enable_interrupts(mask)
|
||||
u_int mask;
|
||||
{
|
||||
return(SetCPSR(mask, 0));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void disable_irq(int irq)
|
||||
*
|
||||
* Disables a specific irq. The irq is removed from the master irq mask
|
||||
*/
|
||||
|
||||
void
|
||||
disable_irq(irq)
|
||||
int irq;
|
||||
{
|
||||
register int oldirqstate;
|
||||
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
current_mask &= ~(1 << irq);
|
||||
irq_setmasks();
|
||||
restore_interrupts(oldirqstate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void enable_irq(int irq)
|
||||
*
|
||||
* Enables a specific irq. The irq is added to the master irq mask
|
||||
* This routine should be used with caution. A handler should already
|
||||
* be installed.
|
||||
*/
|
||||
|
||||
void
|
||||
enable_irq(irq)
|
||||
int irq;
|
||||
{
|
||||
register u_int oldirqstate;
|
||||
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
current_mask |= (1 << irq);
|
||||
irq_setmasks();
|
||||
restore_interrupts(oldirqstate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void stray_irqhandler(u_int mask)
|
||||
*
|
||||
* Handler for stray interrupts. This gets called if a handler cannot be
|
||||
* found for an interrupt.
|
||||
*/
|
||||
|
||||
void
|
||||
stray_irqhandler(mask)
|
||||
u_int mask;
|
||||
{
|
||||
static u_int stray_irqs = 0;
|
||||
|
||||
if (++stray_irqs <= 8)
|
||||
log(LOG_ERR, "Stray interrupt %08x%s\n", mask,
|
||||
stray_irqs >= 8 ? ": stopped logging" : "");
|
||||
}
|
||||
|
||||
|
||||
/* Handle software interrupts */
|
||||
|
||||
void
|
||||
dosoftints()
|
||||
{
|
||||
register u_int softints;
|
||||
int s;
|
||||
|
||||
softints = soft_interrupts & spl_mask;
|
||||
if (softints == 0) return;
|
||||
|
||||
if (current_intr_depth > 1)
|
||||
return;
|
||||
|
||||
s = splsoft();
|
||||
|
||||
/*
|
||||
* Software clock interrupts
|
||||
*/
|
||||
|
||||
if (softints & IRQMASK_SOFTCLOCK) {
|
||||
++cnt.v_soft;
|
||||
++intrcnt[IRQ_SOFTCLOCK];
|
||||
atomic_clear_bit(&soft_interrupts, IRQMASK_SOFTCLOCK);
|
||||
softclock();
|
||||
}
|
||||
|
||||
#if defined(INET) && defined(PLIP) && defined(notyet)
|
||||
if (softints & IRQMASK_SOFTPLIP) {
|
||||
++cnt.v_soft;
|
||||
++intrcnt[IRQ_SOFTPLIP];
|
||||
atomic_clear_bit(&soft_interrupts, IRQMASK_SOFTPLIP);
|
||||
plipintr();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Network software interrupts
|
||||
*/
|
||||
|
||||
if (softints & IRQMASK_SOFTNET) {
|
||||
++cnt.v_soft;
|
||||
++intrcnt[IRQ_SOFTNET];
|
||||
atomic_clear_bit(&soft_interrupts, IRQMASK_SOFTNET);
|
||||
|
||||
#ifdef INET
|
||||
#include "ether.h"
|
||||
#if NETHER > 0
|
||||
if (netisr & (1 << NETISR_ARP)) {
|
||||
atomic_clear_bit(&netisr, (1 << NETISR_ARP));
|
||||
arpintr();
|
||||
}
|
||||
#endif
|
||||
if (netisr & (1 << NETISR_IP)) {
|
||||
atomic_clear_bit(&netisr, (1 << NETISR_IP));
|
||||
ipintr();
|
||||
}
|
||||
#endif
|
||||
#ifdef NETATALK
|
||||
if (netisr & (1 << NETISR_ATALK)) {
|
||||
atomic_clear_bit(&netisr, (1 << NETISR_ATALK));
|
||||
atintr();
|
||||
}
|
||||
#endif
|
||||
#ifdef NS
|
||||
if (netisr & (1 << NETISR_NS)) {
|
||||
atomic_clear_bit(&netisr, (1 << NETISR_NS));
|
||||
nsintr();
|
||||
}
|
||||
#endif
|
||||
#ifdef IMP
|
||||
if (netisr & (1 << NETISR_IMP)) {
|
||||
atomic_clear_bit(&netisr, (1 << NETISR_IMP));
|
||||
impintr();
|
||||
}
|
||||
#endif
|
||||
#ifdef ISO
|
||||
if (netisr & (1 << NETISR_ISO)) {
|
||||
atomic_clear_bit(&netisr, (1 << NETISR_ISO));
|
||||
clnlintr();
|
||||
}
|
||||
#endif
|
||||
#ifdef CCITT
|
||||
if (netisr & (1 << NETISR_CCITT)) {
|
||||
atomic_clear_bit(&netisr, (1 << NETISR_CCITT));
|
||||
ccittintr();
|
||||
}
|
||||
#endif
|
||||
#include "ppp.h"
|
||||
#if NPPP > 0
|
||||
if (netisr & (1 << NETISR_PPP)) {
|
||||
atomic_clear_bit(&netisr, (1 << NETISR_PPP));
|
||||
pppintr();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
(void)splx(s);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* int fiq_claim(fiqhandler_t *handler)
|
||||
*
|
||||
* Claim FIQ's and install a handler for them.
|
||||
*/
|
||||
|
||||
int
|
||||
fiq_claim(handler)
|
||||
fiqhandler_t *handler;
|
||||
{
|
||||
/* Fail if the FIQ's are already claimed */
|
||||
|
||||
if (fiqhandlers)
|
||||
return(-1);
|
||||
|
||||
if (handler->fh_size > 0xc0)
|
||||
return(-1);
|
||||
|
||||
/* Install the handler */
|
||||
|
||||
fiqhandlers = handler;
|
||||
|
||||
/* Now we have to actually install the FIQ handler */
|
||||
|
||||
/* Eventually we will copy this down but for the moment ... */
|
||||
|
||||
zero_page_readwrite();
|
||||
|
||||
WriteWord(0x0000003c, (u_int) handler->fh_func);
|
||||
|
||||
zero_page_readonly();
|
||||
|
||||
/* We must now set up the FIQ registers */
|
||||
|
||||
fiq_setregs(handler);
|
||||
|
||||
/* Set up the FIQ mask */
|
||||
|
||||
WriteWord(IOMD_FIQMSK, handler->fh_mask);
|
||||
|
||||
/* Make sure that the FIQ's are enabled */
|
||||
|
||||
enable_interrupts(F32_bit);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* int fiq_release(fiqhandler_t *handler)
|
||||
*
|
||||
* Release FIQ's and remove a handler for them.
|
||||
*/
|
||||
|
||||
int
|
||||
fiq_release(handler)
|
||||
fiqhandler_t *handler;
|
||||
{
|
||||
/* Fail if the handler is wrong */
|
||||
|
||||
if (fiqhandlers != handler)
|
||||
return(-1);
|
||||
|
||||
/* Disable FIQ interrupts */
|
||||
|
||||
disable_interrupts(F32_bit);
|
||||
|
||||
/* Clear up the FIQ mask */
|
||||
|
||||
WriteWord(IOMD_FIQMSK, 0x00);
|
||||
|
||||
/* Retrieve the FIQ registers */
|
||||
|
||||
fiq_getregs(handler);
|
||||
|
||||
/* Remove the handler */
|
||||
|
||||
fiqhandlers = NULL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* End of irqhandler.c */
|
Loading…
Reference in New Issue
Block a user