*Major* rewrite, long overdue.

The irq delivery code has been rewritten. On entry to the irq vector the
processor is switched to SVC32 mode so all interrupt routines now run
in SVC32 mode rather than IRQ32 mode. This fixes lots of irq re-enabling
problems.
Interrupt latency times are now vastly improved for high priority interrupts.
Cleaned up calling ast() before returning to USR32 mode (don't need to
mess about with trapframe copying.
Cleaned up all the comments and sorted out their indentation.
Rewritten the soft interrupt delivery code.
Added generic ARM7500 support rather than just RC7500 support.
This commit is contained in:
mark 1996-10-15 23:20:40 +00:00
parent c8e4c454f2
commit 81f6df323e
4 changed files with 556 additions and 650 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: irq.S,v 1.8 1996/10/13 16:52:02 christos Exp $ */
/* $NetBSD: irq.S,v 1.9 1996/10/15 23:20:40 mark Exp $ */
/*
* Copyright (c) 1994-1996 Mark Brinicombe.
@ -47,37 +47,52 @@
#include <machine/cpu.h>
#include <machine/iomd.h>
#define PUSHFRAME \
str lr, [sp, #-4]!; /* Push the return address */ \
sub sp, sp, #0x00000004; /* Skip SVC R14 */ \
/*
* PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode
* This should only be used if the processor is not currently in SVC32
* mode. The processor mode is switched to SVC mode and the trap frame is
* stored. The SVC R14 field is used to store the previous value of
* R14 in SVC mode.
*/
#define PUSHFRAMEINSVC \
stmdb sp, {r0-r3}; /* Save 4 registers */ \
mov r0, lr; /* Save xxx32 r14 */ \
mov r1, sp; /* Save xxx32 sp */ \
mrs r3, spsr_all; /* Save xxx32 spsr */ \
mrs r2, cpsr_all; /* Get the CPSR */ \
bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \
orr r2, r2, #(PSR_SVC32_MODE); \
msr cpsr_all, r2; /* Punch into SVC mode */ \
str r0, [sp, #-4]!; /* Push return address */ \
str lr, [sp, #-4]!; /* Push SVC r14 */ \
msr spsr_all, r3; /* Restore correct spsr */ \
ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \
stmdb sp, {r0-r14}^; /* Push the user mode registers */ \
sub sp, sp, #(4*15); /* Adjust the stack pointer */ \
mrs r0, spsr_all; /* Put the SPSR on the stack */ \
str r0, [sp, #-4]!;
str r0, [sp, #-4]!
#define PULLFRAME \
ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \
msr spsr_all, r0; \
add sp, sp, #(4*15); /* Adjust the stack pointer */ \
ldmdb sp, {r0-r14}^; /* Restore the registers (user mode) */ \
mov r0, r0; /* NOP for previous instruction */ \
add sp, sp, #0x00000004; /* Skip SVC R14 */ \
ldr lr, [sp], #0x0004; /* Pull the return address */
/*
* PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack
* in SVC32 mode and restore the saved processor mode and PC.
* This should be used when the SVC R14 register needs to be restored on
* exit.
*/
#define PULLFRAMEANDEXIT \
ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \
msr spsr_all, r0; \
#define PULLFRAMEFROMSVCANDEXIT \
ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \
msr spsr_all, r0; /* restore SPSR */ \
add sp, sp, #(4*15); /* Adjust the stack pointer */ \
ldmdb sp, {r0-r14}^; /* Restore the registers (user mode) */ \
mov r0, r0; /* NOP for previous instruction */ \
add sp, sp, #0x00000004; /* Skip SVC R14 */ \
ldmia sp!, {pc}^ /* Pull the return address */
ldmdb sp, {r0-r14}^; /* Restore the registers (usr mode) */ \
mov r0, r0; /* NOP for previous instruction */ \
ldmia sp!, {lr, pc}^ /* Restore lr and exit */
sp .req r13
lr .req r14
pc .req r15
.text
.text
/*
*
@ -101,6 +116,10 @@ Ldisabled_mask:
Lcurrent_spl_level:
.word _current_spl_level
Lcurrent_intr_depth:
.word _current_intr_depth
.text
.global irq_entry
/*
@ -116,34 +135,17 @@ Lcurrent_spl_level:
irq_entry:
sub lr, lr, #0x00000004 /* Adjust the lr */
PUSHFRAME
PUSHFRAMEINSVC /* Push an interrupt frame */
/* Raise the spl level and re-enable interrupts */
/* mov r11, #0x00000000*/ /* Trace back stops here */
#if 0
ldr r1, Lcurrent_spl_level
ldr r0, [r1]
add r0, r0, #1
bl _raisespl
#endif
#if 0
mrs r0, cpsr_all /* Enable IRQ's */
bic r0, r0, #I32_bit
msr cpsr_all, r0
#endif
/* Load r8 with the IOMD interrupt requests */
/*
* If we did not raise the spl level high enough we will get another
* interrupt here.
*/
mov r11, #0x00000000
mov r10, #(IOMD_BASE) /* Point to the IOMD */
ldrb r8, [r10, #(IOMD_IRQRQA - IOMD_BASE)] /* Get IRQ request A */
/* strb r8, [r10, #(IOMD_IRQRQA - IOMD_BASE)]*/
ldrb r9, [r10, #(IOMD_IRQRQB - IOMD_BASE)] /* Get IRQ request B */
orr r8, r8, r9, lsl #8
#ifdef RC7500
#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 */
@ -154,28 +156,38 @@ irq_entry:
#else
ldrb r9, [r10, #(IOMD_DMARQ - IOMD_BASE)] /* Get DMA Request */
orr r8, r8, r9, lsl #16
#endif
#endif /* CPU_ARM7500 */
/*#if 0*/
mov r0, #0x7d /* Clear IOMD IRQ bits */
and r0, r8, #0x7d /* Clear IOMD IRQA bits */
strb r0, [r10, #(IOMD_IRQRQA - IOMD_BASE)]
/*#endif*/
/* ldr r1, Ldisabled_mask
/*
* 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]
bl _irq_setmasks*/
/* Update the IOMD irq masks */
bl _irq_setmasks
#if 0
mrs r0, cpsr_all /* Enable IRQ's */
bic r0, r0, #I32_bit
msr cpsr_all, r0
#endif
mov r0, sp
mov r1, r8
bl _validate_irq_address
ldr r7, [pc, #irqhandlers - . - 8]
mov r9, #0x00000001
@ -184,7 +196,6 @@ irq_entry:
irqloop:
tst r8, r9 /* Is a bit set ? */
beq nextirq /* No ? try next bit */
ldr r6, [r7] /* Get address of first handler structure */
@ -214,62 +225,44 @@ irqchainloop:
ldr r1, [r0]
add r1, r1, #0x00000001
str r1, [r0]
#endif
#endif /* IRQSTATS */
ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */
teq r0, #0x00000000 /* If arg is zero pass stack frame */
addeq r0, sp, #4 /* ... stack frame */
addeq r0, sp, #8 /* ... stack frame */
ldr pc, [r6, #(IH_FUNC)] /* Call handler */
nextinchain:
/* ldr r1, Ldisabled_mask
ldr r2, [r1]
bic r2, r2, r9
str r2, [r1]
bl _irq_setmasks*/
teq r0, #0x00000001 /* Was the irq serviced ? */
beq nextirq
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 RC7500
#ifdef CPU_ARM7500
teq r9, #0 /* done the last bit ? */
#else
teq r9, #(1 << 24) /* done the last bit ? */
#endif
#endif /* CPU_ARM7500 */
bne irqloop /* no - loop back. */
ldmfd sp!, {r8}
#if 0
mrs r0, cpsr_all /* Enable IRQ's */
bic r0, r0, #I32_bit
msr cpsr_all, r0
#endif
/* Restore previous disabled mask */
ldmfd sp!, {r2}
ldr r1, Ldisabled_mask
str r2, [r1]
bl _irq_setmasks
bl _dosoftints /* Handle the soft interrupts */
/* Disable interrupts and lower the spl level */
#if 0
mrs r0, cpsr_all /* Disable IRQ's */
orr r0, r0, #I32_bit
msr cpsr_all, r0
#endif
#if 0
ldr r1, Lcurrent_spl_level
ldr r0, [r1]
sub r0, r0, #1
bl _lowerspl
#endif
/* Manage AST's. Maybe this should be done as a soft interrupt ? */
ldr r0, [sp] /* Get the SPSR from stack */
@ -282,73 +275,67 @@ nextirq:
streq r1, [r0]
moveq r0, sp /* arg 0 = irq frame */
beq _irqast /* exit via the AST handler */
bleq _ast /* call the AST handler */
#else
/* Manage AST's. Maybe this should be done as a soft interrupt ? */
PULLFRAME
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 */
#endif
/* 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]
.global _irqast
_irqast:
/* Punch into SVC32 mode (R0 points to the irqframe) */
/* We can trash all the registers we like :-) */
/* Kill IRQ's so we atomically decrement current_intr_depth */
/* Make sure interrupts are disabled */
#ifdef DIAGNOSTIC
mrs r2, cpsr_all
tst r2, #(I32_bit)
bne Lis
orr r3, r2, #(I32_bit)
msr cpsr_all, r3
orr r2, r2, #(I32_bit)
/* 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
stmfd sp!, {r0-r3, lr}
add r0, pc, #Lirqtext0 - . - 8
bl _printf
ldmfd sp!, {r0-r3, lr}
Lis:
#endif
add sp, sp, #72 /* Correct IRQ32 sp */
/*
* We have now put IRQ mode back correct so we never need to return to
* IRQ mode we can just exit via SVC mode. We must copy the trap frame
* which still lies on the IRQ stack over to the SVC stack.
*/
/* Punch into SVC 32 mode (IRQ's still disabled) */
mrs r2, cpsr_all
bic r2, r2, #(PSR_MODE)
eor r2, r2, #(PSR_SVC32_MODE)
orr r2, r2, #(I32_bit) /* Overkill */
msr cpsr_all, r2
sub sp, sp, #72 /* Correct SVC32 sp */
mov r12, sp
/* r0 points to the trap frame on the IRQ stack (SP corrected) */
/* r12 points to the trap frame on the SVC stack */
ldmia r0!, {r1-r9} /* Pull 9 regs off the IRQ stack */
stmia r12!, {r1-r9} /* Store on the SVC stack */
ldmia r0!, {r1-r9} /* Pull 9 regs off the IRQ stack */
stmia r12!, {r1-r9} /* Store on the SVC stack */
/* Ok the IRQ trapframe is now the SVC trapframe */
/* IRQ's can be enabled here */
mrs r0, cpsr_all
bic r0, r0, #(I32_bit)
msr cpsr_all, r0
/* r0 points to trap frame on entry to ast() */
mov r0, sp
bl _ast /* Lets go do an ast */
bl _ast
/* Kill IRQ's in preparation for exit */
@ -356,31 +343,32 @@ Lis:
orr r0, r0, #(I32_bit)
msr cpsr_all, r0
PULLFRAMEANDEXIT
PULLFRAMEFROMSVCANDEXIT
Lirqtext0:
.asciz "irqs enabled during ast\n"
.align 0
movs pc, lr /* Exit */
Lspl_mask:
.word _spl_mask
.word _spl_mask /* irq's allowed at current spl level */
Lcurrent_mask:
.word _current_mask
.word _current_mask /* irq's that are usable */
.global _irq_setmasks
_irq_setmasks:
/* Disable interrupts */
mrs r3, cpsr_all
orr r1, r3, #(I32_bit)
msr cpsr_all, r1
ldr r1, Lcurrent_mask
/* Calculate IOMD interrupt mask */
ldr r1, Lcurrent_mask /* All the enabled interrupts */
ldr r1, [r1]
ldr r2, Lspl_mask
ldr r2, Lspl_mask /* Block due to current spl level */
ldr r2, [r2]
and r1, r1, r2
ldr r2, Ldisabled_mask
ldr r2, Ldisabled_mask /* Block due to active interrupts */
ldr r2, [r2]
bic r1, r1, r2
@ -389,7 +377,7 @@ _irq_setmasks:
mov r1, r1, lsr #8
strb r1, [r0, #(IOMD_IRQMSKB - IOMD_BASE)] /* Set IRQ mask B */
mov r1, r1, lsr #8
#ifdef RC7500
#ifdef CPU_ARM7500
strb r1, [r0, #(IOMD_IRQMSKC - IOMD_BASE)]
mov r1, r1, lsr #8
and r2, r1, #0xef
@ -399,10 +387,11 @@ _irq_setmasks:
strb r2, [r0, #(IOMD_DMAMSK - IOMD_BASE)] /* Set DMA mask */
#else
strb r1, [r0, #(IOMD_DMAMSK - IOMD_BASE)] /* Set DMA mask */
#endif
#endif /* CPU_ARM7500 */
/* Restore old cpsr and exit */
msr cpsr_all, r3
mov pc, r14
mov pc, lr
Lcnt:
@ -470,7 +459,7 @@ _intrcnt:
.space 32*4 /* XXX Should be linked to number of interrupts */
_eintrcnt:
#else
#else /* IRQSTATS */
/* Dummy entries to keep vmstat happy */
.text
@ -482,7 +471,7 @@ _eintrnames:
_intrcnt:
.long 0
_eintrcnt:
#endif
#endif /* IRQSTATS */
/* FIQ code */

View File

@ -1,4 +1,4 @@
/* $NetBSD: irqhandler.c,v 1.9 1996/10/13 03:05:52 christos Exp $ */
/* $NetBSD: irqhandler.c,v 1.10 1996/10/15 23:20:41 mark Exp $ */
/*
* Copyright (c) 1994-1996 Mark Brinicombe.
@ -40,11 +40,6 @@
*
* IRQ/FIQ initialisation, claim, release and handler routines
*
* NOTE: Although the irqhandlers support chaining and the claim
* and release routines install handlers at the top of the chain
* The low level IRQ handler will only call the top handler in a
* chain.
*
* Created : 30/09/94
*/
@ -65,10 +60,11 @@
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;
u_int disabled_mask = 0;
u_int spl_mask;
u_int soft_interrupts;
extern u_int intrcnt[];
@ -79,6 +75,7 @@ typedef struct {
} pv_addr_t;
extern pv_addr_t systempage;
extern char *_intrnames;
/* Prototypes */
@ -106,27 +103,33 @@ irq_init()
{
int loop;
/* Clear all the IRQ handlers */
/* Clear all the IRQ handlers */
for (loop = 0; loop < NIRQS; ++loop)
irqhandlers[loop] = NULL;
/* Clear the FIQ handler */
/* Clear the FIQ handler */
fiqhandlers = NULL;
/* Clear the IRQ/FIQ masks in the IOMD */
/* 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.
*/
/*
* 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;
@ -142,7 +145,7 @@ irq_init()
set_spl_masks();
/* Enable IRQ's and FIQ's */
/* Enable IRQ's and FIQ's */
enable_interrupts(I32_bit | F32_bit);
}
@ -167,15 +170,17 @@ irq_claim(irq, handler)
panic("NULL interrupt handler\n");
if (handler->ih_func == NULL)
panic("Interrupt handler does not have a function\n");
#endif
#endif /* DIAGNOSTIC */
/* IRQ_INSTRUCT indicates that we should get the irq number from the irq structure */
/*
* 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 */
/* Make sure the irq number is valid */
if (irq < 0 || irq >= NIRQS)
return(-1);
@ -185,43 +190,42 @@ irq_claim(irq, handler)
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.
*/
/*
* 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
*/
/*
* 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_next == NULL && */handler->ih_name) {
extern char *_intrnames;
if (handler->ih_name) {
char *ptr = _intrnames + (irq * 14);
/* printf("intrnames=%08x ptr=%08x irq=%d\n", (u_int)_intrnames, (u_int)ptr, irq);*/
strcpy(ptr, " ");
strncpy(ptr, handler->ih_name, min(strlen(handler->ih_name), 13));
strncpy(ptr, handler->ih_name,
min(strlen(handler->ih_name), 13));
} else {
extern char *_intrnames;
char *ptr = _intrnames + (irq * 14);
sprintf(ptr, "irq %2d ", irq);
}
#endif
#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.
*/
/*
* 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;
@ -246,28 +250,25 @@ irq_claim(irq, handler)
irqmasks[IPL_NET] &= irqmasks[IPL_TTY];
#endif
}
/*
for (level = 0; level < IRQ_LEVELS; ++level)
printf("irqmask[%d] = %08x\n", level, irqmasks[level]);
*/
#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.
*/
/*
* 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
#endif /* NPODULEBUS */
enable_irq(irq);
set_spl_masks();
return(0);
}
@ -284,22 +285,25 @@ irq_release(irq, handler)
irqhandler_t *handler;
{
int level;
irqhandler_t *irqhand;
irqhandler_t **prehand;
extern char *_intrnames;
/* IRQ_INSTRUCT indicates that we should get the irq number from the irq structure */
/*
* 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 */
/* Make sure the irq number is valid */
if (irq < 0 || irq >= NIRQS)
return(-1);
/* Locate the handler */
/* Locate the handler */
irqhand = irqhandlers[irq];
prehand = &irqhandlers[irq];
@ -309,7 +313,7 @@ irq_release(irq, handler)
irqhand = irqhand->ih_next;
}
/* Remove the handler if located */
/* Remove the handler if located */
if (irqhand)
*prehand = irqhand->ih_next;
@ -317,11 +321,11 @@ irq_release(irq, handler)
return(-1);
/* Now the handler has been removed from the chain mark is as inactive */
/* 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 */
/* Make sure the head of the handler list is active */
if (irqhandlers[irq])
irqhandlers[irq]->ih_flags |= IRQ_FLAG_ACTIVE;
@ -329,35 +333,34 @@ irq_release(irq, handler)
#ifdef IRQSTATS
/* Get the interrupt name from the head of the list */
if (irqhandlers[irq] && irqhandlers[irq]->ih_name) {
extern char *_intrnames;
char *ptr = _intrnames + (irq * 14);
strcpy(ptr, " ");
strncpy(ptr, irqhandlers[irq]->ih_name, min(strlen(irqhandlers[irq]->ih_name), 13));
strncpy(ptr, irqhandlers[irq]->ih_name,
min(strlen(irqhandlers[irq]->ih_name), 13));
} else {
extern char *_intrnames;
char *ptr = _intrnames + (irq * 14);
sprintf(ptr, "irq %2d ", irq);
}
#endif
#endif /* IRQSTATS */
/*
* Update the irq masks.
* If ih_level is out of range then don't bother to update
* the masks.
*/
/*
* 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 */
/* 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.
*/
/*
* Find the lowest interrupt priority on the irq chain.
* Interrupt is allowable at priorities lower than this.
*/
ptr = irqhandlers[irq];
if (ptr) {
@ -375,10 +378,10 @@ irq_release(irq, handler)
}
}
/*
* Disable the appropriate mask bit if there are no handlers left for
* this IRQ.
*/
/*
* Disable the appropriate mask bit if there are no handlers left for
* this IRQ.
*/
if (irqhandlers[irq] == NULL)
disable_irq(irq);
@ -396,10 +399,6 @@ disable_interrupts(mask)
register u_int cpsr;
cpsr = SetCPSR(mask, mask);
#ifdef DIAGNOSTIC
if ((GetCPSR() & I32_bit) == 0)
printf("Alert ! disable_interrupts has failed\n");
#endif
return(cpsr);
}
@ -472,7 +471,6 @@ void
stray_irqhandler(mask)
u_int mask;
{
/* panic("Stray IRQ received (%08x)\n", mask);*/
static u_int stray_irqs = 0;
if (++stray_irqs <= 8)
@ -487,43 +485,30 @@ void
dosoftints()
{
register u_int softints;
u_int oldcpsr;
int s;
softints = soft_interrupts & spl_mask;
if (softints == 0) return;
/* if (soft_interrupts) {
printf("current_spl_level=%d ", current_spl_level);
printf("soft_interrupts=%08x spl_mask=%08x\n", soft_interrupts, spl_mask);
}*/
s = splsoft();
/*
* Software clock interrupts
*/
if (softints & IRQMASK_SOFTCLOCK) {
int s;
s = splhigh();
++cnt.v_soft;
++intrcnt[IRQ_SOFTCLOCK];
soft_interrupts &= ~IRQMASK_SOFTCLOCK;
oldcpsr = enable_interrupts(I32_bit);
atomic_clear_bit(&soft_interrupts, IRQMASK_SOFTCLOCK);
softclock();
restore_interrupts(oldcpsr);
(void)splx(s);
}
#if defined(INET) && defined(PLIP) && defined(notyet)
if (softints & IRQMASK_SOFTPLIP) {
int s;
/* oldcpsr = enable_interrupts(I32_bit); */
++cnt.v_soft;
++intrcnt[IRQ_SOFTPLIP];
soft_interrupts &= ~IRQMASK_SOFTPLIP;
/* s = raisespl(SPL_NET);*/
atomic_clear_bit(&soft_interrupts, IRQMASK_SOFTPLIP);
plipintr();
/* (void)splx(s);*/
/* restore_interrupts(oldcpsr); */
}
#endif
@ -532,75 +517,56 @@ dosoftints()
*/
if (softints & IRQMASK_SOFTNET) {
register int isr;
u_int cpsr;
++cnt.v_soft;
++intrcnt[IRQ_SOFTNET];
soft_interrupts &= ~IRQMASK_SOFTNET;
atomic_clear_bit(&soft_interrupts, IRQMASK_SOFTNET);
cpsr = disable_interrupts(I32_bit);
isr = netisr;
netisr = 0;
restore_interrupts(cpsr);
/* oldcpsr = enable_interrupts(I32_bit); */
/* if (isr == 0) return;*/
#ifdef INET
#include "ether.h"
#if NETHER > 0
if (isr & (1 << NETISR_ARP)) arpintr();
if (netisr & (1 << NETISR_ARP)) {
atomic_clear_bit(&netisr, (1 << NETISR_ARP));
arpintr();
}
#endif
if (isr & (1 << NETISR_IP)) ipintr();
#endif
#ifdef IMP
if (isr & (1 << NETISR_IMP)) impintr();
if (netisr & (1 << NETISR_IP)) {
atomic_clear_bit(&netisr, (1 << NETISR_IP));
ipintr();
}
#endif
#ifdef NS
if (isr & (1 << NETISR_NS)) nsintr();
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 (isr & (1 << NETISR_ISO)) clnlintr();
if (netisr & (1 << NETISR_ISO)) {
atomic_clear_bit(&netisr, (1 << NETISR_ISO));
clnlintr();
}
#endif
#ifdef CCITT
if (isr & (1 << NETISR_CCITT)) ccittintr();
if (netisr & (1 << NETISR_CCITT)) {
atomic_clear_bit(&netisr, (1 << NETISR_CCITT));
ccittintr();
}
#endif
#include "ppp.h"
#if NPPP > 0
if (isr & (1 << NETISR_PPP)) pppintr();
#ifdef PPP
if (netisr & (1 << NETISR_PPP)) {
atomic_clear_bit(&netisr, (1 << NETISR_PPP));
pppintr();
}
#endif
/* restore_interrupts(oldcpsr); */
}
}
extern vgone();
extern vfinddev();
extern idle();
extern cpu_switch();
extern switch_exit();
void
validate_irq_address(irqf, mask)
irqframe_t *irqf;
u_int mask;
{
return;
if (irqf->if_pc > (int)idle && irqf->if_pc < (int)switch_exit)
return;
if (irqf->if_pc > (int)SetCPSR && irqf->if_pc < (int)GetCPSR)
return;
if ((irqf->if_spsr & PSR_MODE) != PSR_USR32_MODE) {
printf("Alert! IRQ while in non USR mode (%08x) pc=%08x\n",
irqf->if_spsr, irqf->if_pc);
}
if ((GetCPSR() & I32_bit) == 0) {
printf("Alert! IRQ's enabled during IRQ handler\n");
}
if (irqf->if_pc >= (int)vgone && irqf->if_pc < (int)vfinddev)
printf("Alert! IRQ between vgone & vfinddev : pc=%08x\n",
irqf->if_pc);
(void)splx(s);
}
@ -614,7 +580,7 @@ int
fiq_claim(handler)
fiqhandler_t *handler;
{
/* Fail if the FIQ's are already claimed */
/* Fail if the FIQ's are already claimed */
if (fiqhandlers)
return(-1);
@ -622,13 +588,13 @@ fiq_claim(handler)
if (handler->fh_size > 0xc0)
return(-1);
/* Install the handler */
/* Install the handler */
fiqhandlers = handler;
/* Now we have to actually install the FIQ handler */
/* Now we have to actually install the FIQ handler */
/* Eventually we will copy this down but for the moment ... */
/* Eventually we will copy this down but for the moment ... */
zero_page_readwrite();
@ -636,17 +602,15 @@ fiq_claim(handler)
zero_page_readonly();
/* bcopy(handler->fh_func, 0x0000001c, handler->fh_size);*/
/* We must now set up the FIQ registers */
/* We must now set up the FIQ registers */
fiq_setregs(handler);
/* Set up the FIQ mask */
/* Set up the FIQ mask */
WriteWord(IOMD_FIQMSK, handler->fh_mask);
/* Make sure that the FIQ's are enabled */
/* Make sure that the FIQ's are enabled */
enable_interrupts(F32_bit);
return(0);
@ -663,24 +627,24 @@ int
fiq_release(handler)
fiqhandler_t *handler;
{
/* Fail if the handler is wrong */
/* Fail if the handler is wrong */
if (fiqhandlers != handler)
return(-1);
/* Disable FIQ interrupts */
/* Disable FIQ interrupts */
disable_interrupts(F32_bit);
/* Clear up the FIQ mask */
/* Clear up the FIQ mask */
WriteWord(IOMD_FIQMSK, 0x00);
/* Retrieve the FIQ registers */
/* Retrieve the FIQ registers */
fiq_getregs(handler);
/* Remove the handler */
/* Remove the handler */
fiqhandlers = NULL;
return(0);

View File

@ -1,4 +1,4 @@
/* $NetBSD: iomd_irq.S,v 1.8 1996/10/13 16:52:02 christos Exp $ */
/* $NetBSD: iomd_irq.S,v 1.9 1996/10/15 23:20:40 mark Exp $ */
/*
* Copyright (c) 1994-1996 Mark Brinicombe.
@ -47,37 +47,52 @@
#include <machine/cpu.h>
#include <machine/iomd.h>
#define PUSHFRAME \
str lr, [sp, #-4]!; /* Push the return address */ \
sub sp, sp, #0x00000004; /* Skip SVC R14 */ \
/*
* PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode
* This should only be used if the processor is not currently in SVC32
* mode. The processor mode is switched to SVC mode and the trap frame is
* stored. The SVC R14 field is used to store the previous value of
* R14 in SVC mode.
*/
#define PUSHFRAMEINSVC \
stmdb sp, {r0-r3}; /* Save 4 registers */ \
mov r0, lr; /* Save xxx32 r14 */ \
mov r1, sp; /* Save xxx32 sp */ \
mrs r3, spsr_all; /* Save xxx32 spsr */ \
mrs r2, cpsr_all; /* Get the CPSR */ \
bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \
orr r2, r2, #(PSR_SVC32_MODE); \
msr cpsr_all, r2; /* Punch into SVC mode */ \
str r0, [sp, #-4]!; /* Push return address */ \
str lr, [sp, #-4]!; /* Push SVC r14 */ \
msr spsr_all, r3; /* Restore correct spsr */ \
ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \
stmdb sp, {r0-r14}^; /* Push the user mode registers */ \
sub sp, sp, #(4*15); /* Adjust the stack pointer */ \
mrs r0, spsr_all; /* Put the SPSR on the stack */ \
str r0, [sp, #-4]!;
str r0, [sp, #-4]!
#define PULLFRAME \
ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \
msr spsr_all, r0; \
add sp, sp, #(4*15); /* Adjust the stack pointer */ \
ldmdb sp, {r0-r14}^; /* Restore the registers (user mode) */ \
mov r0, r0; /* NOP for previous instruction */ \
add sp, sp, #0x00000004; /* Skip SVC R14 */ \
ldr lr, [sp], #0x0004; /* Pull the return address */
/*
* PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack
* in SVC32 mode and restore the saved processor mode and PC.
* This should be used when the SVC R14 register needs to be restored on
* exit.
*/
#define PULLFRAMEANDEXIT \
ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \
msr spsr_all, r0; \
#define PULLFRAMEFROMSVCANDEXIT \
ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \
msr spsr_all, r0; /* restore SPSR */ \
add sp, sp, #(4*15); /* Adjust the stack pointer */ \
ldmdb sp, {r0-r14}^; /* Restore the registers (user mode) */ \
mov r0, r0; /* NOP for previous instruction */ \
add sp, sp, #0x00000004; /* Skip SVC R14 */ \
ldmia sp!, {pc}^ /* Pull the return address */
ldmdb sp, {r0-r14}^; /* Restore the registers (usr mode) */ \
mov r0, r0; /* NOP for previous instruction */ \
ldmia sp!, {lr, pc}^ /* Restore lr and exit */
sp .req r13
lr .req r14
pc .req r15
.text
.text
/*
*
@ -101,6 +116,10 @@ Ldisabled_mask:
Lcurrent_spl_level:
.word _current_spl_level
Lcurrent_intr_depth:
.word _current_intr_depth
.text
.global irq_entry
/*
@ -116,34 +135,17 @@ Lcurrent_spl_level:
irq_entry:
sub lr, lr, #0x00000004 /* Adjust the lr */
PUSHFRAME
PUSHFRAMEINSVC /* Push an interrupt frame */
/* Raise the spl level and re-enable interrupts */
/* mov r11, #0x00000000*/ /* Trace back stops here */
#if 0
ldr r1, Lcurrent_spl_level
ldr r0, [r1]
add r0, r0, #1
bl _raisespl
#endif
#if 0
mrs r0, cpsr_all /* Enable IRQ's */
bic r0, r0, #I32_bit
msr cpsr_all, r0
#endif
/* Load r8 with the IOMD interrupt requests */
/*
* If we did not raise the spl level high enough we will get another
* interrupt here.
*/
mov r11, #0x00000000
mov r10, #(IOMD_BASE) /* Point to the IOMD */
ldrb r8, [r10, #(IOMD_IRQRQA - IOMD_BASE)] /* Get IRQ request A */
/* strb r8, [r10, #(IOMD_IRQRQA - IOMD_BASE)]*/
ldrb r9, [r10, #(IOMD_IRQRQB - IOMD_BASE)] /* Get IRQ request B */
orr r8, r8, r9, lsl #8
#ifdef RC7500
#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 */
@ -154,28 +156,38 @@ irq_entry:
#else
ldrb r9, [r10, #(IOMD_DMARQ - IOMD_BASE)] /* Get DMA Request */
orr r8, r8, r9, lsl #16
#endif
#endif /* CPU_ARM7500 */
/*#if 0*/
mov r0, #0x7d /* Clear IOMD IRQ bits */
and r0, r8, #0x7d /* Clear IOMD IRQA bits */
strb r0, [r10, #(IOMD_IRQRQA - IOMD_BASE)]
/*#endif*/
/* ldr r1, Ldisabled_mask
/*
* 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]
bl _irq_setmasks*/
/* Update the IOMD irq masks */
bl _irq_setmasks
#if 0
mrs r0, cpsr_all /* Enable IRQ's */
bic r0, r0, #I32_bit
msr cpsr_all, r0
#endif
mov r0, sp
mov r1, r8
bl _validate_irq_address
ldr r7, [pc, #irqhandlers - . - 8]
mov r9, #0x00000001
@ -184,7 +196,6 @@ irq_entry:
irqloop:
tst r8, r9 /* Is a bit set ? */
beq nextirq /* No ? try next bit */
ldr r6, [r7] /* Get address of first handler structure */
@ -214,62 +225,44 @@ irqchainloop:
ldr r1, [r0]
add r1, r1, #0x00000001
str r1, [r0]
#endif
#endif /* IRQSTATS */
ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */
teq r0, #0x00000000 /* If arg is zero pass stack frame */
addeq r0, sp, #4 /* ... stack frame */
addeq r0, sp, #8 /* ... stack frame */
ldr pc, [r6, #(IH_FUNC)] /* Call handler */
nextinchain:
/* ldr r1, Ldisabled_mask
ldr r2, [r1]
bic r2, r2, r9
str r2, [r1]
bl _irq_setmasks*/
teq r0, #0x00000001 /* Was the irq serviced ? */
beq nextirq
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 RC7500
#ifdef CPU_ARM7500
teq r9, #0 /* done the last bit ? */
#else
teq r9, #(1 << 24) /* done the last bit ? */
#endif
#endif /* CPU_ARM7500 */
bne irqloop /* no - loop back. */
ldmfd sp!, {r8}
#if 0
mrs r0, cpsr_all /* Enable IRQ's */
bic r0, r0, #I32_bit
msr cpsr_all, r0
#endif
/* Restore previous disabled mask */
ldmfd sp!, {r2}
ldr r1, Ldisabled_mask
str r2, [r1]
bl _irq_setmasks
bl _dosoftints /* Handle the soft interrupts */
/* Disable interrupts and lower the spl level */
#if 0
mrs r0, cpsr_all /* Disable IRQ's */
orr r0, r0, #I32_bit
msr cpsr_all, r0
#endif
#if 0
ldr r1, Lcurrent_spl_level
ldr r0, [r1]
sub r0, r0, #1
bl _lowerspl
#endif
/* Manage AST's. Maybe this should be done as a soft interrupt ? */
ldr r0, [sp] /* Get the SPSR from stack */
@ -282,73 +275,67 @@ nextirq:
streq r1, [r0]
moveq r0, sp /* arg 0 = irq frame */
beq _irqast /* exit via the AST handler */
bleq _ast /* call the AST handler */
#else
/* Manage AST's. Maybe this should be done as a soft interrupt ? */
PULLFRAME
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 */
#endif
/* 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]
.global _irqast
_irqast:
/* Punch into SVC32 mode (R0 points to the irqframe) */
/* We can trash all the registers we like :-) */
/* Kill IRQ's so we atomically decrement current_intr_depth */
/* Make sure interrupts are disabled */
#ifdef DIAGNOSTIC
mrs r2, cpsr_all
tst r2, #(I32_bit)
bne Lis
orr r3, r2, #(I32_bit)
msr cpsr_all, r3
orr r2, r2, #(I32_bit)
/* 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
stmfd sp!, {r0-r3, lr}
add r0, pc, #Lirqtext0 - . - 8
bl _printf
ldmfd sp!, {r0-r3, lr}
Lis:
#endif
add sp, sp, #72 /* Correct IRQ32 sp */
/*
* We have now put IRQ mode back correct so we never need to return to
* IRQ mode we can just exit via SVC mode. We must copy the trap frame
* which still lies on the IRQ stack over to the SVC stack.
*/
/* Punch into SVC 32 mode (IRQ's still disabled) */
mrs r2, cpsr_all
bic r2, r2, #(PSR_MODE)
eor r2, r2, #(PSR_SVC32_MODE)
orr r2, r2, #(I32_bit) /* Overkill */
msr cpsr_all, r2
sub sp, sp, #72 /* Correct SVC32 sp */
mov r12, sp
/* r0 points to the trap frame on the IRQ stack (SP corrected) */
/* r12 points to the trap frame on the SVC stack */
ldmia r0!, {r1-r9} /* Pull 9 regs off the IRQ stack */
stmia r12!, {r1-r9} /* Store on the SVC stack */
ldmia r0!, {r1-r9} /* Pull 9 regs off the IRQ stack */
stmia r12!, {r1-r9} /* Store on the SVC stack */
/* Ok the IRQ trapframe is now the SVC trapframe */
/* IRQ's can be enabled here */
mrs r0, cpsr_all
bic r0, r0, #(I32_bit)
msr cpsr_all, r0
/* r0 points to trap frame on entry to ast() */
mov r0, sp
bl _ast /* Lets go do an ast */
bl _ast
/* Kill IRQ's in preparation for exit */
@ -356,31 +343,32 @@ Lis:
orr r0, r0, #(I32_bit)
msr cpsr_all, r0
PULLFRAMEANDEXIT
PULLFRAMEFROMSVCANDEXIT
Lirqtext0:
.asciz "irqs enabled during ast\n"
.align 0
movs pc, lr /* Exit */
Lspl_mask:
.word _spl_mask
.word _spl_mask /* irq's allowed at current spl level */
Lcurrent_mask:
.word _current_mask
.word _current_mask /* irq's that are usable */
.global _irq_setmasks
_irq_setmasks:
/* Disable interrupts */
mrs r3, cpsr_all
orr r1, r3, #(I32_bit)
msr cpsr_all, r1
ldr r1, Lcurrent_mask
/* Calculate IOMD interrupt mask */
ldr r1, Lcurrent_mask /* All the enabled interrupts */
ldr r1, [r1]
ldr r2, Lspl_mask
ldr r2, Lspl_mask /* Block due to current spl level */
ldr r2, [r2]
and r1, r1, r2
ldr r2, Ldisabled_mask
ldr r2, Ldisabled_mask /* Block due to active interrupts */
ldr r2, [r2]
bic r1, r1, r2
@ -389,7 +377,7 @@ _irq_setmasks:
mov r1, r1, lsr #8
strb r1, [r0, #(IOMD_IRQMSKB - IOMD_BASE)] /* Set IRQ mask B */
mov r1, r1, lsr #8
#ifdef RC7500
#ifdef CPU_ARM7500
strb r1, [r0, #(IOMD_IRQMSKC - IOMD_BASE)]
mov r1, r1, lsr #8
and r2, r1, #0xef
@ -399,10 +387,11 @@ _irq_setmasks:
strb r2, [r0, #(IOMD_DMAMSK - IOMD_BASE)] /* Set DMA mask */
#else
strb r1, [r0, #(IOMD_DMAMSK - IOMD_BASE)] /* Set DMA mask */
#endif
#endif /* CPU_ARM7500 */
/* Restore old cpsr and exit */
msr cpsr_all, r3
mov pc, r14
mov pc, lr
Lcnt:
@ -470,7 +459,7 @@ _intrcnt:
.space 32*4 /* XXX Should be linked to number of interrupts */
_eintrcnt:
#else
#else /* IRQSTATS */
/* Dummy entries to keep vmstat happy */
.text
@ -482,7 +471,7 @@ _eintrnames:
_intrcnt:
.long 0
_eintrcnt:
#endif
#endif /* IRQSTATS */
/* FIQ code */

View File

@ -1,4 +1,4 @@
/* $NetBSD: iomd_irqhandler.c,v 1.9 1996/10/13 03:05:52 christos Exp $ */
/* $NetBSD: iomd_irqhandler.c,v 1.10 1996/10/15 23:20:41 mark Exp $ */
/*
* Copyright (c) 1994-1996 Mark Brinicombe.
@ -40,11 +40,6 @@
*
* IRQ/FIQ initialisation, claim, release and handler routines
*
* NOTE: Although the irqhandlers support chaining and the claim
* and release routines install handlers at the top of the chain
* The low level IRQ handler will only call the top handler in a
* chain.
*
* Created : 30/09/94
*/
@ -65,10 +60,11 @@
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;
u_int disabled_mask = 0;
u_int spl_mask;
u_int soft_interrupts;
extern u_int intrcnt[];
@ -79,6 +75,7 @@ typedef struct {
} pv_addr_t;
extern pv_addr_t systempage;
extern char *_intrnames;
/* Prototypes */
@ -106,27 +103,33 @@ irq_init()
{
int loop;
/* Clear all the IRQ handlers */
/* Clear all the IRQ handlers */
for (loop = 0; loop < NIRQS; ++loop)
irqhandlers[loop] = NULL;
/* Clear the FIQ handler */
/* Clear the FIQ handler */
fiqhandlers = NULL;
/* Clear the IRQ/FIQ masks in the IOMD */
/* 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.
*/
/*
* 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;
@ -142,7 +145,7 @@ irq_init()
set_spl_masks();
/* Enable IRQ's and FIQ's */
/* Enable IRQ's and FIQ's */
enable_interrupts(I32_bit | F32_bit);
}
@ -167,15 +170,17 @@ irq_claim(irq, handler)
panic("NULL interrupt handler\n");
if (handler->ih_func == NULL)
panic("Interrupt handler does not have a function\n");
#endif
#endif /* DIAGNOSTIC */
/* IRQ_INSTRUCT indicates that we should get the irq number from the irq structure */
/*
* 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 */
/* Make sure the irq number is valid */
if (irq < 0 || irq >= NIRQS)
return(-1);
@ -185,43 +190,42 @@ irq_claim(irq, handler)
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.
*/
/*
* 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
*/
/*
* 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_next == NULL && */handler->ih_name) {
extern char *_intrnames;
if (handler->ih_name) {
char *ptr = _intrnames + (irq * 14);
/* printf("intrnames=%08x ptr=%08x irq=%d\n", (u_int)_intrnames, (u_int)ptr, irq);*/
strcpy(ptr, " ");
strncpy(ptr, handler->ih_name, min(strlen(handler->ih_name), 13));
strncpy(ptr, handler->ih_name,
min(strlen(handler->ih_name), 13));
} else {
extern char *_intrnames;
char *ptr = _intrnames + (irq * 14);
sprintf(ptr, "irq %2d ", irq);
}
#endif
#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.
*/
/*
* 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;
@ -246,28 +250,25 @@ irq_claim(irq, handler)
irqmasks[IPL_NET] &= irqmasks[IPL_TTY];
#endif
}
/*
for (level = 0; level < IRQ_LEVELS; ++level)
printf("irqmask[%d] = %08x\n", level, irqmasks[level]);
*/
#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.
*/
/*
* 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
#endif /* NPODULEBUS */
enable_irq(irq);
set_spl_masks();
return(0);
}
@ -284,22 +285,25 @@ irq_release(irq, handler)
irqhandler_t *handler;
{
int level;
irqhandler_t *irqhand;
irqhandler_t **prehand;
extern char *_intrnames;
/* IRQ_INSTRUCT indicates that we should get the irq number from the irq structure */
/*
* 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 */
/* Make sure the irq number is valid */
if (irq < 0 || irq >= NIRQS)
return(-1);
/* Locate the handler */
/* Locate the handler */
irqhand = irqhandlers[irq];
prehand = &irqhandlers[irq];
@ -309,7 +313,7 @@ irq_release(irq, handler)
irqhand = irqhand->ih_next;
}
/* Remove the handler if located */
/* Remove the handler if located */
if (irqhand)
*prehand = irqhand->ih_next;
@ -317,11 +321,11 @@ irq_release(irq, handler)
return(-1);
/* Now the handler has been removed from the chain mark is as inactive */
/* 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 */
/* Make sure the head of the handler list is active */
if (irqhandlers[irq])
irqhandlers[irq]->ih_flags |= IRQ_FLAG_ACTIVE;
@ -329,35 +333,34 @@ irq_release(irq, handler)
#ifdef IRQSTATS
/* Get the interrupt name from the head of the list */
if (irqhandlers[irq] && irqhandlers[irq]->ih_name) {
extern char *_intrnames;
char *ptr = _intrnames + (irq * 14);
strcpy(ptr, " ");
strncpy(ptr, irqhandlers[irq]->ih_name, min(strlen(irqhandlers[irq]->ih_name), 13));
strncpy(ptr, irqhandlers[irq]->ih_name,
min(strlen(irqhandlers[irq]->ih_name), 13));
} else {
extern char *_intrnames;
char *ptr = _intrnames + (irq * 14);
sprintf(ptr, "irq %2d ", irq);
}
#endif
#endif /* IRQSTATS */
/*
* Update the irq masks.
* If ih_level is out of range then don't bother to update
* the masks.
*/
/*
* 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 */
/* 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.
*/
/*
* Find the lowest interrupt priority on the irq chain.
* Interrupt is allowable at priorities lower than this.
*/
ptr = irqhandlers[irq];
if (ptr) {
@ -375,10 +378,10 @@ irq_release(irq, handler)
}
}
/*
* Disable the appropriate mask bit if there are no handlers left for
* this IRQ.
*/
/*
* Disable the appropriate mask bit if there are no handlers left for
* this IRQ.
*/
if (irqhandlers[irq] == NULL)
disable_irq(irq);
@ -396,10 +399,6 @@ disable_interrupts(mask)
register u_int cpsr;
cpsr = SetCPSR(mask, mask);
#ifdef DIAGNOSTIC
if ((GetCPSR() & I32_bit) == 0)
printf("Alert ! disable_interrupts has failed\n");
#endif
return(cpsr);
}
@ -472,7 +471,6 @@ void
stray_irqhandler(mask)
u_int mask;
{
/* panic("Stray IRQ received (%08x)\n", mask);*/
static u_int stray_irqs = 0;
if (++stray_irqs <= 8)
@ -487,43 +485,30 @@ void
dosoftints()
{
register u_int softints;
u_int oldcpsr;
int s;
softints = soft_interrupts & spl_mask;
if (softints == 0) return;
/* if (soft_interrupts) {
printf("current_spl_level=%d ", current_spl_level);
printf("soft_interrupts=%08x spl_mask=%08x\n", soft_interrupts, spl_mask);
}*/
s = splsoft();
/*
* Software clock interrupts
*/
if (softints & IRQMASK_SOFTCLOCK) {
int s;
s = splhigh();
++cnt.v_soft;
++intrcnt[IRQ_SOFTCLOCK];
soft_interrupts &= ~IRQMASK_SOFTCLOCK;
oldcpsr = enable_interrupts(I32_bit);
atomic_clear_bit(&soft_interrupts, IRQMASK_SOFTCLOCK);
softclock();
restore_interrupts(oldcpsr);
(void)splx(s);
}
#if defined(INET) && defined(PLIP) && defined(notyet)
if (softints & IRQMASK_SOFTPLIP) {
int s;
/* oldcpsr = enable_interrupts(I32_bit); */
++cnt.v_soft;
++intrcnt[IRQ_SOFTPLIP];
soft_interrupts &= ~IRQMASK_SOFTPLIP;
/* s = raisespl(SPL_NET);*/
atomic_clear_bit(&soft_interrupts, IRQMASK_SOFTPLIP);
plipintr();
/* (void)splx(s);*/
/* restore_interrupts(oldcpsr); */
}
#endif
@ -532,75 +517,56 @@ dosoftints()
*/
if (softints & IRQMASK_SOFTNET) {
register int isr;
u_int cpsr;
++cnt.v_soft;
++intrcnt[IRQ_SOFTNET];
soft_interrupts &= ~IRQMASK_SOFTNET;
atomic_clear_bit(&soft_interrupts, IRQMASK_SOFTNET);
cpsr = disable_interrupts(I32_bit);
isr = netisr;
netisr = 0;
restore_interrupts(cpsr);
/* oldcpsr = enable_interrupts(I32_bit); */
/* if (isr == 0) return;*/
#ifdef INET
#include "ether.h"
#if NETHER > 0
if (isr & (1 << NETISR_ARP)) arpintr();
if (netisr & (1 << NETISR_ARP)) {
atomic_clear_bit(&netisr, (1 << NETISR_ARP));
arpintr();
}
#endif
if (isr & (1 << NETISR_IP)) ipintr();
#endif
#ifdef IMP
if (isr & (1 << NETISR_IMP)) impintr();
if (netisr & (1 << NETISR_IP)) {
atomic_clear_bit(&netisr, (1 << NETISR_IP));
ipintr();
}
#endif
#ifdef NS
if (isr & (1 << NETISR_NS)) nsintr();
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 (isr & (1 << NETISR_ISO)) clnlintr();
if (netisr & (1 << NETISR_ISO)) {
atomic_clear_bit(&netisr, (1 << NETISR_ISO));
clnlintr();
}
#endif
#ifdef CCITT
if (isr & (1 << NETISR_CCITT)) ccittintr();
if (netisr & (1 << NETISR_CCITT)) {
atomic_clear_bit(&netisr, (1 << NETISR_CCITT));
ccittintr();
}
#endif
#include "ppp.h"
#if NPPP > 0
if (isr & (1 << NETISR_PPP)) pppintr();
#ifdef PPP
if (netisr & (1 << NETISR_PPP)) {
atomic_clear_bit(&netisr, (1 << NETISR_PPP));
pppintr();
}
#endif
/* restore_interrupts(oldcpsr); */
}
}
extern vgone();
extern vfinddev();
extern idle();
extern cpu_switch();
extern switch_exit();
void
validate_irq_address(irqf, mask)
irqframe_t *irqf;
u_int mask;
{
return;
if (irqf->if_pc > (int)idle && irqf->if_pc < (int)switch_exit)
return;
if (irqf->if_pc > (int)SetCPSR && irqf->if_pc < (int)GetCPSR)
return;
if ((irqf->if_spsr & PSR_MODE) != PSR_USR32_MODE) {
printf("Alert! IRQ while in non USR mode (%08x) pc=%08x\n",
irqf->if_spsr, irqf->if_pc);
}
if ((GetCPSR() & I32_bit) == 0) {
printf("Alert! IRQ's enabled during IRQ handler\n");
}
if (irqf->if_pc >= (int)vgone && irqf->if_pc < (int)vfinddev)
printf("Alert! IRQ between vgone & vfinddev : pc=%08x\n",
irqf->if_pc);
(void)splx(s);
}
@ -614,7 +580,7 @@ int
fiq_claim(handler)
fiqhandler_t *handler;
{
/* Fail if the FIQ's are already claimed */
/* Fail if the FIQ's are already claimed */
if (fiqhandlers)
return(-1);
@ -622,13 +588,13 @@ fiq_claim(handler)
if (handler->fh_size > 0xc0)
return(-1);
/* Install the handler */
/* Install the handler */
fiqhandlers = handler;
/* Now we have to actually install the FIQ handler */
/* Now we have to actually install the FIQ handler */
/* Eventually we will copy this down but for the moment ... */
/* Eventually we will copy this down but for the moment ... */
zero_page_readwrite();
@ -636,17 +602,15 @@ fiq_claim(handler)
zero_page_readonly();
/* bcopy(handler->fh_func, 0x0000001c, handler->fh_size);*/
/* We must now set up the FIQ registers */
/* We must now set up the FIQ registers */
fiq_setregs(handler);
/* Set up the FIQ mask */
/* Set up the FIQ mask */
WriteWord(IOMD_FIQMSK, handler->fh_mask);
/* Make sure that the FIQ's are enabled */
/* Make sure that the FIQ's are enabled */
enable_interrupts(F32_bit);
return(0);
@ -663,24 +627,24 @@ int
fiq_release(handler)
fiqhandler_t *handler;
{
/* Fail if the handler is wrong */
/* Fail if the handler is wrong */
if (fiqhandlers != handler)
return(-1);
/* Disable FIQ interrupts */
/* Disable FIQ interrupts */
disable_interrupts(F32_bit);
/* Clear up the FIQ mask */
/* Clear up the FIQ mask */
WriteWord(IOMD_FIQMSK, 0x00);
/* Retrieve the FIQ registers */
/* Retrieve the FIQ registers */
fiq_getregs(handler);
/* Remove the handler */
/* Remove the handler */
fiqhandlers = NULL;
return(0);