Update of /cvsroot/linux-mips/linux/arch/mips/korva
In directory usw-pr-cvs1:/tmp/cvs-serv20691/arch/mips/korva
Modified Files:
int_handler.S irq_korva.c
Log Message:
Fix tx stall problem in ether driver. Update irq dispatching code.
Index: int_handler.S
===================================================================
RCS file: /cvsroot/linux-mips/linux/arch/mips/korva/int_handler.S,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- int_handler.S 2001/08/23 19:13:56 1.1
+++ int_handler.S 2001/11/08 01:46:43 1.2
@@ -33,6 +33,8 @@
* 10 - UART
* 11 - External interrupt
* 12 - Wakeup
+ *
+ * Dispatching korva irqs is moved to a C routine in irq_korva.c file.
*/
#include <linux/config.h>
@@ -130,36 +132,11 @@
j ret_from_irq
ll_cpu_ip6:
- /* it is korva 2nd level interrupts */
- /* reading ISR will clear it */
- la t0, KORVA_BASE_VIRT + KORVA_S_ISR
- lw s0, 0(t0)
-
- /* and with the mask - just to be safe */
- la t0, KORVA_BASE_VIRT + KORVA_S_IMR
- lw t0, 0(t0)
- and s0, s0, t0
-
- /* do we need to deliver all the pending ones? */
- li a0, 8
- li a1, 13
- li t0, 1
-
-loop:
- and t1, t0, s0
- bnez t1, foundone
-
- sll t0, t0, 1
- addiu a0, a0, 1
-
- /* check if we reach the end */
- beq a0, a1, error
- j loop
+ move a0, sp
+ jal korva_irq_dispatch
-foundone:
- move a1, sp
- jal do_IRQ
- j ret_from_irq
+ beqz v0, error
+ j ret_from_irq
error:
j spurious_interrupt
Index: irq_korva.c
===================================================================
RCS file: /cvsroot/linux-mips/linux/arch/mips/korva/irq_korva.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- irq_korva.c 2001/10/30 21:43:37 1.5
+++ irq_korva.c 2001/11/08 01:46:43 1.6
@@ -19,10 +19,11 @@
#include <linux/irq.h>
#include <linux/types.h>
#include <linux/kernel.h>
+#include <linux/linkage.h>
+
#include <asm/korva.h>
#include <asm/mipsregs.h>
-/* [jsun] sooner or later we should move this debug stuff to MIPS common */
#include <asm/debug.h>
#define NUM_KORVA_IRQS 5
@@ -96,3 +97,45 @@
korva_irq_base = irq_base;
}
+
+/*
+ * STRATEGY:
+ *
+ * We read the irq status word and status are cleared. We need
+ * to deliver all the pending irqs if there are multiple of them.
+ *
+ * The tricky part is that while we are calling do_IRQ for one interrupt,
+ * another interrupt may happen. In that case, the second irq_dispatch()
+ * simply add bits to the pending flag. The first irq_dispatch() won't
+ * exit this function until all pending flags are cleared.
+ */
+extern unsigned int do_IRQ(int irq, struct pt_regs *regs);
+asmlinkage int
+korva_irq_dispatch(struct pt_regs *regs)
+{
+ static u32 irq_pending=0;
+ u32 status;
+
+ status = korva_in32(KORVA_S_ISR) & korva_in32(KORVA_S_IMR);
+
+ if (irq_pending) {
+ /* this is a nested interrupt, just add new status */
+ irq_pending |= status;
+
+ } else {
+
+ irq_pending |= status;
+ for (; irq_pending; ) {
+ int index=1;
+ int irq=korva_irq_base;
+ int i=0;
+ for(; i< NUM_KORVA_IRQS; i++, index <<=1, irq++) {
+ if (index & irq_pending)
+ do_IRQ(irq, regs);
+ irq_pending &= ~index;
+ }
+ }
+ }
+
+ return status;
+}
|