summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-04-18 19:49:42 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-04-18 19:49:42 -0700
commit038e5e2bf2819058fb1b4b52b583bef9ad063356 (patch)
tree3a152b455f845a25d0958af5b461b034c2d565fa /arch
parent5c723d26fa223bdb17b9230c77e4e1156884475a (diff)
parentd34cb28a3718a7055ed14e2ec058fe3e4574af63 (diff)
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: (47 commits) [MAINTAINERS] The ham radio code now has website at http://www.linux-ax25.org. [MIPS] Use __ffs() instead of ffs() for waybit calculation. [MIPS] Fix Makefile bugs for MIPS32/MIPS64 R1 and R2. [MIPS] Handle IDE PIO cache aliases on SMP. [MIPS] Make mips_srs_init static. [MIPS] MIPS boards: Set HZ to 100. [MIPS] kgdb: Let gcc compute the array size itself. [MIPS] FPU affinity for MT ASE. [MIPS] MT: Improved multithreading support. [MIPS] kpsd and other AP/SP improvements. [MIPS] R2: Instruction hazard barrier. [MIPS] Fix genrtc compilation. [MIPS] R2: Implement shadow register allocation without spinlock. [MIPS] Fix VR41xx build errors. [MIPS] Fix tx49_blast_icache32_page_indexed. [MIPS] Enable SCHED_NO_NO_OMIT_FRAME_POINTER for MIPS. [MIPS] Use "R" constraint for cache_op. [MIPS] Rewrite all the assembler interrupt handlers to C. [MIPS] Fix the crime against humanity that mipsIRQ.S is. [MIPS] Fixup damage done by 22a9835c350782a5c3257343713932af3ac92ee0. ...
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/Kconfig25
-rw-r--r--arch/mips/Makefile12
-rw-r--r--arch/mips/au1000/common/Makefile2
-rw-r--r--arch/mips/au1000/common/int-handler.S68
-rw-r--r--arch/mips/au1000/common/irq.c20
-rw-r--r--arch/mips/cobalt/Makefile2
-rw-r--r--arch/mips/cobalt/int-handler.S25
-rw-r--r--arch/mips/cobalt/irq.c6
-rw-r--r--arch/mips/configs/tb0287_defconfig1096
-rw-r--r--arch/mips/ddb5xxx/ddb5074/Makefile2
-rw-r--r--arch/mips/ddb5xxx/ddb5074/int-handler.S120
-rw-r--r--arch/mips/ddb5xxx/ddb5074/irq.c26
-rw-r--r--arch/mips/ddb5xxx/ddb5476/Makefile2
-rw-r--r--arch/mips/ddb5xxx/ddb5476/int-handler.S112
-rw-r--r--arch/mips/ddb5xxx/ddb5476/irq.c30
-rw-r--r--arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c6
-rw-r--r--arch/mips/ddb5xxx/ddb5477/Makefile2
-rw-r--r--arch/mips/ddb5xxx/ddb5477/int-handler.S75
-rw-r--r--arch/mips/ddb5xxx/ddb5477/irq.c24
-rw-r--r--arch/mips/dec/boot/decstation.c3
-rw-r--r--arch/mips/dec/int-handler.S14
-rw-r--r--arch/mips/dec/setup.c3
-rw-r--r--arch/mips/galileo-boards/ev96100/Makefile2
-rw-r--r--arch/mips/galileo-boards/ev96100/int-handler.S33
-rw-r--r--arch/mips/galileo-boards/ev96100/irq.c19
-rw-r--r--arch/mips/gt64120/ev64120/Makefile2
-rw-r--r--arch/mips/gt64120/ev64120/int-handler.S113
-rw-r--r--arch/mips/gt64120/ev64120/irq.c27
-rw-r--r--arch/mips/gt64120/momenco_ocelot/Makefile2
-rw-r--r--arch/mips/gt64120/momenco_ocelot/int-handler.S131
-rw-r--r--arch/mips/gt64120/momenco_ocelot/irq.c36
-rw-r--r--arch/mips/ite-boards/generic/Makefile2
-rw-r--r--arch/mips/ite-boards/generic/int-handler.S63
-rw-r--r--arch/mips/ite-boards/generic/irq.c18
-rw-r--r--arch/mips/ite-boards/generic/time.c1
-rw-r--r--arch/mips/ite-boards/ivr/init.c2
-rw-r--r--arch/mips/ite-boards/qed-4n-s01b/init.c2
-rw-r--r--arch/mips/jazz/Makefile2
-rw-r--r--arch/mips/jazz/int-handler.S282
-rw-r--r--arch/mips/jazz/irq.c78
-rw-r--r--arch/mips/jmr3927/common/rtc_ds1742.c60
-rw-r--r--arch/mips/jmr3927/rbhma3100/Makefile2
-rw-r--r--arch/mips/jmr3927/rbhma3100/int-handler.S74
-rw-r--r--arch/mips/jmr3927/rbhma3100/irq.c6
-rw-r--r--arch/mips/kernel/Makefile5
-rw-r--r--arch/mips/kernel/asm-offsets.c3
-rw-r--r--arch/mips/kernel/entry.S69
-rw-r--r--arch/mips/kernel/gdb-low.S24
-rw-r--r--arch/mips/kernel/gdb-stub.c61
-rw-r--r--arch/mips/kernel/genex.S43
-rw-r--r--arch/mips/kernel/head.S57
-rw-r--r--arch/mips/kernel/i8259.c4
-rw-r--r--arch/mips/kernel/irq-msc01.c9
-rw-r--r--arch/mips/kernel/irq.c18
-rw-r--r--arch/mips/kernel/kspd.c398
-rw-r--r--arch/mips/kernel/linux32.c10
-rw-r--r--arch/mips/kernel/mips-mt.c449
-rw-r--r--arch/mips/kernel/mips_ksyms.c15
-rw-r--r--arch/mips/kernel/process.c21
-rw-r--r--arch/mips/kernel/ptrace.c14
-rw-r--r--arch/mips/kernel/ptrace32.c14
-rw-r--r--arch/mips/kernel/r4k_switch.S34
-rw-r--r--arch/mips/kernel/rtlx.c517
-rw-r--r--arch/mips/kernel/scall32-o32.S13
-rw-r--r--arch/mips/kernel/scall64-64.S2
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/scall64-o32.S2
-rw-r--r--arch/mips/kernel/setup.c5
-rw-r--r--arch/mips/kernel/smp-mt.c (renamed from arch/mips/kernel/smp_mt.c)44
-rw-r--r--arch/mips/kernel/smp.c12
-rw-r--r--arch/mips/kernel/smtc-asm.S130
-rw-r--r--arch/mips/kernel/smtc-proc.c93
-rw-r--r--arch/mips/kernel/smtc.c1322
-rw-r--r--arch/mips/kernel/time.c3
-rw-r--r--arch/mips/kernel/traps.c212
-rw-r--r--arch/mips/kernel/vmlinux.lds.S2
-rw-r--r--arch/mips/kernel/vpe.c659
-rw-r--r--arch/mips/lasat/Makefile2
-rw-r--r--arch/mips/lasat/interrupt.c14
-rw-r--r--arch/mips/lasat/lasatIRQ.S69
-rw-r--r--arch/mips/mips-boards/atlas/atlas_int.c92
-rw-r--r--arch/mips/mips-boards/generic/Makefile4
-rw-r--r--arch/mips/mips-boards/generic/gdb_hook.c2
-rw-r--r--arch/mips/mips-boards/generic/init.c1
-rw-r--r--arch/mips/mips-boards/generic/memory.c9
-rw-r--r--arch/mips/mips-boards/generic/mipsIRQ.S155
-rw-r--r--arch/mips/mips-boards/generic/time.c68
-rw-r--r--arch/mips/mips-boards/malta/Makefile1
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c102
-rw-r--r--arch/mips/mips-boards/malta/malta_smp.c128
-rw-r--r--arch/mips/mips-boards/sead/sead_int.c86
-rw-r--r--arch/mips/mips-boards/sim/cmdline.c59
-rw-r--r--arch/mips/mips-boards/sim/sim_cmdline.c6
-rw-r--r--arch/mips/mips-boards/sim/sim_int.c64
-rw-r--r--arch/mips/mips-boards/sim/sim_irq.S4
-rw-r--r--arch/mips/mips-boards/sim/sim_mem.c9
-rw-r--r--arch/mips/mips-boards/sim/sim_smp.c14
-rw-r--r--arch/mips/mm/c-r3k.c5
-rw-r--r--arch/mips/mm/c-r4k.c20
-rw-r--r--arch/mips/mm/c-sb1.c1
-rw-r--r--arch/mips/mm/c-tx39.c7
-rw-r--r--arch/mips/mm/cache.c1
-rw-r--r--arch/mips/mm/fault.c13
-rw-r--r--arch/mips/mm/highmem.c2
-rw-r--r--arch/mips/mm/init.c48
-rw-r--r--arch/mips/mm/sc-rm7k.c2
-rw-r--r--arch/mips/mm/tlb-r4k.c85
-rw-r--r--arch/mips/mm/tlbex.c87
-rw-r--r--arch/mips/momentum/jaguar_atx/Makefile2
-rw-r--r--arch/mips/momentum/jaguar_atx/int-handler.S128
-rw-r--r--arch/mips/momentum/jaguar_atx/irq.c35
-rw-r--r--arch/mips/momentum/jaguar_atx/setup.c36
-rw-r--r--arch/mips/momentum/ocelot_3/Makefile2
-rw-r--r--arch/mips/momentum/ocelot_3/int-handler.S137
-rw-r--r--arch/mips/momentum/ocelot_3/irq.c38
-rw-r--r--arch/mips/momentum/ocelot_3/setup.c24
-rw-r--r--arch/mips/momentum/ocelot_c/Makefile2
-rw-r--r--arch/mips/momentum/ocelot_c/int-handler.S102
-rw-r--r--arch/mips/momentum/ocelot_c/irq.c30
-rw-r--r--arch/mips/momentum/ocelot_g/Makefile2
-rw-r--r--arch/mips/momentum/ocelot_g/int-handler.S131
-rw-r--r--arch/mips/momentum/ocelot_g/irq.c38
-rw-r--r--arch/mips/philips/pnx8550/common/Makefile2
-rw-r--r--arch/mips/philips/pnx8550/common/int.c23
-rw-r--r--arch/mips/philips/pnx8550/common/mipsIRQ.S76
-rw-r--r--arch/mips/philips/pnx8550/common/platform.c1
-rw-r--r--arch/mips/pmc-sierra/yosemite/Makefile2
-rw-r--r--arch/mips/pmc-sierra/yosemite/irq-handler.S93
-rw-r--r--arch/mips/pmc-sierra/yosemite/irq.c33
-rw-r--r--arch/mips/qemu/Makefile2
-rw-r--r--arch/mips/qemu/q-int.S17
-rw-r--r--arch/mips/qemu/q-irq.c3
-rw-r--r--arch/mips/sgi-ip22/Makefile2
-rw-r--r--arch/mips/sgi-ip22/ip22-int.c59
-rw-r--r--arch/mips/sgi-ip22/ip22-irq.S118
-rw-r--r--arch/mips/sgi-ip27/Makefile2
-rw-r--r--arch/mips/sgi-ip27/TODO4
-rw-r--r--arch/mips/sgi-ip27/ip27-irq-glue.S45
-rw-r--r--arch/mips/sgi-ip27/ip27-irq.c27
-rw-r--r--arch/mips/sgi-ip32/Makefile2
-rw-r--r--arch/mips/sgi-ip32/ip32-irq-glue.S86
-rw-r--r--arch/mips/sgi-ip32/ip32-irq.c33
-rw-r--r--arch/mips/sibyte/bcm1480/Makefile2
-rw-r--r--arch/mips/sibyte/bcm1480/irq.c77
-rw-r--r--arch/mips/sibyte/bcm1480/irq_handler.S165
-rw-r--r--arch/mips/sibyte/sb1250/Makefile2
-rw-r--r--arch/mips/sibyte/sb1250/irq.c78
-rw-r--r--arch/mips/sibyte/sb1250/irq_handler.S147
-rw-r--r--arch/mips/sni/Makefile2
-rw-r--r--arch/mips/sni/int-handler.S106
-rw-r--r--arch/mips/sni/irq.c37
-rw-r--r--arch/mips/tx4927/common/Makefile2
-rw-r--r--arch/mips/tx4927/common/tx4927_irq.c30
-rw-r--r--arch/mips/tx4927/common/tx4927_irq_handler.S103
-rw-r--r--arch/mips/tx4938/common/Makefile2
-rw-r--r--arch/mips/tx4938/common/irq.c21
-rw-r--r--arch/mips/tx4938/common/irq_handler.S84
-rw-r--r--arch/mips/vr41xx/Kconfig13
-rw-r--r--arch/mips/vr41xx/common/Makefile2
-rw-r--r--arch/mips/vr41xx/common/int-handler.S114
-rw-r--r--arch/mips/vr41xx/common/irq.c29
161 files changed, 6501 insertions, 3910 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 7aec60d4042..87f0b79c6b1 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -816,6 +816,10 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+ bool
+ default y
+
#
# Select some configuration options automatically based on user selections.
#
@@ -1443,6 +1447,10 @@ choice
prompt "MIPS MT options"
depends on MIPS_MT
+config MIPS_MT_SMTC
+ bool "SMTC: Use all TCs on all VPEs for SMP"
+ select SMP
+
config MIPS_MT_SMP
bool "Use 1 TC on each available VPE for SMP"
select SMP
@@ -1456,6 +1464,11 @@ config MIPS_VPE_LOADER
endchoice
+config MIPS_MT_FPAFF
+ bool "Dynamic FPU affinity for FP-intensive threads"
+ depends on MIPS_MT
+ default y
+
config MIPS_VPE_LOADER_TOM
bool "Load VPE program into memory hidden from linux"
depends on MIPS_VPE_LOADER
@@ -1472,6 +1485,16 @@ config MIPS_VPE_APSP_API
depends on MIPS_VPE_LOADER
help
+config MIPS_APSP_KSPD
+ bool "Enable KSPD"
+ depends on MIPS_VPE_APSP_API
+ default y
+ help
+ KSPD is a kernel daemon that accepts syscall requests from the SP
+ side, actions them and returns the results. It also handles the
+ "exit" syscall notifying other kernel modules the SP program is
+ exiting. You probably want to say yes here.
+
config SB1_PASS_1_WORKAROUNDS
bool
depends on CPU_SB1_PASS_1
@@ -1599,7 +1622,7 @@ source "mm/Kconfig"
config SMP
bool "Multi-Processing support"
- depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250 || QEMU) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP
+ depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250 || QEMU) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP || MIPS_MT_SMTC
---help---
This enables support for systems with more than one CPU. If you have
a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 9a69e0f0ab7..69b9c1b8faf 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -105,18 +105,18 @@ cflags-$(CONFIG_CPU_R4300) += -march=r4300 -Wa,--trap
cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap
cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap
cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
-cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips2 -mtune=r4600) \
+cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
-Wa,-mips32 -Wa,--trap
-cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips2 -mtune=r4600) \
+cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
-Wa,-mips32r2 -Wa,--trap
-cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips2 -mtune=r4600) \
+cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
-Wa,-mips64 -Wa,--trap
-cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips2 -mtune=r4600 ) \
+cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
-Wa,-mips64r2 -Wa,--trap
cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap
-cflags-$(CONFIG_CPU_R5432) += $(call cc-options,-march=r5400,-march=r5000) \
+cflags-$(CONFIG_CPU_R5432) += $(call cc-option,-march=r5400,-march=r5000) \
-Wa,--trap
-cflags-$(CONFIG_CPU_NEVADA) += $(call cc-options,-march=rm5200,-march=r5000) \
+cflags-$(CONFIG_CPU_NEVADA) += $(call cc-option,-march=rm5200,-march=r5000) \
-Wa,--trap
cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=r5000) \
-Wa,--trap
diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile
index a1edfd1f643..bf682f50b85 100644
--- a/arch/mips/au1000/common/Makefile
+++ b/arch/mips/au1000/common/Makefile
@@ -6,7 +6,7 @@
# Makefile for the Alchemy Au1000 CPU, generic files.
#
-obj-y += prom.o int-handler.o irq.o puts.o time.o reset.o \
+obj-y += prom.o irq.o puts.o time.o reset.o \
au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
sleeper.o cputable.o dma.o dbdma.o gpio.o
diff --git a/arch/mips/au1000/common/int-handler.S b/arch/mips/au1000/common/int-handler.S
deleted file mode 100644
index 1c4ca883321..00000000000
--- a/arch/mips/au1000/common/int-handler.S
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: ppopov@mvista.com
- *
- * Interrupt dispatcher for Au1000 boards.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
- .text
- .set macro
- .set noat
- .align 5
-
-NESTED(au1000_IRQ, PT_SIZE, sp)
- SAVE_ALL
- CLI # Important: mark KERNEL mode !
-
- mfc0 t0,CP0_CAUSE # get pending interrupts
- mfc0 t1,CP0_STATUS # get enabled interrupts
- and t0,t1 # isolate allowed ones
-
- andi t0,0xff00 # isolate pending bits
- beqz t0, 3f # spurious interrupt
-
- andi a0, t0, CAUSEF_IP7
- beq a0, zero, 1f
- move a0, sp
- jal mips_timer_interrupt
- j ret_from_irq
-
-1:
- andi a0, t0, CAUSEF_IP2 # Interrupt Controller 0, Request 0
- beq a0, zero, 2f
- move a0,sp
- jal intc0_req0_irqdispatch
- j ret_from_irq
-2:
- andi a0, t0, CAUSEF_IP3 # Interrupt Controller 0, Request 1
- beq a0, zero, 3f
- move a0,sp
- jal intc0_req1_irqdispatch
- j ret_from_irq
-3:
- andi a0, t0, CAUSEF_IP4 # Interrupt Controller 1, Request 0
- beq a0, zero, 4f
- move a0,sp
- jal intc1_req0_irqdispatch
- j ret_from_irq
-4:
- andi a0, t0, CAUSEF_IP5 # Interrupt Controller 1, Request 1
- beq a0, zero, 5f
- move a0, sp
- jal intc1_req1_irqdispatch
- j ret_from_irq
-
-5:
- move a0, sp
- j spurious_interrupt
-END(au1000_IRQ)
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index 1339a0979f6..da61de77615 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -66,7 +66,6 @@
#define EXT_INTC1_REQ1 5 /* IP 5 */
#define MIPS_TIMER_IP 7 /* IP 7 */
-extern asmlinkage void au1000_IRQ(void);
extern void set_debug_traps(void);
extern irq_cpustat_t irq_stat [NR_CPUS];
@@ -446,7 +445,6 @@ void __init arch_init_irq(void)
extern int au1xxx_ic0_nr_irqs;
cp0_status = read_c0_status();
- set_except_vector(0, au1000_IRQ);
/* Initialize interrupt controllers to a safe state.
*/
@@ -661,3 +659,21 @@ restore_au1xxx_intctl(void)
au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync();
}
#endif /* CONFIG_PM */
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+
+ if (pending & CAUSEF_IP7)
+ mips_timer_interrupt(regs);
+ else if (pending & CAUSEF_IP2)
+ intc0_req0_irqdispatch(regs);
+ else if (pending & CAUSEF_IP3)
+ intc0_req1_irqdispatch(regs);
+ else if (pending & CAUSEF_IP4)
+ intc1_req0_irqdispatch(regs);
+ else if (pending & CAUSEF_IP5)
+ intc1_req1_irqdispatch(regs);
+ else
+ spurious_interrupt(regs);
+}
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
index 720e757b2b6..225ac8f34cc 100644
--- a/arch/mips/cobalt/Makefile
+++ b/arch/mips/cobalt/Makefile
@@ -2,7 +2,7 @@
# Makefile for the Cobalt micro systems family specific parts of the kernel
#
-obj-y := irq.o int-handler.o reset.o setup.o
+obj-y := irq.o reset.o setup.o
obj-$(CONFIG_EARLY_PRINTK) += console.o
diff --git a/arch/mips/cobalt/int-handler.S b/arch/mips/cobalt/int-handler.S
deleted file mode 100644
index e75d5e3ca86..00000000000
--- a/arch/mips/cobalt/int-handler.S
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
- * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/mach-cobalt/cobalt.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
- .text
- .align 5
- NESTED(cobalt_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
-
- PTR_LA ra, ret_from_irq
- move a0, sp
- j cobalt_irq
-
- END(cobalt_handle_int)
diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c
index f9a108820d6..0b75f4fb719 100644
--- a/arch/mips/cobalt/irq.c
+++ b/arch/mips/cobalt/irq.c
@@ -20,8 +20,6 @@
#include <asm/mach-cobalt/cobalt.h>
-extern void cobalt_handle_int(void);
-
/*
* We have two types of interrupts that we handle, ones that come in through
* the CPU interrupt lines, and ones that come in on the via chip. The CPU
@@ -79,7 +77,7 @@ static inline void via_pic_irq(struct pt_regs *regs)
do_IRQ(irq, regs);
}
-asmlinkage void cobalt_irq(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned pending;
@@ -122,8 +120,6 @@ void __init arch_init_irq(void)
*/
GALILEO_OUTL(0, GT_INTRMASK_OFS);
- set_except_vector(0, cobalt_handle_int);
-
init_i8259_irqs(); /* 0 ... 15 */
mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */
diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig
new file mode 100644
index 00000000000..8a1e3ace0b2
--- /dev/null
+++ b/arch/mips/configs/tb0287_defconfig
@@ -0,0 +1,1096 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16
+# Wed Mar 22 11:07:34 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+CONFIG_MACH_VR41XX=y
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_CASIO_E55 is not set
+# CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
+CONFIG_TANBAC_TB022X=y
+# CONFIG_TANBAC_TB0226 is not set
+CONFIG_TANBAC_TB0287=y
+# CONFIG_VICTOR_MPC30X is not set
+# CONFIG_ZAO_CAPCELLA is not set
+CONFIG_PCI_VR41XX=y
+# CONFIG_VRC4173 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_VR41XX=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_MIPS_MT is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+CONFIG_BLK_DEV_SIIMAGE=y
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+CONFIG_IEEE1394=m
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_IEEE1394_OUI_DB is not set
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+# CONFIG_IEEE1394_EXPORT_FULL_API is not set
+
+#
+# Device Drivers
+#
+
+#
+# Texas Instruments PCILynx requires I2C
+#
+CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_R8169=y
+# CONFIG_R8169_NAPI is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_VR41XX=y
+CONFIG_SERIAL_VR41XX_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_RTC_VR41XX is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_TANBAC_TB0219 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+CONFIG_GPIO_VR41XX=y
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_XFS_FS=y
+CONFIG_XFS_QUOTA=y
+# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_QUOTACTL=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs"
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=m
diff --git a/arch/mips/ddb5xxx/ddb5074/Makefile b/arch/mips/ddb5xxx/ddb5074/Makefile
index 488206b8d94..304c02107b4 100644
--- a/arch/mips/ddb5xxx/ddb5074/Makefile
+++ b/arch/mips/ddb5xxx/ddb5074/Makefile
@@ -3,6 +3,6 @@
# under Linux.
#
-obj-y += setup.o irq.o int-handler.o nile4_pic.o
+obj-y += setup.o irq.o nile4_pic.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/ddb5xxx/ddb5074/int-handler.S b/arch/mips/ddb5xxx/ddb5074/int-handler.S
deleted file mode 100644
index a78644150b3..00000000000
--- a/arch/mips/ddb5xxx/ddb5074/int-handler.S
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
- *
- * Based on arch/mips/sgi/kernel/indyIRQ.S
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
- * Sony Software Development Center Europe (SDCE), Brussels
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-/* A lot of complication here is taken away because:
- *
- * 1) We handle one interrupt and return, sitting in a loop and moving across
- * all the pending IRQ bits in the cause register is _NOT_ the answer, the
- * common case is one pending IRQ so optimize in that direction.
- *
- * 2) We need not check against bits in the status register IRQ mask, that
- * would make this routine slow as hell.
- *
- * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
- * between like BSD spl() brain-damage.
- *
- * Furthermore, the IRQs on the INDY look basically (barring software IRQs
- * which we don't use at all) like:
- *
- * MIPS IRQ Source
- * -------- ------
- * 0 Software (ignored)
- * 1 Software (ignored)
- * 2 Local IRQ level zero
- * 3 Local IRQ level one
- * 4 8254 Timer zero
- * 5 8254 Timer one
- * 6 Bus Error
- * 7 R4k timer (what we use)
- *
- * We handle the IRQ according to _our_ priority which is:
- *
- * Highest ---- R4k Timer
- * Local IRQ zero
- * Local IRQ one
- * Bus Error
- * 8254 Timer zero
- * Lowest ---- 8254 Timer one
- *
- * then we just return, if multiple IRQs are pending then we will just take
- * another exception, big deal.
- */
-
- .text
- .set noreorder
- .set noat
- .align 5
- NESTED(ddbIRQ, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- mfc0 s0, CP0_CAUSE # get irq mask
-
-#if 1
- mfc0 t2,CP0_STATUS # get enabled interrupts
- and s0,t2 # isolate allowed ones
-#endif
- /* First we check for r4k counter/timer IRQ. */
- andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
- beq a0, zero, 1f
- andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
-
- /* Wheee, local level zero interrupt. */
- jal ddb_local0_irqdispatch
- move a0, sp # delay slot
-
- j ret_from_irq
- nop # delay slot
-
-1:
- beq a0, zero, 1f
- andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
-
- /* Wheee, local level one interrupt. */
- move a0, sp
- jal ddb_local1_irqdispatch
- nop
-
- j ret_from_irq
- nop
-
-1:
- beq a0, zero, 1f
- nop
-
- /* Wheee, an asynchronous bus error... */
- move a0, sp
- jal ddb_buserror_irq
- nop
-
- j ret_from_irq
- nop
-
-1:
- /* Here by mistake? This is possible, what can happen
- * is that by the time we take the exception the IRQ
- * pin goes low, so just leave if this is the case.
- */
- andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
- beq a0, zero, 1f
-
- /* Must be one of the 8254 timers... */
- move a0, sp
- jal ddb_8254timer_irq
- nop
-1:
- j ret_from_irq
- nop
- END(ddbIRQ)
diff --git a/arch/mips/ddb5xxx/ddb5074/irq.c b/arch/mips/ddb5xxx/ddb5074/irq.c
index 45088a1be41..60c087b7738 100644
--- a/arch/mips/ddb5xxx/ddb5074/irq.c
+++ b/arch/mips/ddb5xxx/ddb5074/irq.c
@@ -21,8 +21,6 @@
#include <asm/ddb5xxx/ddb5074.h>
-extern asmlinkage void ddbIRQ(void);
-
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */
@@ -90,7 +88,7 @@ static void m1543_irq_setup(void)
}
-void ddb_local0_irqdispatch(struct pt_regs *regs)
+static void ddb_local0_irqdispatch(struct pt_regs *regs)
{
u32 mask;
int nile4_irq;
@@ -118,29 +116,41 @@ void ddb_local0_irqdispatch(struct pt_regs *regs)
}
}
-void ddb_local1_irqdispatch(void)
+static void ddb_local1_irqdispatch(void)
{
printk("ddb_local1_irqdispatch called\n");
}
-void ddb_buserror_irq(void)
+static void ddb_buserror_irq(void)
{
printk("ddb_buserror_irq called\n");
}
-void ddb_8254timer_irq(void)
+static void ddb_8254timer_irq(void)
{
printk("ddb_8254timer_irq called\n");
}
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & CAUSEF_IP2)
+ ddb_local0_irqdispatch(regs);
+ else if (pending & CAUSEF_IP3)
+ ddb_local1_irqdispatch();
+ else if (pending & CAUSEF_IP6)
+ ddb_buserror_irq();
+ else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
+ ddb_8254timer_irq();
+}
+
void __init arch_init_irq(void)
{
/* setup cascade interrupts */
setup_irq(NILE4_IRQ_BASE + NILE4_INT_INTE, &irq_cascade);
setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade);
- set_except_vector(0, ddbIRQ);
-
nile4_irq_setup(NILE4_IRQ_BASE);
m1543_irq_setup();
init_i8259_irqs();
diff --git a/arch/mips/ddb5xxx/ddb5476/Makefile b/arch/mips/ddb5xxx/ddb5476/Makefile
index 61eec363cb0..ab0312cb47b 100644
--- a/arch/mips/ddb5xxx/ddb5476/Makefile
+++ b/arch/mips/ddb5xxx/ddb5476/Makefile
@@ -3,7 +3,7 @@
# under Linux.
#
-obj-y += setup.o irq.o int-handler.o nile4_pic.o vrc5476_irq.o
+obj-y += setup.o irq.o nile4_pic.o vrc5476_irq.o
obj-$(CONFIG_KGDB) += dbg_io.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/ddb5xxx/ddb5476/int-handler.S b/arch/mips/ddb5xxx/ddb5476/int-handler.S
deleted file mode 100644
index 12c292e189b..00000000000
--- a/arch/mips/ddb5xxx/ddb5476/int-handler.S
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * First-level interrupt dispatcher for ddb5476
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-#include <asm/ddb5xxx/ddb5476.h>
-
-/*
- * first level interrupt dispatcher for ocelot board -
- * We check for the timer first, then check PCI ints A and D.
- * Then check for serial IRQ and fall through.
- */
- .align 5
- NESTED(ddb5476_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- .set noreorder
- mfc0 t0, CP0_CAUSE
- mfc0 t2, CP0_STATUS
-
- and t0, t2
-
- andi t1, t0, STATUSF_IP7 /* cpu timer */
- bnez t1, ll_cpu_ip7
- andi t1, t0, STATUSF_IP2 /* vrc5476 & i8259 */
- bnez t1, ll_cpu_ip2
- andi t1, t0, STATUSF_IP3
- bnez t1, ll_cpu_ip3
- andi t1, t0, STATUSF_IP4
- bnez t1, ll_cpu_ip4
- andi t1, t0, STATUSF_IP5
- bnez t1, ll_cpu_ip5
- andi t1, t0, STATUSF_IP6
- bnez t1, ll_cpu_ip6
- andi t1, t0, STATUSF_IP0 /* software int 0 */
- bnez t1, ll_cpu_ip0
- andi t1, t0, STATUSF_IP1 /* software int 1 */
- bnez t1, ll_cpu_ip1
- nop
-
- .set reorder
-
- /* wrong alarm or masked ... */
- // j spurious_interrupt
- move a0, sp
- jal vrc5476_irq_dispatch
- j ret_from_irq
- nop
-
- .align 5
-
-ll_cpu_ip0:
- li a0, CPU_IRQ_BASE + 0
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip1:
- li a0, CPU_IRQ_BASE + 1
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip2: /* jump to second-level dispatching */
- move a0, sp
- jal vrc5476_irq_dispatch
- j ret_from_irq
-
-ll_cpu_ip3:
- li a0, CPU_IRQ_BASE + 3
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip4:
- li a0, CPU_IRQ_BASE + 4
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip5:
- li a0, CPU_IRQ_BASE + 5
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip6:
- li a0, CPU_IRQ_BASE + 6
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip7:
- li a0, CPU_IRQ_BASE + 7
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
- END(ddb5476_handle_int)
diff --git a/arch/mips/ddb5xxx/ddb5476/irq.c b/arch/mips/ddb5xxx/ddb5476/irq.c
index 5388b5868c4..7583a1f3071 100644
--- a/arch/mips/ddb5xxx/ddb5476/irq.c
+++ b/arch/mips/ddb5xxx/ddb5476/irq.c
@@ -110,11 +110,36 @@ static void nile4_irq_setup(void)
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
static struct irqaction irq_error = { no_action, 0, CPU_MASK_NONE, "error", NULL, NULL };
-extern asmlinkage void ddb5476_handle_int(void);
extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
extern void mips_cpu_irq_init(u32 irq_base);
extern void vrc5476_irq_init(u32 irq_base);
+extern void vrc5476_irq_dispatch(struct pt_regs *regs);
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP7)
+ do_IRQ(CPU_IRQ_BASE + 7, regs);
+ else if (pending & STATUSF_IP2)
+ vrc5476_irq_dispatch(regs);
+ else if (pending & STATUSF_IP3)
+ do_IRQ(CPU_IRQ_BASE + 3, regs);
+ else if (pending & STATUSF_IP4)
+ do_IRQ(CPU_IRQ_BASE + 4, regs);
+ else if (pending & STATUSF_IP5)
+ do_IRQ(CPU_IRQ_BASE + 5, regs);
+ else if (pending & STATUSF_IP6)
+ do_IRQ(CPU_IRQ_BASE + 6, regs);
+ else if (pending & STATUSF_IP0)
+ do_IRQ(CPU_IRQ_BASE, regs);
+ else if (pending & STATUSF_IP1)
+ do_IRQ(CPU_IRQ_BASE + 1, regs);
+
+ vrc5476_irq_dispatch(regs);
+}
+
void __init arch_init_irq(void)
{
/* hardware initialization */
@@ -137,7 +162,4 @@ void __init arch_init_irq(void)
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_LBRT, &irq_error);
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCIS, &irq_error);
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCI, &irq_error);
-
- /* setup the grandpa intr vector */
- set_except_vector(0, ddb5476_handle_int);
}
diff --git a/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c b/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c
index f66fe5b5863..a3c5e7b1801 100644
--- a/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c
+++ b/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c
@@ -77,11 +77,9 @@ vrc5476_irq_init(u32 base)
}
-asmlinkage void
+void
vrc5476_irq_dispatch(struct pt_regs *regs)
{
- extern void spurious_interrupt(void);
-
u32 mask;
int nile4_irq;
@@ -107,5 +105,5 @@ vrc5476_irq_dispatch(struct pt_regs *regs)
return;
}
}
- spurious_interrupt();
+ spurious_interrupt(regs);
}
diff --git a/arch/mips/ddb5xxx/ddb5477/Makefile b/arch/mips/ddb5xxx/ddb5477/Makefile
index b79b43c9f93..ea68815ad17 100644
--- a/arch/mips/ddb5xxx/ddb5477/Makefile
+++ b/arch/mips/ddb5xxx/ddb5477/Makefile
@@ -2,7 +2,7 @@
# Makefile for NEC DDB-Vrc5477 board
#
-obj-y += int-handler.o irq.o irq_5477.o setup.o lcd44780.o
+obj-y += irq.o irq_5477.o setup.o lcd44780.o
obj-$(CONFIG_RUNTIME_DEBUG) += debug.o
obj-$(CONFIG_KGDB) += kgdb_io.o
diff --git a/arch/mips/ddb5xxx/ddb5477/int-handler.S b/arch/mips/ddb5xxx/ddb5477/int-handler.S
deleted file mode 100644
index a2502a14400..00000000000
--- a/arch/mips/ddb5xxx/ddb5477/int-handler.S
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * First-level interrupt dispatcher for ddb5477
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include <asm/ddb5xxx/ddb5477.h>
-
-/*
- * first level interrupt dispatcher for ocelot board -
- * We check for the timer first, then check PCI ints A and D.
- * Then check for serial IRQ and fall through.
- */
- .align 5
- NESTED(ddb5477_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- .set noreorder
- mfc0 t0, CP0_CAUSE
- mfc0 t2, CP0_STATUS
-
- and t0, t2
-
- andi t1, t0, STATUSF_IP7 /* cpu timer */
- bnez t1, ll_cputimer_irq
- andi t1, t0, (STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 )
- bnez t1, ll_vrc5477_irq
- andi t1, t0, STATUSF_IP0 /* software int 0 */
- bnez t1, ll_cpu_ip0
- andi t1, t0, STATUSF_IP1 /* software int 1 */
- bnez t1, ll_cpu_ip1
- nop
- .set reorder
-
- /* wrong alarm or masked ... */
- j spurious_interrupt
- nop
- END(ddb5477_handle_int)
-
- .align 5
-
-ll_vrc5477_irq:
- move a0, sp
- jal vrc5477_irq_dispatch
- j ret_from_irq
-
-ll_cputimer_irq:
- li a0, CPU_IRQ_BASE + 7
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-
-ll_cpu_ip0:
- li a0, CPU_IRQ_BASE + 0
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpu_ip1:
- li a0, CPU_IRQ_BASE + 1
- move a1, sp
- jal do_IRQ
- j ret_from_irq
diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c
index 9ffe1a9142c..de433cf9fb5 100644
--- a/arch/mips/ddb5xxx/ddb5477/irq.c
+++ b/arch/mips/ddb5xxx/ddb5477/irq.c
@@ -75,7 +75,6 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
extern void vrc5477_irq_init(u32 base);
extern void mips_cpu_irq_init(u32 base);
-extern asmlinkage void ddb5477_handle_int(void);
extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
@@ -135,9 +134,6 @@ void __init arch_init_irq(void)
/* setup cascade interrupts */
setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade);
setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);
-
- /* hook up the first-level interrupt handler */
- set_except_vector(0, ddb5477_handle_int);
}
u8 i8259_interrupt_ack(void)
@@ -159,7 +155,7 @@ u8 i8259_interrupt_ack(void)
* the first level int-handler will jump here if it is a vrc5477 irq
*/
#define NUM_5477_IRQS 32
-asmlinkage void
+static void
vrc5477_irq_dispatch(struct pt_regs *regs)
{
u32 intStatus;
@@ -197,3 +193,21 @@ vrc5477_irq_dispatch(struct pt_regs *regs)
}
}
}
+
+#define VR5477INTS (STATUSF_IP2|STATUSF_IP3|STATUSF_IP4|STATUSF_IP5|STATUSF_IP6)
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP7)
+ do_IRQ(CPU_IRQ_BASE + 7, regs);
+ else if (pending & VR5477INTS)
+ vrc5477_irq_dispatch(regs);
+ else if (pending & STATUSF_IP0)
+ do_IRQ(CPU_IRQ_BASE, regs);
+ else if (pending & STATUSF_IP1)
+ do_IRQ(CPU_IRQ_BASE + 1, regs);
+ else
+ spurious_interrupt(regs);
+}
diff --git a/arch/mips/dec/boot/decstation.c b/arch/mips/dec/boot/decstation.c
index 56fd4277555..4db8bacaf22 100644
--- a/arch/mips/dec/boot/decstation.c
+++ b/arch/mips/dec/boot/decstation.c
@@ -1,6 +1,7 @@
/*
* arch/mips/dec/decstation.c
*/
+#include <asm/sections.h>
#define RELOC
#define INITRD
@@ -24,7 +25,7 @@
#define INITRD_START (*(unsigned long *) (PARAM+0x218))
#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
-extern int _ftext, _end; /* begin and end of kernel image */
+extern int _ftext; /* begin and end of kernel image */
extern void kernel_entry(int, char **, unsigned long, int *);
void * memcpy(void * dest, const void *src, unsigned int count)
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
index 41fa372007b..e8ec93e33fe 100644
--- a/arch/mips/dec/int-handler.S
+++ b/arch/mips/dec/int-handler.S
@@ -36,7 +36,7 @@
.text
.set noreorder
/*
- * decstation_handle_int: Interrupt handler for DECstations
+ * plat_irq_dispatch: Interrupt handler for DECstations
*
* We follow the model in the Indy interrupt code by David Miller, where he
* says: a lot of complication here is taken away because:
@@ -125,11 +125,7 @@
* just take another exception, big deal.
*/
.align 5
- NESTED(decstation_handle_int, PT_SIZE, ra)
- .set noat
- SAVE_ALL
- CLI # TEST: interrupts should be off
- .set at
+ NESTED(plat_irq_dispatch, PT_SIZE, ra)
.set noreorder
/*
@@ -282,9 +278,11 @@ fpu:
#endif
spurious:
- j spurious_interrupt
+ jal spurious_interrupt
nop
- END(decstation_handle_int)
+ j ret_from_irq
+ nop
+ END(plat_irq_dispatch)
/*
* Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index 7c1ca8f6330..ad5d436d80c 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -48,8 +48,6 @@ extern void dec_machine_halt(void);
extern void dec_machine_power_off(void);
extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs);
-extern asmlinkage void decstation_handle_int(void);
-
unsigned long dec_kn_slot_base, dec_kn_slot_size;
EXPORT_SYMBOL(dec_kn_slot_base);
@@ -744,7 +742,6 @@ void __init arch_init_irq(void)
panic("Don't know how to set this up!");
break;
}
- set_except_vector(0, decstation_handle_int);
/* Free the FPU interrupt if the exception is present. */
if (!cpu_has_nofpuex) {
diff --git a/arch/mips/galileo-boards/ev96100/Makefile b/arch/mips/galileo-boards/ev96100/Makefile
index 58c02f9db69..cd868ec78cb 100644
--- a/arch/mips/galileo-boards/ev96100/Makefile
+++ b/arch/mips/galileo-boards/ev96100/Makefile
@@ -6,4 +6,4 @@
# Makefile for the Galileo EV96100 board.
#
-obj-y += init.o irq.o puts.o reset.o time.o int-handler.o setup.o
+obj-y += init.o irq.o puts.o reset.o time.o setup.o
diff --git a/arch/mips/galileo-boards/ev96100/int-handler.S b/arch/mips/galileo-boards/ev96100/int-handler.S
deleted file mode 100644
index ff4d10a3885..00000000000
--- a/arch/mips/galileo-boards/ev96100/int-handler.S
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
- .set noat
- .align 5
-
-NESTED(ev96100IRQ, PT_SIZE, sp)
- SAVE_ALL
- CLI # Important: mark KERNEL mode !
-
- mfc0 t0, CP0_CAUSE # get pending interrupts
- mfc0 t1, CP0_STATUS # get enabled interrupts
- and t0, t1 # isolate allowed ones
-
- # FIX ME add R7000 extensions
- andi t0,0xff00 # isolate pending bits
- andi a0, t0, CAUSEF_IP7
- beq a0, zero, 1f
- move a0, sp
- jal mips_timer_interrupt
- j ret_from_irq
-
-1: beqz t0, 3f # spurious interrupt
-
- move a0, t0
- move a1, sp
- jal ev96100_cpu_irq
- j ret_from_irq
-
-3: j spurious_interrupt
- END(ev96100IRQ)
diff --git a/arch/mips/galileo-boards/ev96100/irq.c b/arch/mips/galileo-boards/ev96100/irq.c
index 97bf094da4f..ee5d6720f23 100644
--- a/arch/mips/galileo-boards/ev96100/irq.c
+++ b/arch/mips/galileo-boards/ev96100/irq.c
@@ -40,8 +40,6 @@
#include <linux/interrupt.h>
#include <asm/irq_cpu.h>
-extern asmlinkage void ev96100IRQ(void);
-
static inline unsigned int ffz8(unsigned int word)
{
unsigned long k;
@@ -54,13 +52,26 @@ static inline unsigned int ffz8(unsigned int word)
return k;
}
-asmlinkage void ev96100_cpu_irq(unsigned int pendin)
+extern void mips_timer_interrupt(struct pt_regs *regs);
+
+asmlinkage void ev96100_cpu_irq(unsigned int pending, struct pt_regs *regs)
{
do_IRQ(ffz8(pending >> 8), regs);
}
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+ if (pending & CAUSEF_IP7)
+ mips_timer_interrupt(regs);
+ else if (pending)
+ ev96100_cpu_irq(pending, regs);
+ else
+ spurious_interrupt(regs);
+}
+
void __init arch_init_irq(void)
{
- set_except_vector(0, ev96100IRQ);
mips_cpu_irq_init(0);
}
diff --git a/arch/mips/gt64120/ev64120/Makefile b/arch/mips/gt64120/ev64120/Makefile
index ebe91c57e17..b2c53a8f871 100644
--- a/arch/mips/gt64120/ev64120/Makefile
+++ b/arch/mips/gt64120/ev64120/Makefile
@@ -6,6 +6,6 @@
# Makefile for the Galileo EV64120 board.
#
-obj-y += int-handler.o irq.o promcon.o reset.o serialGT.o setup.o
+obj-y += irq.o promcon.o reset.o serialGT.o setup.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/gt64120/ev64120/int-handler.S b/arch/mips/gt64120/ev64120/int-handler.S
deleted file mode 100644
index 752435faf2d..00000000000
--- a/arch/mips/gt64120/ev64120/int-handler.S
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * int-handler.S
- *
- * Based on the cobalt handler.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-/*
- * galileo_handle_int -
- * We check for the timer first, then check PCI ints A and D.
- * Then check for serial IRQ and fall through.
- */
- .align 5
- .set reorder
- .set noat
- NESTED(galileo_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- mfc0 t0,CP0_CAUSE
- mfc0 t2,CP0_STATUS
-
- and t0,t2
-
- andi t1,t0,STATUSF_IP4 /* int2 hardware line (timer) */
- bnez t1,ll_gt64120_irq
- andi t1,t0,STATUSF_IP2 /* int0 hardware line */
- bnez t1,ll_pci_intA
- andi t1,t0,STATUSF_IP5 /* int3 hardware line */
- bnez t1,ll_pci_intD
- andi t1,t0,STATUSF_IP6 /* int4 hardware line */
- bnez t1,ll_serial_irq
- andi t1,t0,STATUSF_IP7 /* compare int */
- bnez t1,ll_compare_irq
- nop
-
- /* wrong alarm or masked ... */
- j spurious_interrupt
- nop
- END(galileo_handle_int)
-
-
- .align 5
- .set reorder
-ll_gt64120_irq:
- li a0,4
- move a1,sp
- jal do_IRQ
- nop
- j ret_from_irq
- nop
-
- .align 5
- .set reorder
-ll_compare_irq:
- li a0,7
- move a1,sp
- jal do_IRQ
- nop
- j ret_from_irq
- nop
-
- .align 5
- .set reorder
-ll_pci_intA:
- move a0,sp
- jal pci_intA
- nop
- j ret_from_irq
- nop
-
-#if 0
- .align 5
- .set reorder
-ll_pci_intB:
- move a0,sp
- jal pci_intB
- nop
- j ret_from_irq
- nop
-
- .align 5
- .set reorder
-ll_pci_intC:
- move a0,sp
- jal pci_intC
- nop
- j ret_from_irq
- nop
-#endif
-
- .align 5
- .set reorder
-ll_pci_intD:
- move a0,sp
- jal pci_intD
- nop
- j ret_from_irq
- nop
-
- .align 5
- .set reorder
-ll_serial_irq:
- li a0,6
- move a1,sp
- jal do_IRQ
- nop
- j ret_from_irq
- nop
diff --git a/arch/mips/gt64120/ev64120/irq.c b/arch/mips/gt64120/ev64120/irq.c
index 3b186159b21..46c468b26b3 100644
--- a/arch/mips/gt64120/ev64120/irq.c
+++ b/arch/mips/gt64120/ev64120/irq.c
@@ -46,14 +46,22 @@
#include <asm/system.h>
#include <asm/gt64120.h>
-asmlinkage inline void pci_intA(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
- do_IRQ(GT_INTA, regs);
-}
-
-asmlinkage inline void pci_intD(struct pt_regs *regs)
-{
- do_IRQ(GT_INTD, regs);
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP4) /* int2 hardware line (timer) */
+ do_IRQ(4, regs);
+ else if (pending & STATUSF_IP2) /* int0 hardware line */
+ do_IRQ(GT_INTA, regs);
+ else if (pending & STATUSF_IP5) /* int3 hardware line */
+ do_IRQ(GT_INTD, regs);
+ else if (pending & STATUSF_IP6) /* int4 hardware line */
+ do_IRQ(6, regs);
+ else if (pending & STATUSF_IP7) /* compare int */
+ do_IRQ(7, regs);
+ else
+ spurious_interrupt(regs);
}
static void disable_ev64120_irq(unsigned int irq_nr)
@@ -109,16 +117,11 @@ static struct hw_interrupt_type ev64120_irq_type = {
void gt64120_irq_setup(void)
{
- extern asmlinkage void galileo_handle_int(void);
-
/*
* Clear all of the interrupts while we change the able around a bit.
*/
clear_c0_status(ST0_IM);
- /* Sets the exception_handler array. */
- set_except_vector(0, galileo_handle_int);
-
local_irq_disable();
/*
diff --git a/arch/mips/gt64120/momenco_ocelot/Makefile b/arch/mips/gt64120/momenco_ocelot/Makefile
index 7b59c6567c7..6f708df8373 100644
--- a/arch/mips/gt64120/momenco_ocelot/Makefile
+++ b/arch/mips/gt64120/momenco_ocelot/Makefile
@@ -2,7 +2,7 @@
# Makefile for Momentum's Ocelot board.
#
-obj-y += int-handler.o irq.o prom.o reset.o setup.o
+obj-y += irq.o prom.o reset.o setup.o
obj-$(CONFIG_KGDB) += dbg_io.o
diff --git a/arch/mips/gt64120/momenco_ocelot/int-handler.S b/arch/mips/gt64120/momenco_ocelot/int-handler.S
deleted file mode 100644
index 808acef248c..00000000000
--- a/arch/mips/gt64120/momenco_ocelot/int-handler.S
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * First-level interrupt dispatcher for ocelot board.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-/*
- * first level interrupt dispatcher for ocelot board -
- * We check for the timer first, then check PCI ints A and D.
- * Then check for serial IRQ and fall through.
- */
- .align 5
- NESTED(ocelot_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- mfc0 t0, CP0_CAUSE
- mfc0 t2, CP0_STATUS
-
- and t0, t2
-
- andi t1, t0, STATUSF_IP2 /* int0 hardware line */
- bnez t1, ll_pri_enet_irq
- andi t1, t0, STATUSF_IP3 /* int1 hardware line */
- bnez t1, ll_sec_enet_irq
- andi t1, t0, STATUSF_IP4 /* int2 hardware line */
- bnez t1, ll_uart1_irq
- andi t1, t0, STATUSF_IP5 /* int3 hardware line */
- bnez t1, ll_cpci_irq
- andi t1, t0, STATUSF_IP6 /* int4 hardware line */
- bnez t1, ll_galileo_irq
- andi t1, t0, STATUSF_IP7 /* cpu timer */
- bnez t1, ll_cputimer_irq
-
- /* now look at the extended interrupts */
- mfc0 t0, CP0_CAUSE
- cfc0 t1, CP0_S1_INTCONTROL
-
- /* shift the mask 8 bits left to line up the bits */
- sll t2, t1, 8
-
- and t0, t2
- srl t0, t0, 16
-
- andi t1, t0, STATUSF_IP8 /* int6 hardware line */
- bnez t1, ll_pmc1_irq
- andi t1, t0, STATUSF_IP9 /* int7 hardware line */
- bnez t1, ll_pmc2_irq
- andi t1, t0, STATUSF_IP10 /* int8 hardware line */
- bnez t1, ll_cpci_abcd_irq
- andi t1, t0, STATUSF_IP11 /* int9 hardware line */
- bnez t1, ll_uart2_irq
-
- .set reorder
-
- /* wrong alarm or masked ... */
- j spurious_interrupt
- nop
- END(ocelot_handle_int)
-
- .align 5
-ll_pri_enet_irq:
- li a0, 2
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_sec_enet_irq:
- li a0, 3
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_uart1_irq:
- li a0, 4
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpci_irq:
- li a0, 5
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_galileo_irq:
- li a0, 6
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cputimer_irq:
- li a0, 7
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pmc1_irq:
- li a0, 8
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pmc2_irq:
- li a0, 9
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpci_abcd_irq:
- li a0, 10
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_uart2_irq:
- li a0, 11
- move a1, sp
- jal do_IRQ
- j ret_from_irq
diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c
index 4f108da71b2..885f67f32ea 100644
--- a/arch/mips/gt64120/momenco_ocelot/irq.c
+++ b/arch/mips/gt64120/momenco_ocelot/irq.c
@@ -48,7 +48,38 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
-extern asmlinkage void ocelot_handle_int(void);
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP2) /* int0 hardware line */
+ do_IRQ(2, regs);
+ else if (pending & STATUSF_IP3) /* int1 hardware line */
+ do_IRQ(3, regs);
+ else if (pending & STATUSF_IP4) /* int2 hardware line */
+ do_IRQ(4, regs);
+ else if (pending & STATUSF_IP5) /* int3 hardware line */
+ do_IRQ(5, regs);
+ else if (pending & STATUSF_IP6) /* int4 hardware line */
+ do_IRQ(6, regs);
+ else if (pending & STATUSF_IP7) /* cpu timer */
+ do_IRQ(7, regs);
+ else {
+ /*
+ * Now look at the extended interrupts
+ */
+ pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
+
+ if (pending & STATUSF_IP8) /* int6 hardware line */
+ do_IRQ(8, regs);
+ else if (pending & STATUSF_IP9) /* int7 hardware line */
+ do_IRQ(9, regs);
+ else if (pending & STATUSF_IP10) /* int8 hardware line */
+ do_IRQ(10, regs);
+ else if (pending & STATUSF_IP11) /* int9 hardware line */
+ do_IRQ(11, regs);
+ }
+}
void __init arch_init_irq(void)
{
@@ -59,9 +90,6 @@ void __init arch_init_irq(void)
clear_c0_status(ST0_IM);
local_irq_disable();
- /* Sets the first-level interrupt dispatcher. */
- set_except_vector(0, ocelot_handle_int);
-
mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8);
}
diff --git a/arch/mips/ite-boards/generic/Makefile b/arch/mips/ite-boards/generic/Makefile
index 0e7853f4398..63431538d0e 100644
--- a/arch/mips/ite-boards/generic/Makefile
+++ b/arch/mips/ite-boards/generic/Makefile
@@ -6,7 +6,7 @@
# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files.
#
-obj-y += it8172_setup.o irq.o int-handler.o pmon_prom.o \
+obj-y += it8172_setup.o irq.o pmon_prom.o \
time.o lpc.o puts.o reset.o
obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o
diff --git a/arch/mips/ite-boards/generic/int-handler.S b/arch/mips/ite-boards/generic/int-handler.S
deleted file mode 100644
index d190d8add9c..00000000000
--- a/arch/mips/ite-boards/generic/int-handler.S
+++ /dev/null
@@ -1,63 +0,0 @@
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
- .text
- .set macro
- .set noat
- .align 5
-
-NESTED(it8172_IRQ, PT_SIZE, sp)
- SAVE_ALL
- CLI # Important: mark KERNEL mode !
-
- /* We're working with 'reorder' set at this point. */
- /*
- * Get pending interrupts
- */
-
- mfc0 t0,CP0_CAUSE # get pending interrupts
- mfc0 t1,CP0_STATUS # get enabled interrupts
- and t0,t1 # isolate allowed ones
-
- andi t0,0xff00 # isolate pending bits
- beqz t0, 3f # spurious interrupt
-
- andi a0, t0, CAUSEF_IP7
- beq a0, zero, 1f
-
- li a0, 127 # MIPS_CPU_TIMER_IRQ = (NR_IRQS-1)
- move a1, sp
- jal ll_timer_interrupt
- j ret_from_irq
- nop
-
-1:
- andi a0, t0, CAUSEF_IP2 # the only int we expect at this time
- beq a0, zero, 3f
- move a0,sp
- jal it8172_hw0_irqdispatch
-
- mfc0 t0,CP0_STATUS # disable interrupts
- ori t0,1
- xori t0,1
- mtc0 t0,CP0_STATUS
- nop
- nop
- nop
-
- la a1, ret_from_irq
- jr a1
- nop
-
-3:
- move a0, sp
- jal mips_spurious_interrupt
- nop
- la a1, ret_from_irq
- jr a1
- nop
-
-END(it8172_IRQ)
-
diff --git a/arch/mips/ite-boards/generic/irq.c b/arch/mips/ite-boards/generic/irq.c
index e67f9612949..77be7216bdd 100644
--- a/arch/mips/ite-boards/generic/irq.c
+++ b/arch/mips/ite-boards/generic/irq.c
@@ -62,12 +62,8 @@
#define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
-void disable_it8172_irq(unsigned int irq_nr);
-void enable_it8172_irq(unsigned int irq_nr);
-
extern void set_debug_traps(void);
extern void mips_timer_interrupt(int irq, struct pt_regs *regs);
-extern asmlinkage void it8172_IRQ(void);
struct it8172_intc_regs volatile *it8172_hw0_icregs =
(struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE));
@@ -181,8 +177,6 @@ void __init arch_init_irq(void)
int i;
unsigned long flags;
- set_except_vector(0, it8172_IRQ);
-
/* mask all interrupts */
it8172_hw0_icregs->lb_mask = 0xffff;
it8172_hw0_icregs->lpc_mask = 0xffff;
@@ -282,6 +276,18 @@ void it8172_hw0_irqdispatch(struct pt_regs *regs)
do_IRQ(irq, regs);
}
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+ if (!pending)
+ mips_spurious_interrupt(regs);
+ else if (pending & CAUSEF_IP7)
+ ll_timer_interrupt(127, regs);
+ else if (pending & CAUSEF_IP2)
+ it8172_hw0_irqdispatch(regs);
+}
+
void show_pending_irqs(void)
{
fputs("intstatus: ");
diff --git a/arch/mips/ite-boards/generic/time.c b/arch/mips/ite-boards/generic/time.c
index b79817bb6cc..dee497a9180 100644
--- a/arch/mips/ite-boards/generic/time.c
+++ b/arch/mips/ite-boards/generic/time.c
@@ -29,6 +29,7 @@
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/spinlock.h>
+#include <linux/mc146818rtc.h>
#include <asm/time.h>
#include <asm/mipsregs.h>
diff --git a/arch/mips/ite-boards/ivr/init.c b/arch/mips/ite-boards/ivr/init.c
index b774db035b3..05cf9218c43 100644
--- a/arch/mips/ite-boards/ivr/init.c
+++ b/arch/mips/ite-boards/ivr/init.c
@@ -34,13 +34,13 @@
#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <asm/sections.h>
#include <asm/it8172/it8172.h>
#include <asm/it8172/it8172_dbg.h>
int prom_argc;
char **prom_argv, **prom_envp;
-extern char _end;
extern void __init prom_init_cmdline(void);
extern unsigned long __init prom_get_memsize(void);
extern void __init it8172_init_ram_resource(unsigned long memsize);
diff --git a/arch/mips/ite-boards/qed-4n-s01b/init.c b/arch/mips/ite-boards/qed-4n-s01b/init.c
index e8ec8be66a8..ea2a754cafe 100644
--- a/arch/mips/ite-boards/qed-4n-s01b/init.c
+++ b/arch/mips/ite-boards/qed-4n-s01b/init.c
@@ -34,13 +34,13 @@
#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <asm/sections.h>
#include <asm/it8172/it8172.h>
#include <asm/it8172/it8172_dbg.h>
int prom_argc;
char **prom_argv, **prom_envp;
-extern char _end;
extern void __init prom_init_cmdline(void);
extern unsigned long __init prom_get_memsize(void);
extern void __init it8172_init_ram_resource(unsigned long memsize);
diff --git a/arch/mips/jazz/Makefile b/arch/mips/jazz/Makefile
index 85749246a67..02bd39add89 100644
--- a/arch/mips/jazz/Makefile
+++ b/arch/mips/jazz/Makefile
@@ -2,6 +2,6 @@
# Makefile for the Jazz family specific parts of the kernel
#
-obj-y := int-handler.o irq.o jazzdma.o reset.o setup.o
+obj-y := irq.o jazzdma.o reset.o setup.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/jazz/int-handler.S b/arch/mips/jazz/int-handler.S
deleted file mode 100644
index dc752c67b52..00000000000
--- a/arch/mips/jazz/int-handler.S
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle and Andreas Busse
- *
- * Jazz family specific interrupt stuff
- *
- * To do: On Jazz machines we remap some non-ISA interrupts to ISA
- * interrupts. These interrupts should use their own vectors.
- * Squeeze the last cycles out of the handlers. Only a dead
- * cycle is a good cycle.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/jazz.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-/*
- * jazz_handle_int: Interrupt handler for the ACER Pica-61 boards
- */
- .set noreorder
-
- NESTED(jazz_handle_int, PT_SIZE, ra)
- .set noat
- SAVE_ALL
- CLI
- .set at
-
- /*
- * Get pending interrupts
- */
- mfc0 t0,CP0_CAUSE # get pending interrupts
- mfc0 t1,CP0_STATUS # get enabled interrupts
- and t0,t1 # isolate allowed ones
- andi t0,0xff00 # isolate pending bits
- beqz t0,3f
- sll t0,16 # delay slot
-
- /*
- * Find irq with highest priority
- * FIXME: This is slow - use binary search
- */
- la t1,ll_vectors
-1: bltz t0,2f # found pending irq
- sll t0,1
- b 1b
- subu t1,PTRSIZE # delay slot
-
- /*
- * Do the low-level stuff
- */
-2: lw t0,(t1)
- jr t0
- nop # delay slot
- END(jazz_handle_int)
-
-ll_sw0: li s1,~IE_SW0
- mfc0 t0,CP0_CAUSE
- and t0,s1
- mtc0 t0,CP0_CAUSE
- PANIC("Unimplemented sw0 handler")
-
-ll_sw1: li s1,~IE_SW1
- mfc0 t0,CP0_CAUSE
- and t0,s1
- mtc0 t0,CP0_CAUSE
- PANIC("Unimplemented sw1 handler")
-
-ll_local_dma: li s1,~IE_IRQ0
- PANIC("Unimplemented local_dma handler")
-
-ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE
-#if PTRSIZE == 8 /* True 64 bit kernel */
- dsll t0,1
-#endif
- .set reorder
- LONG_L t0,local_vector(t0)
- jr t0
- .set noreorder
-
-/*
- * The braindead PICA hardware gives us no way to distinguish if we really
- * received interrupt 7 from the (E)ISA bus or if we just received an
- * interrupt with no findable cause. This sometimes happens with braindead
- * cards. Oh well - for all the Jazz boxes slots are more or less just
- * whistles and bells and we're aware of the problem.
- */
-ll_isa_irq: lw a0, JAZZ_EISA_IRQ_ACK
-
- jal do_IRQ
- move a1,sp
-
- j ret_from_irq
- nop
-
-/*
- * Hmm... This is not just a plain PC clone so the question is
- * which devices on Jazz machines can generate an (E)ISA NMI?
- * (Writing to nonexistent memory?)
- */
-ll_isa_nmi: li s1,~IE_IRQ3
- PANIC("Unimplemented isa_nmi handler")
-
-/*
- * Timer IRQ - remapped to be more similar to an IBM compatible.
- *
- * The timer interrupt is handled specially to ensure that the jiffies
- * variable is updated at all times. Specifically, the timer interrupt is
- * just like the complete handlers except that it is invoked with interrupts
- * disabled and should never re-enable them. If other interrupts were
- * allowed to be processed while the timer interrupt is active, then the
- * other interrupts would have to avoid using the jiffies variable for delay
- * and interval timing operations to avoid hanging the system.
- */
-ll_timer: lw zero,JAZZ_TIMER_REGISTER # timer irq cleared on read
- li s1,~IE_IRQ4
-
- li a0, JAZZ_TIMER_IRQ
- jal do_IRQ
- move a1,sp
-
- mfc0 t0,CP0_STATUS # disable interrupts again
- ori t0,1
- xori t0,1
- mtc0 t0,CP0_STATUS
-
- j ret_from_irq
- nop
-
-/*
- * CPU count/compare IRQ (unused)
- */
-ll_count: j ret_from_irq
- mtc0 zero,CP0_COMPARE
-
-#if 0
-/*
- * Call the handler for the interrupt
- * (Currently unused)
- */
-call_real: /*
- * temporarily disable interrupt
- */
- mfc0 t2,CP0_STATUS
- and t2,s1
- mtc0 t2,CP0_STATUS
- nor s1,zero,s1
- jal do_IRQ
-
- /*
- * reenable interrupt
- */
- mfc0 t2,CP0_STATUS
- or t2,s1
- mtc0 t2,CP0_STATUS
- j ret_from_irq
-#endif
-
- .data
- PTR ll_sw0 # SW0
- PTR ll_sw1 # SW1
- PTR ll_local_dma # Local DMA
- PTR ll_local_dev # Local devices
- PTR ll_isa_irq # ISA IRQ
- PTR ll_isa_nmi # ISA NMI
- PTR ll_timer # Timer
-ll_vectors: PTR ll_count # Count/Compare IRQ
-
- /*
- * Interrupt handlers for local devices.
- */
- .text
- .set reorder
-loc_no_irq: PANIC("Unimplemented loc_no_irq handler")
-/*
- * Parallel port IRQ
- */
-loc_parallel: li s1,~JAZZ_IE_PARALLEL
- li a0,JAZZ_PARALLEL_IRQ
- b loc_call
-
-/*
- * Floppy IRQ
- */
-loc_floppy: li s1,~JAZZ_IE_FLOPPY
- li a0,JAZZ_FLOPPY_IRQ
- b loc_call
-
-/*
- * Sound IRQ
- */
-loc_sound: PANIC("Unimplemented loc_sound handler")
-loc_video: PANIC("Unimplemented loc_video handler")
-
-/*
- * Ethernet interrupt handler
- */
-loc_ethernet: li s1,~JAZZ_IE_ETHERNET
- li a0,JAZZ_ETHERNET_IRQ
- b loc_call
-
-/*
- * SCSI interrupt handler
- */
-loc_scsi: li s1,~JAZZ_IE_SCSI
- li a0,JAZZ_SCSI_IRQ
- b loc_call
-
-/*
- * Keyboard interrupt handler
- */
-loc_keyboard: li s1,~JAZZ_IE_KEYBOARD
- li a0,JAZZ_KEYBOARD_IRQ
- b loc_call
-
-/*
- * Mouse interrupt handler
- */
-loc_mouse: li s1,~JAZZ_IE_MOUSE
- li a0,JAZZ_MOUSE_IRQ
- b loc_call
-
-/*
- * Serial port 1 IRQ
- */
-loc_serial1: li s1,~JAZZ_IE_SERIAL1
- li a0,JAZZ_SERIAL1_IRQ
- b loc_call
-
-/*
- * Serial port 2 IRQ
- */
-loc_serial2: li s1,~JAZZ_IE_SERIAL2
- li a0,JAZZ_SERIAL2_IRQ
- b loc_call
-
-/*
- * Call the interrupt handler for an interrupt generated by a
- * local device.
- */
-loc_call: /*
- * Temporarily disable interrupt source
- */
- lhu t2,JAZZ_IO_IRQ_ENABLE
- and t2,s1
- sh t2,JAZZ_IO_IRQ_ENABLE
-
- nor s1,zero,s1
- jal do_IRQ
-
- /*
- * Reenable interrupt
- */
- lhu t2,JAZZ_IO_IRQ_ENABLE
- or t2,s1
- sh t2,JAZZ_IO_IRQ_ENABLE
-
- j ret_from_irq
-
-/*
- * "Jump extender" to reach spurious_interrupt
- */
-3: j spurious_interrupt
-
-/*
- * Vectors for interrupts generated by local devices
- */
- .data
-local_vector: PTR loc_no_irq
- PTR loc_parallel
- PTR loc_floppy
- PTR loc_sound
- PTR loc_video
- PTR loc_ethernet
- PTR loc_scsi
- PTR loc_keyboard
- PTR loc_mouse
- PTR loc_serial1
- PTR loc_serial2
diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c
index b309b1bcf2e..becc9accd49 100644
--- a/arch/mips/jazz/irq.c
+++ b/arch/mips/jazz/irq.c
@@ -15,8 +15,6 @@
#include <asm/io.h>
#include <asm/jazz.h>
-extern asmlinkage void jazz_handle_int(void);
-
static DEFINE_SPINLOCK(r4030_lock);
static void enable_r4030_irq(unsigned int irq)
@@ -90,10 +88,82 @@ void __init init_r4030_ints(void)
*/
void __init arch_init_irq(void)
{
- set_except_vector(0, jazz_handle_int);
-
init_i8259_irqs(); /* Integrated i8259 */
init_r4030_ints();
change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1);
}
+
+static void loc_call(unsigned int irq, struct pt_regs *regs, unsigned int mask)
+{
+ r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
+ r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) & mask);
+ do_IRQ(irq, regs);
+ r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
+ r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | mask);
+}
+
+static void ll_local_dev(struct pt_regs *regs)
+{
+ switch (r4030_read_reg32(JAZZ_IO_IRQ_SOURCE)) {
+ case 0:
+ panic("Unimplemented loc_no_irq handler");
+ break;
+ case 4:
+ loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_PARALLEL);
+ break;
+ case 8:
+ loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_FLOPPY);
+ break;
+ case 12:
+ panic("Unimplemented loc_sound handler");
+ break;
+ case 16:
+ panic("Unimplemented loc_video handler");
+ break;
+ case 20:
+ loc_call(JAZZ_ETHERNET_IRQ, regs, JAZZ_IE_ETHERNET);
+ break;
+ case 24:
+ loc_call(JAZZ_SCSI_IRQ, regs, JAZZ_IE_SCSI);
+ break;
+ case 28:
+ loc_call(JAZZ_KEYBOARD_IRQ, regs, JAZZ_IE_KEYBOARD);
+ break;
+ case 32:
+ loc_call(JAZZ_MOUSE_IRQ, regs, JAZZ_IE_MOUSE);
+ break;
+ case 36:
+ loc_call(JAZZ_SERIAL1_IRQ, regs, JAZZ_IE_SERIAL1);
+ break;
+ case 40:
+ loc_call(JAZZ_SERIAL2_IRQ, regs, JAZZ_IE_SERIAL2);
+ break;
+ }
+}
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+ if (pending & IE_IRQ5)
+ write_c0_compare(0);
+ else if (pending & IE_IRQ4) {
+ r4030_read_reg32(JAZZ_TIMER_REGISTER);
+ do_IRQ(JAZZ_TIMER_IRQ, regs);
+ } else if (pending & IE_IRQ3)
+ panic("Unimplemented ISA NMI handler");
+ else if (pending & IE_IRQ2)
+ do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK), regs);
+ else if (pending & IE_IRQ1) {
+ ll_local_dev(regs);
+ } else if (unlikely(pending & IE_IRQ0))
+ panic("Unimplemented local_dma handler");
+ else if (pending & IE_SW1) {
+ clear_c0_cause(IE_SW1);
+ panic("Unimplemented sw1 handler");
+ } else if (pending & IE_SW0) {
+ clear_c0_cause(IE_SW0);
+ panic("Unimplemented sw0 handler");
+ }
+}
diff --git a/arch/mips/jmr3927/common/rtc_ds1742.c b/arch/mips/jmr3927/common/rtc_ds1742.c
index a6bd3f4d304..e6561345d12 100644
--- a/arch/mips/jmr3927/common/rtc_ds1742.c
+++ b/arch/mips/jmr3927/common/rtc_ds1742.c
@@ -60,15 +60,15 @@ rtc_ds1742_get_time(void)
unsigned long flags;
spin_lock_irqsave(&rtc_lock, flags);
- CMOS_WRITE(RTC_READ, RTC_CONTROL);
- second = BCD2BIN(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK);
- minute = BCD2BIN(CMOS_READ(RTC_MINUTES));
- hour = BCD2BIN(CMOS_READ(RTC_HOURS));
- day = BCD2BIN(CMOS_READ(RTC_DATE));
- month = BCD2BIN(CMOS_READ(RTC_MONTH));
- year = BCD2BIN(CMOS_READ(RTC_YEAR));
- century = BCD2BIN(CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK);
- CMOS_WRITE(0, RTC_CONTROL);
+ rtc_write(RTC_READ, RTC_CONTROL);
+ second = BCD2BIN(rtc_read(RTC_SECONDS) & RTC_SECONDS_MASK);
+ minute = BCD2BIN(rtc_read(RTC_MINUTES));
+ hour = BCD2BIN(rtc_read(RTC_HOURS));
+ day = BCD2BIN(rtc_read(RTC_DATE));
+ month = BCD2BIN(rtc_read(RTC_MONTH));
+ year = BCD2BIN(rtc_read(RTC_YEAR));
+ century = BCD2BIN(rtc_read(RTC_CENTURY) & RTC_CENTURY_MASK);
+ rtc_write(0, RTC_CONTROL);
spin_unlock_irqrestore(&rtc_lock, flags);
year += century * 100;
@@ -87,16 +87,16 @@ rtc_ds1742_set_time(unsigned long t)
unsigned long flags;
spin_lock_irqsave(&rtc_lock, flags);
- CMOS_WRITE(RTC_READ, RTC_CONTROL);
- cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK);
- cmos_minute = (u8)CMOS_READ(RTC_MINUTES);
- cmos_hour = (u8)CMOS_READ(RTC_HOURS);
- cmos_day = (u8)CMOS_READ(RTC_DATE);
- cmos_month = (u8)CMOS_READ(RTC_MONTH);
- cmos_year = (u8)CMOS_READ(RTC_YEAR);
- cmos_century = CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK;
+ rtc_write(RTC_READ, RTC_CONTROL);
+ cmos_second = (u8)(rtc_read(RTC_SECONDS) & RTC_SECONDS_MASK);
+ cmos_minute = (u8)rtc_read(RTC_MINUTES);
+ cmos_hour = (u8)rtc_read(RTC_HOURS);
+ cmos_day = (u8)rtc_read(RTC_DATE);
+ cmos_month = (u8)rtc_read(RTC_MONTH);
+ cmos_year = (u8)rtc_read(RTC_YEAR);
+ cmos_century = rtc_read(RTC_CENTURY) & RTC_CENTURY_MASK;
- CMOS_WRITE(RTC_WRITE, RTC_CONTROL);
+ rtc_write(RTC_WRITE, RTC_CONTROL);
/* convert */
to_tm(t, &tm);
@@ -104,18 +104,18 @@ rtc_ds1742_set_time(unsigned long t)
/* check each field one by one */
year = BIN2BCD(tm.tm_year - EPOCH);
if (year != cmos_year) {
- CMOS_WRITE(year,RTC_YEAR);
+ rtc_write(year,RTC_YEAR);
}
month = BIN2BCD(tm.tm_mon);
if (month != (cmos_month & 0x1f)) {
- CMOS_WRITE((month & 0x1f) | (cmos_month & ~0x1f),RTC_MONTH);
+ rtc_write((month & 0x1f) | (cmos_month & ~0x1f),RTC_MONTH);
}
day = BIN2BCD(tm.tm_mday);
if (day != cmos_day) {
- CMOS_WRITE(day, RTC_DATE);
+ rtc_write(day, RTC_DATE);
}
if (cmos_hour & 0x40) {
@@ -130,20 +130,20 @@ rtc_ds1742_set_time(unsigned long t)
/* 24 hour format */
hour = BIN2BCD(tm.tm_hour) & 0x3f;
}
- if (hour != cmos_hour) CMOS_WRITE(hour, RTC_HOURS);
+ if (hour != cmos_hour) rtc_write(hour, RTC_HOURS);
minute = BIN2BCD(tm.tm_min);
if (minute != cmos_minute) {
- CMOS_WRITE(minute, RTC_MINUTES);
+ rtc_write(minute, RTC_MINUTES);
}
second = BIN2BCD(tm.tm_sec);
if (second != cmos_second) {
- CMOS_WRITE(second & RTC_SECONDS_MASK,RTC_SECONDS);
+ rtc_write(second & RTC_SECONDS_MASK,RTC_SECONDS);
}
/* RTC_CENTURY and RTC_CONTROL share same address... */
- CMOS_WRITE(cmos_century, RTC_CONTROL);
+ rtc_write(cmos_century, RTC_CONTROL);
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
@@ -163,9 +163,9 @@ rtc_ds1742_init(unsigned long base)
rtc_mips_set_time = rtc_ds1742_set_time;
/* clear oscillator stop bit */
- CMOS_WRITE(RTC_READ, RTC_CONTROL);
- cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK);
- CMOS_WRITE(RTC_WRITE, RTC_CONTROL);
- CMOS_WRITE(cmos_second, RTC_SECONDS); /* clear msb */
- CMOS_WRITE(0, RTC_CONTROL);
+ rtc_write(RTC_READ, RTC_CONTROL);
+ cmos_second = (u8)(rtc_read(RTC_SECONDS) & RTC_SECONDS_MASK);
+ rtc_write(RTC_WRITE, RTC_CONTROL);
+ rtc_write(cmos_second, RTC_SECONDS); /* clear msb */
+ rtc_write(0, RTC_CONTROL);
}
diff --git a/arch/mips/jmr3927/rbhma3100/Makefile b/arch/mips/jmr3927/rbhma3100/Makefile
index 75bf418b94c..baf5077813c 100644
--- a/arch/mips/jmr3927/rbhma3100/Makefile
+++ b/arch/mips/jmr3927/rbhma3100/Makefile
@@ -2,7 +2,7 @@
# Makefile for TOSHIBA JMR-TX3927 board
#
-obj-y += init.o int-handler.o irq.o setup.o
+obj-y += init.o irq.o setup.o
obj-$(CONFIG_RUNTIME_DEBUG) += debug.o
obj-$(CONFIG_KGDB) += kgdb_io.o
diff --git a/arch/mips/jmr3927/rbhma3100/int-handler.S b/arch/mips/jmr3927/rbhma3100/int-handler.S
deleted file mode 100644
index f85bbf40754..00000000000
--- a/arch/mips/jmr3927/rbhma3100/int-handler.S
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ahennessy@mvista.com
- *
- * Based on arch/mips/tsdb/kernel/int-handler.S
- *
- * Copyright (C) 2000-2001 Toshiba Corporation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include <asm/jmr3927/jmr3927.h>
-
- /* A lot of complication here is taken away because:
- *
- * 1) We handle one interrupt and return, sitting in a loop
- * and moving across all the pending IRQ bits in the cause
- * register is _NOT_ the answer, the common case is one
- * pending IRQ so optimize in that direction.
- *
- * 2) We need not check against bits in the status register
- * IRQ mask, that would make this routine slow as hell.
- *
- * 3) Linux only thinks in terms of all IRQs on or all IRQs
- * off, nothing in between like BSD spl() brain-damage.
- *
- */
-
-/* Flush write buffer (needed?)
- * NOTE: TX39xx performs "non-blocking load", so explicitly use the target
- * register of LBU to flush immediately.
- */
-#define FLUSH_WB(tmp) \
- la tmp, JMR3927_IOC_REV_ADDR; \
- lbu tmp, (tmp); \
- move tmp, zero;
-
- .text
- .set noreorder
- .set noat
- .align 5
- NESTED(jmr3927_IRQ, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- jal jmr3927_irc_irqdispatch
- move a0, sp
- FLUSH_WB(t0)
- j ret_from_irq
- nop
- END(jmr3927_IRQ)
diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c
index 2810727f1d4..11304d1354f 100644
--- a/arch/mips/jmr3927/rbhma3100/irq.c
+++ b/arch/mips/jmr3927/rbhma3100/irq.c
@@ -77,8 +77,6 @@ static int jmr3927_gen_iack(void)
}
#endif
-extern asmlinkage void jmr3927_IRQ(void);
-
#define irc_dlevel 0
#define irc_elevel 1
@@ -262,7 +260,7 @@ void jmr3927_spurious(struct pt_regs *regs)
regs->cp0_cause, regs->cp0_epc, regs->regs[31]);
}
-void jmr3927_irc_irqdispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
int irq;
@@ -398,8 +396,6 @@ void __init arch_init_irq(void)
jmr3927_irq_init(NR_ISA_IRQS);
- set_except_vector(0, jmr3927_IRQ);
-
/* setup irq space */
add_tb_irq_space(&jmr3927_isac_irqspace);
add_tb_irq_space(&jmr3927_ioc_irqspace);
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 309d54cceda..34e8a256765 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -34,8 +34,11 @@ obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o
obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_MIPS_MT_SMP) += smp_mt.o
+obj-$(CONFIG_MIPS_MT) += mips-mt.o
+obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
+obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
+obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o
obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o
obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index ca6b03c773b..92b28b674d6 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -69,6 +69,9 @@ void output_ptreg_defines(void)
offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr);
offset("#define PT_STATUS ", struct pt_regs, cp0_status);
offset("#define PT_CAUSE ", struct pt_regs, cp0_cause);
+#ifdef CONFIG_MIPS_MT_SMTC
+ offset("#define PT_TCSTATUS ", struct pt_regs, cp0_tcstatus);
+#endif /* CONFIG_MIPS_MT_SMTC */
size("#define PT_SIZE ", struct pt_regs);
linefeed;
}
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 83c87fe4ee4..d101d2fb24c 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -17,6 +17,9 @@
#include <asm/isadep.h>
#include <asm/thread_info.h>
#include <asm/war.h>
+#ifdef CONFIG_MIPS_MT_SMTC
+#include <asm/mipsmtregs.h>
+#endif
#ifdef CONFIG_PREEMPT
.macro preempt_stop
@@ -75,6 +78,37 @@ FEXPORT(syscall_exit)
bnez t0, syscall_exit_work
FEXPORT(restore_all) # restore full frame
+#ifdef CONFIG_MIPS_MT_SMTC
+/* Detect and execute deferred IPI "interrupts" */
+ move a0,sp
+ jal deferred_smtc_ipi
+/* Re-arm any temporarily masked interrupts not explicitly "acked" */
+ mfc0 v0, CP0_TCSTATUS
+ ori v1, v0, TCSTATUS_IXMT
+ mtc0 v1, CP0_TCSTATUS
+ andi v0, TCSTATUS_IXMT
+ ehb
+ mfc0 t0, CP0_TCCONTEXT
+ DMT 9 # dmt t1
+ jal mips_ihb
+ mfc0 t2, CP0_STATUS
+ andi t3, t0, 0xff00
+ or t2, t2, t3
+ mtc0 t2, CP0_STATUS
+ ehb
+ andi t1, t1, VPECONTROL_TE
+ beqz t1, 1f
+ EMT
+1:
+ mfc0 v1, CP0_TCSTATUS
+ /* We set IXMT above, XOR should cler it here */
+ xori v1, v1, TCSTATUS_IXMT
+ or v1, v0, v1
+ mtc0 v1, CP0_TCSTATUS
+ ehb
+ xor t0, t0, t3
+ mtc0 t0, CP0_TCCONTEXT
+#endif /* CONFIG_MIPS_MT_SMTC */
.set noat
RESTORE_TEMP
RESTORE_AT
@@ -120,28 +154,17 @@ syscall_exit_work:
jal do_syscall_trace
b resume_userspace
+#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT)
+
/*
- * Common spurious interrupt handler.
+ * MIPS32R2 Instruction Hazard Barrier - must be called
+ *
+ * For C code use the inline version named instruction_hazard().
*/
-LEAF(spurious_interrupt)
- /*
- * Someone tried to fool us by sending an interrupt but we
- * couldn't find a cause for it.
- */
- PTR_LA t1, irq_err_count
-#ifdef CONFIG_SMP
-1: ll t0, (t1)
- addiu t0, 1
- sc t0, (t1)
-#if R10000_LLSC_WAR
- beqzl t0, 1b
-#else
- beqz t0, 1b
-#endif
-#else
- lw t0, (t1)
- addiu t0, 1
- sw t0, (t1)
-#endif
- j ret_from_irq
- END(spurious_interrupt)
+LEAF(mips_ihb)
+ .set mips32r2
+ jr.hb ra
+ nop
+ END(mips_ihb)
+
+#endif /* CONFIG_CPU_MIPSR2 or CONFIG_MIPS_MT */
diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S
index 235ad9f6bd3..10f28fb9f00 100644
--- a/arch/mips/kernel/gdb-low.S
+++ b/arch/mips/kernel/gdb-low.S
@@ -283,11 +283,33 @@
*/
3:
+#ifdef CONFIG_MIPS_MT_SMTC
+ /* Read-modify write of Status must be atomic */
+ mfc0 t2, CP0_TCSTATUS
+ ori t1, t2, TCSTATUS_IXMT
+ mtc0 t1, CP0_TCSTATUS
+ andi t2, t2, TCSTATUS_IXMT
+ ehb
+ DMT 9 # dmt t1
+ jal mips_ihb
+ nop
+#endif /* CONFIG_MIPS_MT_SMTC */
mfc0 t0, CP0_STATUS
ori t0, 0x1f
xori t0, 0x1f
mtc0 t0, CP0_STATUS
-
+#ifdef CONFIG_MIPS_MT_SMTC
+ andi t1, t1, VPECONTROL_TE
+ beqz t1, 9f
+ nop
+ EMT # emt
+9:
+ mfc0 t1, CP0_TCSTATUS
+ xori t1, t1, TCSTATUS_IXMT
+ or t1, t1, t2
+ mtc0 t1, CP0_TCSTATUS
+ ehb
+#endif /* CONFIG_MIPS_MT_SMTC */
LONG_L v0, GDB_FR_STATUS(sp)
LONG_L v1, GDB_FR_EPC(sp)
mtc0 v0, CP0_STATUS
diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c
index d4f88e0af24..6ecbdc1fefd 100644
--- a/arch/mips/kernel/gdb-stub.c
+++ b/arch/mips/kernel/gdb-stub.c
@@ -140,6 +140,7 @@
#include <asm/system.h>
#include <asm/gdb-stub.h>
#include <asm/inst.h>
+#include <asm/smp.h>
/*
* external low-level support routines
@@ -669,6 +670,64 @@ static void kgdb_wait(void *arg)
local_irq_restore(flags);
}
+/*
+ * GDB stub needs to call kgdb_wait on all processor with interrupts
+ * disabled, so it uses it's own special variant.
+ */
+static int kgdb_smp_call_kgdb_wait(void)
+{
+#ifdef CONFIG_SMP
+ struct call_data_struct data;
+ int i, cpus = num_online_cpus() - 1;
+ int cpu = smp_processor_id();
+
+ /*
+ * Can die spectacularly if this CPU isn't yet marked online
+ */
+ BUG_ON(!cpu_online(cpu));
+
+ if (!cpus)
+ return 0;
+
+ if (spin_is_locked(&smp_call_lock)) {
+ /*
+ * Some other processor is trying to make us do something
+ * but we're not going to respond... give up
+ */
+ return -1;
+ }
+
+ /*
+ * We will continue here, accepting the fact that
+ * the kernel may deadlock if another CPU attempts
+ * to call smp_call_function now...
+ */
+
+ data.func = kgdb_wait;
+ data.info = NULL;
+ atomic_set(&data.started, 0);
+ data.wait = 0;
+
+ spin_lock(&smp_call_lock);
+ call_data = &data;
+ mb();
+
+ /* Send a message to all other CPUs and wait for them to respond */
+ for (i = 0; i < NR_CPUS; i++)
+ if (cpu_online(i) && i != cpu)
+ core_send_ipi(i, SMP_CALL_FUNCTION);
+
+ /* Wait for response */
+ /* FIXME: lock-up detection, backtrace on lock-up */
+ while (atomic_read(&data.started) != cpus)
+ barrier();
+
+ call_data = NULL;
+ spin_unlock(&smp_call_lock);
+#endif
+
+ return 0;
+}
/*
* This function does all command processing for interfacing to gdb. It
@@ -718,7 +777,7 @@ void handle_exception (struct gdb_regs *regs)
/*
* force other cpus to enter kgdb
*/
- smp_call_function(kgdb_wait, NULL, 0, 0);
+ kgdb_smp_call_kgdb_wait();
/*
* If we're in breakpoint() increment the PC
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index 13f22d1d0e8..ff7af369f28 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <asm/asm.h>
+#include <asm/asmmacro.h>
#include <asm/cacheops.h>
#include <asm/regdef.h>
#include <asm/fpregdef.h>
@@ -122,6 +123,20 @@ handle_vcei:
.set pop
END(except_vec3_r4000)
+ __FINIT
+
+ .align 5
+NESTED(handle_int, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+
+ PTR_LA ra, ret_from_irq
+ move a0, sp
+ j plat_irq_dispatch
+ END(handle_int)
+
+ __INIT
+
/*
* Special interrupt vector for MIPS64 ISA & embedded MIPS processors.
* This is a dedicated interrupt exception vector which reduces the
@@ -157,6 +172,15 @@ NESTED(except_vec_vi, 0, sp)
SAVE_AT
.set push
.set noreorder
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * To keep from blindly blocking *all* interrupts
+ * during service by SMTC kernel, we also want to
+ * pass the IM value to be cleared.
+ */
+EXPORT(except_vec_vi_mori)
+ ori a0, $0, 0
+#endif /* CONFIG_MIPS_MT_SMTC */
EXPORT(except_vec_vi_lui)
lui v0, 0 /* Patched */
j except_vec_vi_handler
@@ -173,6 +197,25 @@ EXPORT(except_vec_vi_end)
NESTED(except_vec_vi_handler, 0, sp)
SAVE_TEMP
SAVE_STATIC
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * SMTC has an interesting problem that interrupts are level-triggered,
+ * and the CLI macro will clear EXL, potentially causing a duplicate
+ * interrupt service invocation. So we need to clear the associated
+ * IM bit of Status prior to doing CLI, and restore it after the
+ * service routine has been invoked - we must assume that the
+ * service routine will have cleared the state, and any active
+ * level represents a new or otherwised unserviced event...
+ */
+ mfc0 t1, CP0_STATUS
+ and t0, a0, t1
+ mfc0 t2, CP0_TCCONTEXT
+ or t0, t0, t2
+ mtc0 t0, CP0_TCCONTEXT
+ xor t1, t1, t0
+ mtc0 t1, CP0_STATUS
+ ehb
+#endif /* CONFIG_MIPS_MT_SMTC */
CLI
move a0, sp
jalr v0
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 2e9122a4213..bdf6f6eff72 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -18,6 +18,7 @@
#include <linux/threads.h>
#include <asm/asm.h>
+#include <asm/asmmacro.h>
#include <asm/regdef.h>
#include <asm/page.h>
#include <asm/mipsregs.h>
@@ -82,12 +83,33 @@
*/
.macro setup_c0_status set clr
.set push
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * For SMTC, we need to set privilege and disable interrupts only for
+ * the current TC, using the TCStatus register.
+ */
+ mfc0 t0, CP0_TCSTATUS
+ /* Fortunately CU 0 is in the same place in both registers */
+ /* Set TCU0, TMX, TKSU (for later inversion) and IXMT */
+ li t1, ST0_CU0 | 0x08001c00
+ or t0, t1
+ /* Clear TKSU, leave IXMT */
+ xori t0, 0x00001800
+ mtc0 t0, CP0_TCSTATUS
+ ehb
+ /* We need to leave the global IE bit set, but clear EXL...*/
+ mfc0 t0, CP0_STATUS
+ or t0, ST0_CU0 | ST0_EXL | ST0_ERL | \set | \clr
+ xor t0, ST0_EXL | ST0_ERL | \clr
+ mtc0 t0, CP0_STATUS
+#else
mfc0 t0, CP0_STATUS
or t0, ST0_CU0|\set|0x1f|\clr
xor t0, 0x1f|\clr
mtc0 t0, CP0_STATUS
.set noreorder
sll zero,3 # ehb
+#endif
.set pop
.endm
@@ -134,6 +156,24 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
ARC64_TWIDDLE_PC
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * In SMTC kernel, "CLI" is thread-specific, in TCStatus.
+ * We still need to enable interrupts globally in Status,
+ * and clear EXL/ERL.
+ *
+ * TCContext is used to track interrupt levels under
+ * service in SMTC kernel. Clear for boot TC before
+ * allowing any interrupts.
+ */
+ mtc0 zero, CP0_TCCONTEXT
+
+ mfc0 t0, CP0_STATUS
+ ori t0, t0, 0xff1f
+ xori t0, t0, 0x001e
+ mtc0 t0, CP0_STATUS
+#endif /* CONFIG_MIPS_MT_SMTC */
+
PTR_LA t0, __bss_start # clear .bss
LONG_S zero, (t0)
PTR_LA t1, __bss_stop - LONGSIZE
@@ -166,8 +206,25 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
* function after setting up the stack and gp registers.
*/
NESTED(smp_bootstrap, 16, sp)
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * Read-modify-writes of Status must be atomic, and this
+ * is one case where CLI is invoked without EXL being
+ * necessarily set. The CLI and setup_c0_status will
+ * in fact be redundant for all but the first TC of
+ * each VPE being booted.
+ */
+ DMT 10 # dmt t2 /* t0, t1 are used by CLI and setup_c0_status() */
+ jal mips_ihb
+#endif /* CONFIG_MIPS_MT_SMTC */
setup_c0_status_sec
smp_slave_setup
+#ifdef CONFIG_MIPS_MT_SMTC
+ andi t2, t2, VPECONTROL_TE
+ beqz t2, 2f
+ EMT # emt
+2:
+#endif /* CONFIG_MIPS_MT_SMTC */
j start_secondary
END(smp_bootstrap)
#endif /* CONFIG_SMP */
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index b974ac9057f..2125ba5f1d9 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -187,6 +187,10 @@ handle_real_irq:
outb(cached_21,0x21);
outb(0x60+irq,0x20); /* 'Specific EOI' to master */
}
+#ifdef CONFIG_MIPS_MT_SMTC
+ if (irq_hwmask[irq] & ST0_IM)
+ set_c0_status(irq_hwmask[irq] & ST0_IM);
+#endif /* CONFIG_MIPS_MT_SMTC */
spin_unlock_irqrestore(&i8259A_lock, flags);
return;
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
index 3f653c7cfbf..97ebdc754b9 100644
--- a/arch/mips/kernel/irq-msc01.c
+++ b/arch/mips/kernel/irq-msc01.c
@@ -76,6 +76,11 @@ static void level_mask_and_ack_msc_irq(unsigned int irq)
mask_msc_irq(irq);
if (!cpu_has_veic)
MSCIC_WRITE(MSC01_IC_EOI, 0);
+#ifdef CONFIG_MIPS_MT_SMTC
+ /* This actually needs to be a call into platform code */
+ if (irq_hwmask[irq] & ST0_IM)
+ set_c0_status(irq_hwmask[irq] & ST0_IM);
+#endif /* CONFIG_MIPS_MT_SMTC */
}
/*
@@ -92,6 +97,10 @@ static void edge_mask_and_ack_msc_irq(unsigned int irq)
MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT);
MSCIC_WRITE(MSC01_IC_SUP+irq*8, r);
}
+#ifdef CONFIG_MIPS_MT_SMTC
+ if (irq_hwmask[irq] & ST0_IM)
+ set_c0_status(irq_hwmask[irq] & ST0_IM);
+#endif /* CONFIG_MIPS_MT_SMTC */
}
/*
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index 3dd76b3d296..3dce742e716 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -38,6 +38,15 @@ void ack_bad_irq(unsigned int irq)
atomic_t irq_err_count;
+#ifdef CONFIG_MIPS_MT_SMTC
+/*
+ * SMTC Kernel needs to manipulate low-level CPU interrupt mask
+ * in do_IRQ. These are passed in setup_irq_smtc() and stored
+ * in this table.
+ */
+unsigned long irq_hwmask[NR_IRQS];
+#endif /* CONFIG_MIPS_MT_SMTC */
+
#undef do_IRQ
/*
@@ -49,6 +58,7 @@ asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs)
{
irq_enter();
+ __DO_IRQ_SMTC_HOOK();
__do_IRQ(irq, regs);
irq_exit();
@@ -101,6 +111,11 @@ skip:
return 0;
}
+asmlinkage void spurious_interrupt(struct pt_regs *regs)
+{
+ atomic_inc(&irq_err_count);
+}
+
#ifdef CONFIG_KGDB
extern void breakpoint(void);
extern void set_debug_traps(void);
@@ -124,6 +139,9 @@ void __init init_IRQ(void)
irq_desc[i].depth = 1;
irq_desc[i].handler = &no_irq_type;
spin_lock_init(&irq_desc[i].lock);
+#ifdef CONFIG_MIPS_MT_SMTC
+ irq_hwmask[i] = 0;
+#endif /* CONFIG_MIPS_MT_SMTC */
}
arch_init_irq();
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
new file mode 100644
index 00000000000..f06a144c788
--- /dev/null
+++ b/arch/mips/kernel/kspd.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/unistd.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/syscalls.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+
+#include <asm/vpe.h>
+#include <asm/rtlx.h>
+#include <asm/kspd.h>
+
+static struct workqueue_struct *workqueue = NULL;
+static struct work_struct work;
+
+extern unsigned long cpu_khz;
+
+struct mtsp_syscall {
+ int cmd;
+ unsigned char abi;
+ unsigned char size;
+};
+
+struct mtsp_syscall_ret {
+ int retval;
+ int errno;
+};
+
+struct mtsp_syscall_generic {
+ int arg0;
+ int arg1;
+ int arg2;
+ int arg3;
+ int arg4;
+ int arg5;
+ int arg6;
+};
+
+static struct list_head kspd_notifylist;
+static int sp_stopping = 0;
+
+/* these should match with those in the SDE kit */
+#define MTSP_SYSCALL_BASE 0
+#define MTSP_SYSCALL_EXIT (MTSP_SYSCALL_BASE + 0)
+#define MTSP_SYSCALL_OPEN (MTSP_SYSCALL_BASE + 1)
+#define MTSP_SYSCALL_READ (MTSP_SYSCALL_BASE + 2)
+#define MTSP_SYSCALL_WRITE (MTSP_SYSCALL_BASE + 3)
+#define MTSP_SYSCALL_CLOSE (MTSP_SYSCALL_BASE + 4)
+#define MTSP_SYSCALL_LSEEK32 (MTSP_SYSCALL_BASE + 5)
+#define MTSP_SYSCALL_ISATTY (MTSP_SYSCALL_BASE + 6)
+#define MTSP_SYSCALL_GETTIME (MTSP_SYSCALL_BASE + 7)
+#define MTSP_SYSCALL_PIPEFREQ (MTSP_SYSCALL_BASE + 8)
+#define MTSP_SYSCALL_GETTOD (MTSP_SYSCALL_BASE + 9)
+
+#define MTSP_O_RDONLY 0x0000
+#define MTSP_O_WRONLY 0x0001
+#define MTSP_O_RDWR 0x0002
+#define MTSP_O_NONBLOCK 0x0004
+#define MTSP_O_APPEND 0x0008
+#define MTSP_O_SHLOCK 0x0010
+#define MTSP_O_EXLOCK 0x0020
+#define MTSP_O_ASYNC 0x0040
+#define MTSP_O_FSYNC O_SYNC
+#define MTSP_O_NOFOLLOW 0x0100
+#define MTSP_O_SYNC 0x0080
+#define MTSP_O_CREAT 0x0200
+#define MTSP_O_TRUNC 0x0400
+#define MTSP_O_EXCL 0x0800
+#define MTSP_O_BINARY 0x8000
+
+#define SP_VPE 1
+
+struct apsp_table {
+ int sp;
+ int ap;
+};
+
+/* we might want to do the mode flags too */
+struct apsp_table open_flags_table[] = {
+ { MTSP_O_RDWR, O_RDWR },
+ { MTSP_O_WRONLY, O_WRONLY },
+ { MTSP_O_CREAT, O_CREAT },
+ { MTSP_O_TRUNC, O_TRUNC },
+ { MTSP_O_NONBLOCK, O_NONBLOCK },
+ { MTSP_O_APPEND, O_APPEND },
+ { MTSP_O_NOFOLLOW, O_NOFOLLOW }
+};
+
+struct apsp_table syscall_command_table[] = {
+ { MTSP_SYSCALL_OPEN, __NR_open },
+ { MTSP_SYSCALL_CLOSE, __NR_close },
+ { MTSP_SYSCALL_READ, __NR_read },
+ { MTSP_SYSCALL_WRITE, __NR_write },
+ { MTSP_SYSCALL_LSEEK32, __NR_lseek }
+};
+
+static int sp_syscall(int num, int arg0, int arg1, int arg2, int arg3)
+{
+ register long int _num __asm__ ("$2") = num;
+ register long int _arg0 __asm__ ("$4") = arg0;
+ register long int _arg1 __asm__ ("$5") = arg1;
+ register long int _arg2 __asm__ ("$6") = arg2;
+ register long int _arg3 __asm__ ("$7") = arg3;
+
+ mm_segment_t old_fs;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ __asm__ __volatile__ (
+ " syscall \n"
+ : "=r" (_num), "=r" (_arg3)
+ : "r" (_num), "r" (_arg0), "r" (_arg1), "r" (_arg2), "r" (_arg3));
+
+ set_fs(old_fs);
+
+ /* $a3 is error flag */
+ if (_arg3)
+ return -_num;
+
+ return _num;
+}
+
+static int translate_syscall_command(int cmd)
+{
+ int i;
+ int ret = -1;
+
+ for (i = 0; i < ARRAY_SIZE(syscall_command_table); i++) {
+ if ((cmd == syscall_command_table[i].sp))
+ return syscall_command_table[i].ap;
+ }
+
+ return ret;
+}
+
+static unsigned int translate_open_flags(int flags)
+{
+ int i;
+ unsigned int ret = 0;
+
+ for (i = 0; i < (sizeof(open_flags_table) / sizeof(struct apsp_table));
+ i++) {
+ if( (flags & open_flags_table[i].sp) ) {
+ ret |= open_flags_table[i].ap;
+ }
+ }
+
+ return ret;
+}
+
+
+static void sp_setfsuidgid( uid_t uid, gid_t gid)
+{
+ current->fsuid = uid;
+ current->fsgid = gid;
+
+ key_fsuid_changed(current);
+ key_fsgid_changed(current);
+}
+
+/*
+ * Expects a request to be on the sysio channel. Reads it. Decides whether
+ * its a linux syscall and runs it, or whatever. Puts the return code back
+ * into the request and sends the whole thing back.
+ */
+void sp_work_handle_request(void)
+{
+ struct mtsp_syscall sc;
+ struct mtsp_syscall_generic generic;
+ struct mtsp_syscall_ret ret;
+ struct kspd_notifications *n;
+ struct timeval tv;
+ struct timezone tz;
+ int cmd;
+
+ char *vcwd;
+ mm_segment_t old_fs;
+ int size;
+
+ ret.retval = -1;
+
+ if (!rtlx_read(RTLX_CHANNEL_SYSIO, &sc, sizeof(struct mtsp_syscall), 0)) {
+ printk(KERN_ERR "Expected request but nothing to read\n");
+ return;
+ }
+
+ size = sc.size;
+
+ if (size) {
+ if (!rtlx_read(RTLX_CHANNEL_SYSIO, &generic, size, 0)) {
+ printk(KERN_ERR "Expected request but nothing to read\n");
+ return;
+ }
+ }
+
+ /* Run the syscall at the priviledge of the user who loaded the
+ SP program */
+
+ if (vpe_getuid(SP_VPE))
+ sp_setfsuidgid( vpe_getuid(SP_VPE), vpe_getgid(SP_VPE));
+
+ switch (sc.cmd) {
+ /* needs the flags argument translating from SDE kit to
+ linux */
+ case MTSP_SYSCALL_PIPEFREQ:
+ ret.retval = cpu_khz * 1000;
+ ret.errno = 0;
+ break;
+
+ case MTSP_SYSCALL_GETTOD:
+ memset(&tz, 0, sizeof(tz));
+ if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv,
+ (int)&tz, 0,0)) == 0)
+ ret.retval = tv.tv_sec;
+
+ ret.errno = errno;
+ break;
+
+ case MTSP_SYSCALL_EXIT:
+ list_for_each_entry(n, &kspd_notifylist, list)
+ n->kspd_sp_exit(SP_VPE);
+ sp_stopping = 1;
+
+ printk(KERN_DEBUG "KSPD got exit syscall from SP exitcode %d\n",
+ generic.arg0);
+ break;
+
+ case MTSP_SYSCALL_OPEN:
+ generic.arg1 = translate_open_flags(generic.arg1);
+
+ vcwd = vpe_getcwd(SP_VPE);
+
+ /* change to the cwd of the process that loaded the SP program */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ sys_chdir(vcwd);
+ set_fs(old_fs);
+
+ sc.cmd = __NR_open;
+
+ /* fall through */
+
+ default:
+ if ((sc.cmd >= __NR_Linux) &&
+ (sc.cmd <= (__NR_Linux + __NR_Linux_syscalls)) )
+ cmd = sc.cmd;
+ else
+ cmd = translate_syscall_command(sc.cmd);
+
+ if (cmd >= 0) {
+ ret.retval = sp_syscall(cmd, generic.arg0, generic.arg1,
+ generic.arg2, generic.arg3);
+ ret.errno = errno;
+ } else
+ printk(KERN_WARNING
+ "KSPD: Unknown SP syscall number %d\n", sc.cmd);
+ break;
+ } /* switch */
+
+ if (vpe_getuid(SP_VPE))
+ sp_setfsuidgid( 0, 0);
+
+ if ((rtlx_write(RTLX_CHANNEL_SYSIO, &ret, sizeof(struct mtsp_syscall_ret), 0))
+ < sizeof(struct mtsp_syscall_ret))
+ printk("KSPD: sp_work_handle_request failed to send to SP\n");
+}
+
+static void sp_cleanup(void)
+{
+ struct files_struct *files = current->files;
+ int i, j;
+ struct fdtable *fdt;
+
+ j = 0;
+
+ /*
+ * It is safe to dereference the fd table without RCU or
+ * ->file_lock
+ */
+ fdt = files_fdtable(files);
+ for (;;) {
+ unsigned long set;
+ i = j * __NFDBITS;
+ if (i >= fdt->max_fdset || i >= fdt->max_fds)
+ break;
+ set = fdt->open_fds->fds_bits[j++];
+ while (set) {
+ if (set & 1) {
+ struct file * file = xchg(&fdt->fd[i], NULL);
+ if (file)
+ filp_close(file, files);
+ }
+ i++;
+ set >>= 1;
+ }
+ }
+}
+
+static int channel_open = 0;
+
+/* the work handler */
+static void sp_work(void *data)
+{
+ if (!channel_open) {
+ if( rtlx_open(RTLX_CHANNEL_SYSIO, 1) != 0) {
+ printk("KSPD: unable to open sp channel\n");
+ sp_stopping = 1;
+ } else {
+ channel_open++;
+ printk(KERN_DEBUG "KSPD: SP channel opened\n");
+ }
+ } else {
+ /* wait for some data, allow it to sleep */
+ rtlx_read_poll(RTLX_CHANNEL_SYSIO, 1);
+
+ /* Check we haven't been woken because we are stopping */
+ if (!sp_stopping)
+ sp_work_handle_request();
+ }
+
+ if (!sp_stopping)
+ queue_work(workqueue, &work);
+ else
+ sp_cleanup();
+}
+
+static void startwork(int vpe)
+{
+ sp_stopping = channel_open = 0;
+
+ if (workqueue == NULL) {
+ if ((workqueue = create_singlethread_workqueue("kspd")) == NULL) {
+ printk(KERN_ERR "unable to start kspd\n");
+ return;
+ }
+
+ INIT_WORK(&work, sp_work, NULL);
+ queue_work(workqueue, &work);
+ } else
+ queue_work(workqueue, &work);
+
+}
+
+static void stopwork(int vpe)
+{
+ sp_stopping = 1;
+
+ printk(KERN_DEBUG "KSPD: SP stopping\n");
+}
+
+void kspd_notify(struct kspd_notifications *notify)
+{
+ list_add(&notify->list, &kspd_notifylist);
+}
+
+static struct vpe_notifications notify;
+static int kspd_module_init(void)
+{
+ INIT_LIST_HEAD(&kspd_notifylist);
+
+ notify.start = startwork;
+ notify.stop = stopwork;
+ vpe_notify(SP_VPE, &notify);
+
+ return 0;
+}
+
+static void kspd_module_exit(void)
+{
+
+}
+
+module_init(kspd_module_init);
+module_exit(kspd_module_exit);
+
+MODULE_DESCRIPTION("MIPS KSPD");
+MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 3f40c37a9ee..7c953bcc5f6 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -1182,6 +1182,16 @@ asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
return sys_readahead(fd, merge_64(a2, a3), count);
}
+asmlinkage long sys32_sync_file_range(int fd, int __pad,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ int flags)
+{
+ return sys_sync_file_range(fd,
+ merge_64(a2, a3), merge_64(a4, a5),
+ flags);
+}
+
/* Argument list sizes for sys_socketcall */
#define AL(x) ((x) * sizeof(unsigned int))
static unsigned char socketcall_nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c
new file mode 100644
index 00000000000..02237a685ec
--- /dev/null
+++ b/arch/mips/kernel/mips-mt.c
@@ -0,0 +1,449 @@
+/*
+ * General MIPS MT support routines, usable in AP/SP, SMVP, or SMTC kernels
+ * Copyright (C) 2005 Mips Technologies, Inc
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+#include <asm/mipsmtregs.h>
+#include <asm/r4kcache.h>
+#include <asm/cacheflush.h>
+
+/*
+ * CPU mask used to set process affinity for MT VPEs/TCs with FPUs
+ */
+
+cpumask_t mt_fpu_cpumask;
+
+#ifdef CONFIG_MIPS_MT_FPAFF
+
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+unsigned long mt_fpemul_threshold = 0;
+
+/*
+ * Replacement functions for the sys_sched_setaffinity() and
+ * sys_sched_getaffinity() system calls, so that we can integrate
+ * FPU affinity with the user's requested processor affinity.
+ * This code is 98% identical with the sys_sched_setaffinity()
+ * and sys_sched_getaffinity() system calls, and should be
+ * updated when kernel/sched.c changes.
+ */
+
+/*
+ * find_process_by_pid - find a process with a matching PID value.
+ * used in sys_sched_set/getaffinity() in kernel/sched.c, so
+ * cloned here.
+ */
+static inline task_t *find_process_by_pid(pid_t pid)
+{
+ return pid ? find_task_by_pid(pid) : current;
+}
+
+
+/*
+ * mipsmt_sys_sched_setaffinity - set the cpu affinity of a process
+ */
+asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
+ unsigned long __user *user_mask_ptr)
+{
+ cpumask_t new_mask;
+ cpumask_t effective_mask;
+ int retval;
+ task_t *p;
+
+ if (len < sizeof(new_mask))
+ return -EINVAL;
+
+ if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
+ return -EFAULT;
+
+ lock_cpu_hotplug();
+ read_lock(&tasklist_lock);
+
+ p = find_process_by_pid(pid);
+ if (!p) {
+ read_unlock(&tasklist_lock);
+ unlock_cpu_hotplug();
+ return -ESRCH;
+ }
+
+ /*
+ * It is not safe to call set_cpus_allowed with the
+ * tasklist_lock held. We will bump the task_struct's
+ * usage count and drop tasklist_lock before invoking
+ * set_cpus_allowed.
+ */
+ get_task_struct(p);
+
+ retval = -EPERM;
+ if ((current->euid != p->euid) && (current->euid != p->uid) &&
+ !capable(CAP_SYS_NICE)) {
+ read_unlock(&tasklist_lock);
+ goto out_unlock;
+ }
+
+ /* Record new user-specified CPU set for future reference */
+ p->thread.user_cpus_allowed = new_mask;
+
+ /* Unlock the task list */
+ read_unlock(&tasklist_lock);
+
+ /* Compute new global allowed CPU set if necessary */
+ if( (p->thread.mflags & MF_FPUBOUND)
+ && cpus_intersects(new_mask, mt_fpu_cpumask)) {
+ cpus_and(effective_mask, new_mask, mt_fpu_cpumask);
+ retval = set_cpus_allowed(p, effective_mask);
+ } else {
+ p->thread.mflags &= ~MF_FPUBOUND;
+ retval = set_cpus_allowed(p, new_mask);
+ }
+
+
+out_unlock:
+ put_task_struct(p);
+ unlock_cpu_hotplug();
+ return retval;
+}
+
+/*
+ * mipsmt_sys_sched_getaffinity - get the cpu affinity of a process
+ */
+asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
+ unsigned long __user *user_mask_ptr)
+{
+ unsigned int real_len;
+ cpumask_t mask;
+ int retval;
+ task_t *p;
+
+ real_len = sizeof(mask);
+ if (len < real_len)
+ return -EINVAL;
+
+ lock_cpu_hotplug();
+ read_lock(&tasklist_lock);
+
+ retval = -ESRCH;
+ p = find_process_by_pid(pid);
+ if (!p)
+ goto out_unlock;
+
+ retval = 0;
+
+ cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map);
+
+out_unlock:
+ read_unlock(&tasklist_lock);
+ unlock_cpu_hotplug();
+ if (retval)
+ return retval;
+ if (copy_to_user(user_mask_ptr, &mask, real_len))
+ return -EFAULT;
+ return real_len;
+}
+
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
+/*
+ * Dump new MIPS MT state for the core. Does not leave TCs halted.
+ * Takes an argument which taken to be a pre-call MVPControl value.
+ */
+
+void mips_mt_regdump(unsigned long mvpctl)
+{
+ unsigned long flags;
+ unsigned long vpflags;
+ unsigned long mvpconf0;
+ int nvpe;
+ int ntc;
+ int i;
+ int tc;
+ unsigned long haltval;
+ unsigned long tcstatval;
+#ifdef CONFIG_MIPS_MT_SMTC
+ void smtc_soft_dump(void);
+#endif /* CONFIG_MIPT_MT_SMTC */
+
+ local_irq_save(flags);
+ vpflags = dvpe();
+ printk("=== MIPS MT State Dump ===\n");
+ printk("-- Global State --\n");
+ printk(" MVPControl Passed: %08lx\n", mvpctl);
+ printk(" MVPControl Read: %08lx\n", vpflags);
+ printk(" MVPConf0 : %08lx\n", (mvpconf0 = read_c0_mvpconf0()));
+ nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
+ ntc = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
+ printk("-- per-VPE State --\n");
+ for(i = 0; i < nvpe; i++) {
+ for(tc = 0; tc < ntc; tc++) {
+ settc(tc);
+ if((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) {
+ printk(" VPE %d\n", i);
+ printk(" VPEControl : %08lx\n", read_vpe_c0_vpecontrol());
+ printk(" VPEConf0 : %08lx\n", read_vpe_c0_vpeconf0());
+ printk(" VPE%d.Status : %08lx\n",
+ i, read_vpe_c0_status());
+ printk(" VPE%d.EPC : %08lx\n", i, read_vpe_c0_epc());
+ printk(" VPE%d.Cause : %08lx\n", i, read_vpe_c0_cause());
+ printk(" VPE%d.Config7 : %08lx\n",
+ i, read_vpe_c0_config7());
+ break; /* Next VPE */
+ }
+ }
+ }
+ printk("-- per-TC State --\n");
+ for(tc = 0; tc < ntc; tc++) {
+ settc(tc);
+ if(read_tc_c0_tcbind() == read_c0_tcbind()) {
+ /* Are we dumping ourself? */
+ haltval = 0; /* Then we're not halted, and mustn't be */
+ tcstatval = flags; /* And pre-dump TCStatus is flags */
+ printk(" TC %d (current TC with VPE EPC above)\n", tc);
+ } else {
+ haltval = read_tc_c0_tchalt();
+ write_tc_c0_tchalt(1);
+ tcstatval = read_tc_c0_tcstatus();
+ printk(" TC %d\n", tc);
+ }
+ printk(" TCStatus : %08lx\n", tcstatval);
+ printk(" TCBind : %08lx\n", read_tc_c0_tcbind());
+ printk(" TCRestart : %08lx\n", read_tc_c0_tcrestart());
+ printk(" TCHalt : %08lx\n", haltval);
+ printk(" TCContext : %08lx\n", read_tc_c0_tccontext());
+ if (!haltval)
+ write_tc_c0_tchalt(0);
+ }
+#ifdef CONFIG_MIPS_MT_SMTC
+ smtc_soft_dump();
+#endif /* CONFIG_MIPT_MT_SMTC */
+ printk("===========================\n");
+ evpe(vpflags);
+ local_irq_restore(flags);
+}
+
+static int mt_opt_norps = 0;
+static int mt_opt_rpsctl = -1;
+static int mt_opt_nblsu = -1;
+static int mt_opt_forceconfig7 = 0;
+static int mt_opt_config7 = -1;
+
+static int __init rps_disable(char *s)
+{
+ mt_opt_norps = 1;
+ return 1;
+}
+__setup("norps", rps_disable);
+
+static int __init rpsctl_set(char *str)
+{
+ get_option(&str, &mt_opt_rpsctl);
+ return 1;
+}
+__setup("rpsctl=", rpsctl_set);
+
+static int __init nblsu_set(char *str)
+{
+ get_option(&str, &mt_opt_nblsu);
+ return 1;
+}
+__setup("nblsu=", nblsu_set);
+
+static int __init config7_set(char *str)
+{
+ get_option(&str, &mt_opt_config7);
+ mt_opt_forceconfig7 = 1;
+ return 1;
+}
+__setup("config7=", config7_set);
+
+/* Experimental cache flush control parameters that should go away some day */
+int mt_protiflush = 0;
+int mt_protdflush = 0;
+int mt_n_iflushes = 1;
+int mt_n_dflushes = 1;
+
+static int __init set_protiflush(char *s)
+{
+ mt_protiflush = 1;
+ return 1;
+}
+__setup("protiflush", set_protiflush);
+
+static int __init set_protdflush(char *s)
+{
+ mt_protdflush = 1;
+ return 1;
+}
+__setup("protdflush", set_protdflush);
+
+static int __init niflush(char *s)
+{
+ get_option(&s, &mt_n_iflushes);
+ return 1;
+}
+__setup("niflush=", niflush);
+
+static int __init ndflush(char *s)
+{
+ get_option(&s, &mt_n_dflushes);
+ return 1;
+}
+__setup("ndflush=", ndflush);
+#ifdef CONFIG_MIPS_MT_FPAFF
+static int fpaff_threshold = -1;
+
+static int __init fpaff_thresh(char *str)
+{
+ get_option(&str, &fpaff_threshold);
+ return 1;
+}
+
+__setup("fpaff=", fpaff_thresh);
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
+static unsigned int itc_base = 0;
+
+static int __init set_itc_base(char *str)
+{
+ get_option(&str, &itc_base);
+ return 1;
+}
+
+__setup("itcbase=", set_itc_base);
+
+void mips_mt_set_cpuoptions(void)
+{
+ unsigned int oconfig7 = read_c0_config7();
+ unsigned int nconfig7 = oconfig7;
+
+ if (mt_opt_norps) {
+ printk("\"norps\" option deprectated: use \"rpsctl=\"\n");
+ }
+ if (mt_opt_rpsctl >= 0) {
+ printk("34K return prediction stack override set to %d.\n",
+ mt_opt_rpsctl);
+ if (mt_opt_rpsctl)
+ nconfig7 |= (1 << 2);
+ else
+ nconfig7 &= ~(1 << 2);
+ }
+ if (mt_opt_nblsu >= 0) {
+ printk("34K ALU/LSU sync override set to %d.\n", mt_opt_nblsu);
+ if (mt_opt_nblsu)
+ nconfig7 |= (1 << 5);
+ else
+ nconfig7 &= ~(1 << 5);
+ }
+ if (mt_opt_forceconfig7) {
+ printk("CP0.Config7 forced to 0x%08x.\n", mt_opt_config7);
+ nconfig7 = mt_opt_config7;
+ }
+ if (oconfig7 != nconfig7) {
+ __asm__ __volatile("sync");
+ write_c0_config7(nconfig7);
+ ehb ();
+ printk("Config7: 0x%08x\n", read_c0_config7());
+ }
+
+ /* Report Cache management debug options */
+ if (mt_protiflush)
+ printk("I-cache flushes single-threaded\n");
+ if (mt_protdflush)
+ printk("D-cache flushes single-threaded\n");
+ if (mt_n_iflushes != 1)
+ printk("I-Cache Flushes Repeated %d times\n", mt_n_iflushes);
+ if (mt_n_dflushes != 1)
+ printk("D-Cache Flushes Repeated %d times\n", mt_n_dflushes);
+
+#ifdef CONFIG_MIPS_MT_FPAFF
+ /* FPU Use Factor empirically derived from experiments on 34K */
+#define FPUSEFACTOR 333
+
+ if (fpaff_threshold >= 0) {
+ mt_fpemul_threshold = fpaff_threshold;
+ } else {
+ mt_fpemul_threshold =
+ (FPUSEFACTOR * (loops_per_jiffy/(500000/HZ))) / HZ;
+ }
+ printk("FPU Affinity set after %ld emulations\n",
+ mt_fpemul_threshold);
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
+ if (itc_base != 0) {
+ /*
+ * Configure ITC mapping. This code is very
+ * specific to the 34K core family, which uses
+ * a special mode bit ("ITC") in the ErrCtl
+ * register to enable access to ITC control
+ * registers via cache "tag" operations.
+ */
+ unsigned long ectlval;
+ unsigned long itcblkgrn;
+
+ /* ErrCtl register is known as "ecc" to Linux */
+ ectlval = read_c0_ecc();
+ write_c0_ecc(ectlval | (0x1 << 26));
+ ehb();
+#define INDEX_0 (0x80000000)
+#define INDEX_8 (0x80000008)
+ /* Read "cache tag" for Dcache pseudo-index 8 */
+ cache_op(Index_Load_Tag_D, INDEX_8);
+ ehb();
+ itcblkgrn = read_c0_dtaglo();
+ itcblkgrn &= 0xfffe0000;
+ /* Set for 128 byte pitch of ITC cells */
+ itcblkgrn |= 0x00000c00;
+ /* Stage in Tag register */
+ write_c0_dtaglo(itcblkgrn);
+ ehb();
+ /* Write out to ITU with CACHE op */
+ cache_op(Index_Store_Tag_D, INDEX_8);
+ /* Now set base address, and turn ITC on with 0x1 bit */
+ write_c0_dtaglo((itc_base & 0xfffffc00) | 0x1 );
+ ehb();
+ /* Write out to ITU with CACHE op */
+ cache_op(Index_Store_Tag_D, INDEX_0);
+ write_c0_ecc(ectlval);
+ ehb();
+ printk("Mapped %ld ITC cells starting at 0x%08x\n",
+ ((itcblkgrn & 0x7fe00000) >> 20), itc_base);
+ }
+}
+
+/*
+ * Function to protect cache flushes from concurrent execution
+ * depends on MP software model chosen.
+ */
+
+void mt_cflush_lockdown(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ void smtc_cflush_lockdown(void);
+
+ smtc_cflush_lockdown();
+#endif /* CONFIG_MIPS_MT_SMTC */
+ /* FILL IN VSMP and AP/SP VERSIONS HERE */
+}
+
+void mt_cflush_release(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ void smtc_cflush_release(void);
+
+ smtc_cflush_release();
+#endif /* CONFIG_MIPS_MT_SMTC */
+ /* FILL IN VSMP and AP/SP VERSIONS HERE */
+}
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index e042f9d2ba3..0a71a4c3371 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -28,21 +28,9 @@ extern long __strnlen_user_asm(const char *s);
/*
* String functions
*/
-EXPORT_SYMBOL(memchr);
-EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strchr);
-#ifdef CONFIG_64BIT
-EXPORT_SYMBOL(strncmp);
-#endif
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strncat);
-EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(kernel_thread);
@@ -61,6 +49,3 @@ EXPORT_SYMBOL(__strnlen_user_asm);
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(invalid_pte_table);
-#ifdef CONFIG_GENERIC_IRQ_PROBE
-EXPORT_SYMBOL(probe_irq_mask);
-#endif
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index c66db5e5ab6..199a06e873c 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -41,6 +41,10 @@
#include <asm/elf.h>
#include <asm/isadep.h>
#include <asm/inst.h>
+#ifdef CONFIG_MIPS_MT_SMTC
+#include <asm/mipsmtregs.h>
+extern void smtc_idle_loop_hook(void);
+#endif /* CONFIG_MIPS_MT_SMTC */
/*
* The idle thread. There's no useful work to be done, so just try to conserve
@@ -51,9 +55,13 @@ ATTRIB_NORET void cpu_idle(void)
{
/* endless idle loop with no priority at all */
while (1) {
- while (!need_resched())
+ while (!need_resched()) {
+#ifdef CONFIG_MIPS_MT_SMTC
+ smtc_idle_loop_hook();
+#endif /* CONFIG_MIPS_MT_SMTC */
if (cpu_wait)
(*cpu_wait)();
+ }
preempt_enable_no_resched();
schedule();
preempt_disable();
@@ -177,6 +185,17 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
clear_tsk_thread_flag(p, TIF_USEDFPU);
+#ifdef CONFIG_MIPS_MT_FPAFF
+ /*
+ * FPU affinity support is cleaner if we track the
+ * user-visible CPU affinity from the very beginning.
+ * The generic cpus_allowed mask will already have
+ * been copied from the parent before copy_thread
+ * is invoked.
+ */
+ p->thread.user_cpus_allowed = p->cpus_allowed;
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
if (clone_flags & CLONE_SETTLS)
ti->tp_value = regs->regs[7];
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index f838b36cc76..f3106d0771b 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -248,10 +248,20 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case FPC_EIR: { /* implementation / version register */
unsigned int flags;
+#ifdef CONFIG_MIPS_MT_SMTC
+ unsigned int irqflags;
+ unsigned int mtflags;
+#endif /* CONFIG_MIPS_MT_SMTC */
if (!cpu_has_fpu)
break;
+#ifdef CONFIG_MIPS_MT_SMTC
+ /* Read-modify-write of Status must be atomic */
+ local_irq_save(irqflags);
+ mtflags = dmt();
+#endif /* CONFIG_MIPS_MT_SMTC */
+
preempt_disable();
if (cpu_has_mipsmt) {
unsigned int vpflags = dvpe();
@@ -266,6 +276,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
write_c0_status(flags);
}
+#ifdef CONFIG_MIPS_MT_SMTC
+ emt(mtflags);
+ local_irq_restore(irqflags);
+#endif /* CONFIG_MIPS_MT_SMTC */
preempt_enable();
break;
}
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index 0d5cf97af72..8704dc0496e 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -173,12 +173,22 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
break;
case FPC_EIR: { /* implementation / version register */
unsigned int flags;
+#ifdef CONFIG_MIPS_MT_SMTC
+ unsigned int irqflags;
+ unsigned int mtflags;
+#endif /* CONFIG_MIPS_MT_SMTC */
if (!cpu_has_fpu) {
tmp = 0;
break;
}
+#ifdef CONFIG_MIPS_MT_SMTC
+ /* Read-modify-write of Status must be atomic */
+ local_irq_save(irqflags);
+ mtflags = dmt();
+#endif /* CONFIG_MIPS_MT_SMTC */
+
preempt_disable();
if (cpu_has_mipsmt) {
unsigned int vpflags = dvpe();
@@ -193,6 +203,10 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
write_c0_status(flags);
}
+#ifdef CONFIG_MIPS_MT_SMTC
+ emt(mtflags);
+ local_irq_restore(irqflags);
+#endif /* CONFIG_MIPS_MT_SMTC */
preempt_enable();
break;
}
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index d2afbd19a9c..0b1b54acee9 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -88,7 +88,18 @@
PTR_ADDIU t0, $28, _THREAD_SIZE - 32
set_saved_sp t0, t1, t2
-
+#ifdef CONFIG_MIPS_MT_SMTC
+ /* Read-modify-writes of Status must be atomic on a VPE */
+ mfc0 t2, CP0_TCSTATUS
+ ori t1, t2, TCSTATUS_IXMT
+ mtc0 t1, CP0_TCSTATUS
+ andi t2, t2, TCSTATUS_IXMT
+ ehb
+ DMT 8 # dmt t0
+ move t1,ra
+ jal mips_ihb
+ move ra,t1
+#endif /* CONFIG_MIPS_MT_SMTC */
mfc0 t1, CP0_STATUS /* Do we really need this? */
li a3, 0xff01
and t1, a3
@@ -97,6 +108,18 @@
and a2, a3
or a2, t1
mtc0 a2, CP0_STATUS
+#ifdef CONFIG_MIPS_MT_SMTC
+ ehb
+ andi t0, t0, VPECONTROL_TE
+ beqz t0, 1f
+ emt
+1:
+ mfc0 t1, CP0_TCSTATUS
+ xori t1, t1, TCSTATUS_IXMT
+ or t1, t1, t2
+ mtc0 t1, CP0_TCSTATUS
+ ehb
+#endif /* CONFIG_MIPS_MT_SMTC */
move v0, a0
jr ra
END(resume)
@@ -131,10 +154,19 @@ LEAF(_restore_fp)
#define FPU_DEFAULT 0x00000000
LEAF(_init_fpu)
+#ifdef CONFIG_MIPS_MT_SMTC
+ /* Rather than manipulate per-VPE Status, set per-TC bit in TCStatus */
+ mfc0 t0, CP0_TCSTATUS
+ /* Bit position is the same for Status, TCStatus */
+ li t1, ST0_CU1
+ or t0, t1
+ mtc0 t0, CP0_TCSTATUS
+#else /* Normal MIPS CU1 enable */
mfc0 t0, CP0_STATUS
li t1, ST0_CU1
or t0, t1
mtc0 t0, CP0_STATUS
+#endif /* CONFIG_MIPS_MT_SMTC */
fpu_enable_hazard
li t1, FPU_DEFAULT
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index 986a9cf2306..6179805af9f 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -21,45 +21,44 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/elf.h>
+#include <linux/seq_file.h>
+#include <linux/syscalls.h>
+#include <linux/moduleloader.h>
#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/wait.h>
-
#include <asm/mipsmtregs.h>
-#include <asm/bitops.h>
+#include <asm/cacheflush.h>
+#include <asm/atomic.h>
#include <asm/cpu.h>
#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/vpe.h>
#include <asm/rtlx.h>
-#include <asm/uaccess.h>
#define RTLX_TARG_VPE 1
static struct rtlx_info *rtlx;
static int major;
static char module_name[] = "rtlx";
-static struct irqaction irq;
-static int irq_num;
-
-static inline int spacefree(int read, int write, int size)
-{
- if (read == write) {
- /*
- * never fill the buffer completely, so indexes are always
- * equal if empty and only empty, or !equal if data available
- */
- return size - 1;
- }
-
- return ((read + size - write) % size) - 1;
-}
static struct chan_waitqueues {
wait_queue_head_t rt_queue;
wait_queue_head_t lx_queue;
+ int in_open;
} channel_wqs[RTLX_CHANNELS];
+static struct irqaction irq;
+static int irq_num;
+static struct vpe_notifications notify;
+static int sp_stopping = 0;
+
extern void *vpe_get_shared(int index);
static void rtlx_dispatch(struct pt_regs *regs)
@@ -67,174 +66,298 @@ static void rtlx_dispatch(struct pt_regs *regs)
do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs);
}
+
+/* Interrupt handler may be called before rtlx_init has otherwise had
+ a chance to run.
+*/
static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
int i;
for (i = 0; i < RTLX_CHANNELS; i++) {
- struct rtlx_channel *chan = &rtlx->channel[i];
-
- if (chan->lx_read != chan->lx_write)
- wake_up_interruptible(&channel_wqs[i].lx_queue);
+ wake_up(&channel_wqs[i].lx_queue);
+ wake_up(&channel_wqs[i].rt_queue);
}
return IRQ_HANDLED;
}
-/* call when we have the address of the shared structure from the SP side. */
-static int rtlx_init(struct rtlx_info *rtlxi)
+static __attribute_used__ void dump_rtlx(void)
{
int i;
- if (rtlxi->id != RTLX_ID) {
- printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi);
- return -ENOEXEC;
- }
+ printk("id 0x%lx state %d\n", rtlx->id, rtlx->state);
- /* initialise the wait queues */
for (i = 0; i < RTLX_CHANNELS; i++) {
- init_waitqueue_head(&channel_wqs[i].rt_queue);
- init_waitqueue_head(&channel_wqs[i].lx_queue);
- }
+ struct rtlx_channel *chan = &rtlx->channel[i];
- /* set up for interrupt handling */
- memset(&irq, 0, sizeof(struct irqaction));
+ printk(" rt_state %d lx_state %d buffer_size %d\n",
+ chan->rt_state, chan->lx_state, chan->buffer_size);
- if (cpu_has_vint)
- set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
+ printk(" rt_read %d rt_write %d\n",
+ chan->rt_read, chan->rt_write);
- irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
- irq.handler = rtlx_interrupt;
- irq.flags = SA_INTERRUPT;
- irq.name = "RTLX";
- irq.dev_id = rtlx;
- setup_irq(irq_num, &irq);
+ printk(" lx_read %d lx_write %d\n",
+ chan->lx_read, chan->lx_write);
+
+ printk(" rt_buffer <%s>\n", chan->rt_buffer);
+ printk(" lx_buffer <%s>\n", chan->lx_buffer);
+ }
+}
+
+/* call when we have the address of the shared structure from the SP side. */
+static int rtlx_init(struct rtlx_info *rtlxi)
+{
+ if (rtlxi->id != RTLX_ID) {
+ printk(KERN_ERR "no valid RTLX id at 0x%p 0x%x\n", rtlxi, rtlxi->id);
+ return -ENOEXEC;
+ }
rtlx = rtlxi;
return 0;
}
-/* only allow one open process at a time to open each channel */
-static int rtlx_open(struct inode *inode, struct file *filp)
+/* notifications */
+static void starting(int vpe)
{
- int minor, ret;
+ int i;
+ sp_stopping = 0;
+
+ /* force a reload of rtlx */
+ rtlx=NULL;
+
+ /* wake up any sleeping rtlx_open's */
+ for (i = 0; i < RTLX_CHANNELS; i++)
+ wake_up_interruptible(&channel_wqs[i].lx_queue);
+}
+
+static void stopping(int vpe)
+{
+ int i;
+
+ sp_stopping = 1;
+ for (i = 0; i < RTLX_CHANNELS; i++)
+ wake_up_interruptible(&channel_wqs[i].lx_queue);
+}
+
+
+int rtlx_open(int index, int can_sleep)
+{
+ int ret;
struct rtlx_channel *chan;
+ volatile struct rtlx_info **p;
- /* assume only 1 device at the mo. */
- minor = MINOR(inode->i_rdev);
+ if (index >= RTLX_CHANNELS) {
+ printk(KERN_DEBUG "rtlx_open index out of range\n");
+ return -ENOSYS;
+ }
+
+ if (channel_wqs[index].in_open) {
+ printk(KERN_DEBUG "rtlx_open channel %d already opened\n", index);
+ return -EBUSY;
+ }
+
+ channel_wqs[index].in_open++;
if (rtlx == NULL) {
- struct rtlx_info **p;
if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
- printk(KERN_ERR "vpe_get_shared is NULL. "
- "Has an SP program been loaded?\n");
- return -EFAULT;
+ if (can_sleep) {
+ DECLARE_WAITQUEUE(wait, current);
+
+ /* go to sleep */
+ add_wait_queue(&channel_wqs[index].lx_queue, &wait);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ while ((p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
+
+ /* back running */
+ } else {
+ printk( KERN_DEBUG "No SP program loaded, and device "
+ "opened with O_NONBLOCK\n");
+ channel_wqs[index].in_open = 0;
+ return -ENOSYS;
+ }
}
if (*p == NULL) {
- printk(KERN_ERR "vpe_shared %p %p\n", p, *p);
- return -EFAULT;
+ if (can_sleep) {
+ DECLARE_WAITQUEUE(wait, current);
+
+ /* go to sleep */
+ add_wait_queue(&channel_wqs[index].lx_queue, &wait);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (*p == NULL) {
+ schedule();
+
+ /* reset task state to interruptable otherwise
+ we'll whizz round here like a very fast loopy
+ thing. schedule() appears to return with state
+ set to TASK_RUNNING.
+
+ If the loaded SP program, for whatever reason,
+ doesn't set up the shared structure *p will never
+ become true. So whoever connected to either /dev/rt?
+ or if it was kspd, will then take up rather a lot of
+ processor cycles.
+ */
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
+
+ /* back running */
+ }
+ else {
+ printk(" *vpe_get_shared is NULL. "
+ "Has an SP program been loaded?\n");
+ channel_wqs[index].in_open = 0;
+ return -ENOSYS;
+ }
+ }
+
+ if ((unsigned int)*p < KSEG0) {
+ printk(KERN_WARNING "vpe_get_shared returned an invalid pointer "
+ "maybe an error code %d\n", (int)*p);
+ channel_wqs[index].in_open = 0;
+ return -ENOSYS;
}
- if ((ret = rtlx_init(*p)) < 0)
- return ret;
+ if ((ret = rtlx_init(*p)) < 0) {
+ channel_wqs[index].in_open = 0;
+ return ret;
+ }
}
- chan = &rtlx->channel[minor];
+ chan = &rtlx->channel[index];
- if (test_and_set_bit(RTLX_STATE_OPENED, &chan->lx_state))
- return -EBUSY;
+ if (chan->lx_state == RTLX_STATE_OPENED) {
+ channel_wqs[index].in_open = 0;
+ return -EBUSY;
+ }
+ chan->lx_state = RTLX_STATE_OPENED;
+ channel_wqs[index].in_open = 0;
return 0;
}
-static int rtlx_release(struct inode *inode, struct file *filp)
+int rtlx_release(int index)
{
- int minor = MINOR(inode->i_rdev);
-
- clear_bit(RTLX_STATE_OPENED, &rtlx->channel[minor].lx_state);
- smp_mb__after_clear_bit();
-
+ rtlx->channel[index].lx_state = RTLX_STATE_UNUSED;
return 0;
}
-static unsigned int rtlx_poll(struct file *file, poll_table * wait)
+unsigned int rtlx_read_poll(int index, int can_sleep)
{
- int minor;
- unsigned int mask = 0;
- struct rtlx_channel *chan;
+ struct rtlx_channel *chan;
- minor = MINOR(file->f_dentry->d_inode->i_rdev);
- chan = &rtlx->channel[minor];
+ if (rtlx == NULL)
+ return 0;
- poll_wait(file, &channel_wqs[minor].rt_queue, wait);
- poll_wait(file, &channel_wqs[minor].lx_queue, wait);
+ chan = &rtlx->channel[index];
/* data available to read? */
- if (chan->lx_read != chan->lx_write)
- mask |= POLLIN | POLLRDNORM;
+ if (chan->lx_read == chan->lx_write) {
+ if (can_sleep) {
+ DECLARE_WAITQUEUE(wait, current);
- /* space to write */
- if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size))
- mask |= POLLOUT | POLLWRNORM;
+ /* go to sleep */
+ add_wait_queue(&channel_wqs[index].lx_queue, &wait);
- return mask;
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (chan->lx_read == chan->lx_write) {
+ schedule();
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (sp_stopping) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
+ return 0;
+ }
+ }
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
+
+ /* back running */
+ }
+ else
+ return 0;
+ }
+
+ return (chan->lx_write + chan->buffer_size - chan->lx_read)
+ % chan->buffer_size;
}
-static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count,
- loff_t * ppos)
+static inline int write_spacefree(int read, int write, int size)
{
- unsigned long failed;
- size_t fl = 0L;
- int minor;
- struct rtlx_channel *lx;
- DECLARE_WAITQUEUE(wait, current);
+ if (read == write) {
+ /*
+ * Never fill the buffer completely, so indexes are always
+ * equal if empty and only empty, or !equal if data available
+ */
+ return size - 1;
+ }
- minor = MINOR(file->f_dentry->d_inode->i_rdev);
- lx = &rtlx->channel[minor];
+ return ((read + size - write) % size) - 1;
+}
- /* data available? */
- if (lx->lx_write == lx->lx_read) {
- if (file->f_flags & O_NONBLOCK)
- return 0; /* -EAGAIN makes cat whinge */
+unsigned int rtlx_write_poll(int index)
+{
+ struct rtlx_channel *chan = &rtlx->channel[index];
+ return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size);
+}
- /* go to sleep */
- add_wait_queue(&channel_wqs[minor].lx_queue, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
+static inline void copy_to(void *dst, void *src, size_t count, int user)
+{
+ if (user)
+ copy_to_user(dst, src, count);
+ else
+ memcpy(dst, src, count);
+}
- while (lx->lx_write == lx->lx_read)
- schedule();
+static inline void copy_from(void *dst, void *src, size_t count, int user)
+{
+ if (user)
+ copy_from_user(dst, src, count);
+ else
+ memcpy(dst, src, count);
+}
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&channel_wqs[minor].lx_queue, &wait);
+ssize_t rtlx_read(int index, void *buff, size_t count, int user)
+{
+ size_t fl = 0L;
+ struct rtlx_channel *lx;
- /* back running */
- }
+ if (rtlx == NULL)
+ return -ENOSYS;
+
+ lx = &rtlx->channel[index];
/* find out how much in total */
count = min(count,
- (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size);
+ (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read)
+ % lx->buffer_size);
/* then how much from the read pointer onwards */
- fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
+ fl = min( count, (size_t)lx->buffer_size - lx->lx_read);
- failed = copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl);
- if (failed) {
- count = fl - failed;
- goto out;
- }
+ copy_to(buff, &lx->lx_buffer[lx->lx_read], fl, user);
/* and if there is anything left at the beginning of the buffer */
- if (count - fl) {
- failed = copy_to_user (buffer + fl, lx->lx_buffer, count - fl);
- if (failed) {
- count -= failed;
- goto out;
- }
- }
+ if ( count - fl )
+ copy_to (buff + fl, lx->lx_buffer, count - fl, user);
-out:
/* update the index */
lx->lx_read += count;
lx->lx_read %= lx->buffer_size;
@@ -242,20 +365,101 @@ out:
return count;
}
-static ssize_t rtlx_write(struct file *file, const char __user * buffer,
+ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
+{
+ struct rtlx_channel *rt;
+ size_t fl;
+
+ if (rtlx == NULL)
+ return(-ENOSYS);
+
+ rt = &rtlx->channel[index];
+
+ /* total number of bytes to copy */
+ count = min(count,
+ (size_t)write_spacefree(rt->rt_read, rt->rt_write,
+ rt->buffer_size));
+
+ /* first bit from write pointer to the end of the buffer, or count */
+ fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
+
+ copy_from (&rt->rt_buffer[rt->rt_write], buffer, fl, user);
+
+ /* if there's any left copy to the beginning of the buffer */
+ if( count - fl )
+ copy_from (rt->rt_buffer, buffer + fl, count - fl, user);
+
+ rt->rt_write += count;
+ rt->rt_write %= rt->buffer_size;
+
+ return(count);
+}
+
+
+static int file_open(struct inode *inode, struct file *filp)
+{
+ int minor = MINOR(inode->i_rdev);
+
+ return rtlx_open(minor, (filp->f_flags & O_NONBLOCK) ? 0 : 1);
+}
+
+static int file_release(struct inode *inode, struct file *filp)
+{
+ int minor;
+ minor = MINOR(inode->i_rdev);
+
+ return rtlx_release(minor);
+}
+
+static unsigned int file_poll(struct file *file, poll_table * wait)
+{
+ int minor;
+ unsigned int mask = 0;
+
+ minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ poll_wait(file, &channel_wqs[minor].rt_queue, wait);
+ poll_wait(file, &channel_wqs[minor].lx_queue, wait);
+
+ if (rtlx == NULL)
+ return 0;
+
+ /* data available to read? */
+ if (rtlx_read_poll(minor, 0))
+ mask |= POLLIN | POLLRDNORM;
+
+ /* space to write */
+ if (rtlx_write_poll(minor))
+ mask |= POLLOUT | POLLWRNORM;
+
+ return mask;
+}
+
+static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
+ loff_t * ppos)
+{
+ int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ /* data available? */
+ if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) {
+ return 0; // -EAGAIN makes cat whinge
+ }
+
+ return rtlx_read(minor, buffer, count, 1);
+}
+
+static ssize_t file_write(struct file *file, const char __user * buffer,
size_t count, loff_t * ppos)
{
- unsigned long failed;
int minor;
struct rtlx_channel *rt;
- size_t fl;
DECLARE_WAITQUEUE(wait, current);
minor = MINOR(file->f_dentry->d_inode->i_rdev);
rt = &rtlx->channel[minor];
/* any space left... */
- if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) {
+ if (!rtlx_write_poll(minor)) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
@@ -263,61 +467,64 @@ static ssize_t rtlx_write(struct file *file, const char __user * buffer,
add_wait_queue(&channel_wqs[minor].rt_queue, &wait);
set_current_state(TASK_INTERRUPTIBLE);
- while (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size))
+ while (!rtlx_write_poll(minor))
schedule();
set_current_state(TASK_RUNNING);
remove_wait_queue(&channel_wqs[minor].rt_queue, &wait);
}
- /* total number of bytes to copy */
- count = min(count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) );
-
- /* first bit from write pointer to the end of the buffer, or count */
- fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
-
- failed = copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl);
- if (failed) {
- count = fl - failed;
- goto out;
- }
-
- /* if there's any left copy to the beginning of the buffer */
- if (count - fl) {
- failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
- if (failed) {
- count -= failed;
- goto out;
- }
- }
-
-out:
- rt->rt_write += count;
- rt->rt_write %= rt->buffer_size;
-
- return count;
+ return rtlx_write(minor, (void *)buffer, count, 1);
}
static struct file_operations rtlx_fops = {
- .owner = THIS_MODULE,
- .open = rtlx_open,
- .release = rtlx_release,
- .write = rtlx_write,
- .read = rtlx_read,
- .poll = rtlx_poll
+ .owner = THIS_MODULE,
+ .open = file_open,
+ .release = file_release,
+ .write = file_write,
+ .read = file_read,
+ .poll = file_poll
};
+static struct irqaction rtlx_irq = {
+ .handler = rtlx_interrupt,
+ .flags = SA_INTERRUPT,
+ .name = "RTLX",
+};
+
+static int rtlx_irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
+
static char register_chrdev_failed[] __initdata =
KERN_ERR "rtlx_module_init: unable to register device\n";
-static int __init rtlx_module_init(void)
+static int rtlx_module_init(void)
{
+ int i;
+
major = register_chrdev(0, module_name, &rtlx_fops);
if (major < 0) {
printk(register_chrdev_failed);
return major;
}
+ /* initialise the wait queues */
+ for (i = 0; i < RTLX_CHANNELS; i++) {
+ init_waitqueue_head(&channel_wqs[i].rt_queue);
+ init_waitqueue_head(&channel_wqs[i].lx_queue);
+ channel_wqs[i].in_open = 0;
+ }
+
+ /* set up notifiers */
+ notify.start = starting;
+ notify.stop = stopping;
+ vpe_notify(RTLX_TARG_VPE, &notify);
+
+ if (cpu_has_vint)
+ set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
+
+ rtlx_irq.dev_id = rtlx;
+ setup_irq(rtlx_irq_num, &rtlx_irq);
+
return 0;
}
@@ -330,5 +537,5 @@ module_init(rtlx_module_init);
module_exit(rtlx_module_exit);
MODULE_DESCRIPTION("MIPS RTLX");
-MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc.");
+MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
MODULE_LICENSE("GPL");
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 2f2dc54b2e2..a0ac0e5f61a 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -569,8 +569,19 @@ einval: li v0, -EINVAL
sys sys_tkill 2
sys sys_sendfile64 5
sys sys_futex 6
+#ifdef CONFIG_MIPS_MT_FPAFF
+ /*
+ * For FPU affinity scheduling on MIPS MT processors, we need to
+ * intercept sys_sched_xxxaffinity() calls until we get a proper hook
+ * in kernel/sched.c. Considered only temporary we only support these
+ * hooks for the 32-bit kernel - there is no MIPS64 MT processor atm.
+ */
+ sys mipsmt_sys_sched_setaffinity 3
+ sys mipsmt_sys_sched_getaffinity 3
+#else
sys sys_sched_setaffinity 3
sys sys_sched_getaffinity 3 /* 4240 */
+#endif /* CONFIG_MIPS_MT_FPAFF */
sys sys_io_setup 2
sys sys_io_destroy 1
sys sys_io_getevents 5
@@ -634,6 +645,8 @@ einval: li v0, -EINVAL
sys sys_pselect6 6
sys sys_ppoll 5
sys sys_unshare 1
+ sys sys_splice 4
+ sys sys_sync_file_range 7 /* 4305 */
.endm
/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 98bf25df56f..9ba75088737 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -460,3 +460,5 @@ sys_call_table:
PTR sys_pselect6 /* 5260 */
PTR sys_ppoll
PTR sys_unshare
+ PTR sys_splice
+ PTR sys_sync_file_range
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 05a2c0567da..942aca26f9c 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -386,3 +386,5 @@ EXPORT(sysn32_call_table)
PTR sys_pselect6
PTR sys_ppoll /* 6265 */
PTR sys_unshare
+ PTR sys_splice
+ PTR sys_sync_file_range
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 19c4ca481b0..b53a9207f53 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -508,4 +508,6 @@ sys_call_table:
PTR sys_pselect6
PTR sys_ppoll
PTR sys_unshare
+ PTR sys_splice
+ PTR sys32_sync_file_range /* 4305 */
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index dcbfd27071f..bcf1b10e518 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -529,7 +529,10 @@ void __init setup_arch(char **cmdline_p)
int __init fpu_disable(char *s)
{
- cpu_data[0].options &= ~MIPS_CPU_FPU;
+ int i;
+
+ for (i = 0; i < NR_CPUS; i++)
+ cpu_data[i].options &= ~MIPS_CPU_FPU;
return 1;
}
diff --git a/arch/mips/kernel/smp_mt.c b/arch/mips/kernel/smp-mt.c
index 993b8bf56aa..57770902b9a 100644
--- a/arch/mips/kernel/smp_mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -1,8 +1,4 @@
/*
- * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved.
- *
- * Elizabeth Clarke (beth@mips.com)
- *
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
@@ -16,6 +12,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
+ * Copyright (C) 2004, 05, 06 MIPS Technologies, Inc.
+ * Elizabeth Clarke (beth@mips.com)
+ * Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
*/
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -24,6 +24,7 @@
#include <linux/compiler.h>
#include <asm/atomic.h>
+#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -33,8 +34,8 @@
#include <asm/time.h>
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
-#include <asm/cacheflush.h>
-#include <asm/mips-boards/maltaint.h>
+#include <asm/mips_mt.h>
+#include <asm/mips-boards/maltaint.h> /* This is f*cking wrong */
#define MIPS_CPU_IPI_RESCHED_IRQ 0
#define MIPS_CPU_IPI_CALL_IRQ 1
@@ -66,6 +67,7 @@ void __init sanitize_tlb_entries(void)
if (!cpu_has_mipsmt)
return;
+ /* Enable VPC */
set_c0_mvpcontrol(MVPCONTROL_VPC);
back_to_back_c0_hazard();
@@ -106,12 +108,12 @@ void __init sanitize_tlb_entries(void)
static void ipi_resched_dispatch (struct pt_regs *regs)
{
- do_IRQ(MIPS_CPU_IPI_RESCHED_IRQ, regs);
+ do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ, regs);
}
static void ipi_call_dispatch (struct pt_regs *regs)
{
- do_IRQ(MIPS_CPU_IPI_CALL_IRQ, regs);
+ do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ, regs);
}
irqreturn_t ipi_resched_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -148,6 +150,11 @@ void plat_smp_setup(void)
unsigned long val;
int i, num;
+#ifdef CONFIG_MIPS_MT_FPAFF
+ /* If we have an FPU, enroll ourselves in the FPU-full mask */
+ if (cpu_has_fpu)
+ cpu_set(0, mt_fpu_cpumask);
+#endif /* CONFIG_MIPS_MT_FPAFF */
if (!cpu_has_mipsmt)
return;
@@ -155,6 +162,8 @@ void plat_smp_setup(void)
dvpe();
dmt();
+ mips_mt_set_cpuoptions();
+
/* Put MVPE's into 'configuration state' */
set_c0_mvpcontrol(MVPCONTROL_VPC);
@@ -189,11 +198,13 @@ void plat_smp_setup(void)
if (i != 0) {
write_vpe_c0_status((read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
- write_vpe_c0_cause(read_vpe_c0_cause() & ~CAUSEF_IP);
/* set config to be the same as vpe0, particularly kseg0 coherency alg */
write_vpe_c0_config( read_c0_config());
+ /* make sure there are no software interrupts pending */
+ write_vpe_c0_cause(read_vpe_c0_cause() & ~(C_SW1|C_SW0));
+
/* Propagate Config7 */
write_vpe_c0_config7(read_c0_config7());
}
@@ -233,16 +244,16 @@ void plat_smp_setup(void)
/* We'll wait until starting the secondaries before starting MVPE */
printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
+}
+void __init plat_prepare_cpus(unsigned int max_cpus)
+{
/* set up ipi interrupts */
if (cpu_has_vint) {
set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
}
-}
-void __init plat_prepare_cpus(unsigned int max_cpus)
-{
cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ;
@@ -287,7 +298,8 @@ void prom_boot_secondary(int cpu, struct task_struct *idle)
/* global pointer */
write_tc_gpr_gp((unsigned long)gp);
- flush_icache_range((unsigned long)gp, (unsigned long)(gp + 1));
+ flush_icache_range((unsigned long)gp,
+ (unsigned long)(gp + sizeof(struct thread_info)));
/* finally out of configuration and into chaos */
clear_c0_mvpcontrol(MVPCONTROL_VPC);
@@ -305,6 +317,12 @@ void prom_smp_finish(void)
{
write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
+#ifdef CONFIG_MIPS_MT_FPAFF
+ /* If we have an FPU, enroll ourselves in the FPU-full mask */
+ if (cpu_has_fpu)
+ cpu_set(smp_processor_id(), mt_fpu_cpumask);
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
local_irq_enable();
}
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 78d171bfa33..d42f358754a 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -38,6 +38,10 @@
#include <asm/mmu_context.h>
#include <asm/smp.h>
+#ifdef CONFIG_MIPS_MT_SMTC
+#include <asm/mipsmtregs.h>
+#endif /* CONFIG_MIPS_MT_SMTC */
+
cpumask_t phys_cpu_present_map; /* Bitmask of available CPUs */
volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */
cpumask_t cpu_online_map; /* Bitmask of currently online CPUs */
@@ -85,6 +89,10 @@ asmlinkage void start_secondary(void)
{
unsigned int cpu;
+#ifdef CONFIG_MIPS_MT_SMTC
+ /* Only do cpu_probe for first TC of CPU */
+ if ((read_c0_tcbind() & TCBIND_CURTC) == 0)
+#endif /* CONFIG_MIPS_MT_SMTC */
cpu_probe();
cpu_report();
per_cpu_trap_init();
@@ -179,11 +187,13 @@ int smp_call_function (void (*func) (void *info), void *info, int retry,
if (wait)
while (atomic_read(&data.finished) != cpus)
barrier();
+ call_data = NULL;
spin_unlock(&smp_call_lock);
return 0;
}
+
void smp_call_function_interrupt(void)
{
void (*func) (void *info) = call_data->func;
@@ -446,5 +456,3 @@ subsys_initcall(topology_init);
EXPORT_SYMBOL(flush_tlb_page);
EXPORT_SYMBOL(flush_tlb_one);
-EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(synchronize_irq);
diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S
new file mode 100644
index 00000000000..c9d65196d91
--- /dev/null
+++ b/arch/mips/kernel/smtc-asm.S
@@ -0,0 +1,130 @@
+/*
+ * Assembly Language Functions for MIPS MT SMTC support
+ */
+
+/*
+ * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. */
+
+#include <asm/regdef.h>
+#include <asm/asmmacro.h>
+#include <asm/stackframe.h>
+#include <asm/stackframe.h>
+
+/*
+ * "Software Interrupt" linkage.
+ *
+ * This is invoked when an "Interrupt" is sent from one TC to another,
+ * where the TC to be interrupted is halted, has it's Restart address
+ * and Status values saved by the "remote control" thread, then modified
+ * to cause execution to begin here, in kenel mode. This code then
+ * disguises the TC state as that of an exception and transfers
+ * control to the general exception or vectored interrupt handler.
+ */
+ .set noreorder
+
+/*
+The __smtc_ipi_vector would use k0 and k1 as temporaries and
+1) Set EXL (this is per-VPE, so this can't be done by proxy!)
+2) Restore the K/CU and IXMT bits to the pre "exception" state
+ (EXL means no interrupts and access to the kernel map).
+3) Set EPC to be the saved value of TCRestart.
+4) Jump to the exception handler entry point passed by the sender.
+
+CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED??
+*/
+
+/*
+ * Reviled and slandered vision: Set EXL and restore K/CU/IXMT
+ * state of pre-halt thread, then save everything and call
+ * thought some function pointer to imaginary_exception, which
+ * will parse a register value or memory message queue to
+ * deliver things like interprocessor interrupts. On return
+ * from that function, jump to the global ret_from_irq code
+ * to invoke the scheduler and return as appropriate.
+ */
+
+#define PT_PADSLOT4 (PT_R0-8)
+#define PT_PADSLOT5 (PT_R0-4)
+
+ .text
+ .align 5
+FEXPORT(__smtc_ipi_vector)
+ .set noat
+ /* Disable thread scheduling to make Status update atomic */
+ DMT 27 # dmt k1
+ ehb
+ /* Set EXL */
+ mfc0 k0,CP0_STATUS
+ ori k0,k0,ST0_EXL
+ mtc0 k0,CP0_STATUS
+ ehb
+ /* Thread scheduling now inhibited by EXL. Restore TE state. */
+ andi k1,k1,VPECONTROL_TE
+ beqz k1,1f
+ emt
+1:
+ /*
+ * The IPI sender has put some information on the anticipated
+ * kernel stack frame. If we were in user mode, this will be
+ * built above the saved kernel SP. If we were already in the
+ * kernel, it will be built above the current CPU SP.
+ *
+ * Were we in kernel mode, as indicated by CU0?
+ */
+ sll k1,k0,3
+ .set noreorder
+ bltz k1,2f
+ move k1,sp
+ .set reorder
+ /*
+ * If previously in user mode, set CU0 and use kernel stack.
+ */
+ li k1,ST0_CU0
+ or k1,k1,k0
+ mtc0 k1,CP0_STATUS
+ ehb
+ get_saved_sp
+ /* Interrupting TC will have pre-set values in slots in the new frame */
+2: subu k1,k1,PT_SIZE
+ /* Load TCStatus Value */
+ lw k0,PT_TCSTATUS(k1)
+ /* Write it to TCStatus to restore CU/KSU/IXMT state */
+ mtc0 k0,$2,1
+ ehb
+ lw k0,PT_EPC(k1)
+ mtc0 k0,CP0_EPC
+ /* Save all will redundantly recompute the SP, but use it for now */
+ SAVE_ALL
+ CLI
+ move a0,sp
+ /* Function to be invoked passed stack pad slot 5 */
+ lw t0,PT_PADSLOT5(sp)
+ /* Argument from sender passed in stack pad slot 4 */
+ lw a1,PT_PADSLOT4(sp)
+ jalr t0
+ nop
+ j ret_from_irq
+ nop
+
+/*
+ * Called from idle loop to provoke processing of queued IPIs
+ * First IPI message in queue passed as argument.
+ */
+
+LEAF(self_ipi)
+ /* Before anything else, block interrupts */
+ mfc0 t0,CP0_TCSTATUS
+ ori t1,t0,TCSTATUS_IXMT
+ mtc0 t1,CP0_TCSTATUS
+ ehb
+ /* We know we're in kernel mode, so prepare stack frame */
+ subu t1,sp,PT_SIZE
+ sw ra,PT_EPC(t1)
+ sw a0,PT_PADSLOT4(t1)
+ la t2,ipi_decode
+ sw t2,PT_PADSLOT5(t1)
+ /* Save pre-disable value of TCStatus */
+ sw t0,PT_TCSTATUS(t1)
+ j __smtc_ipi_vector
+ nop
+END(self_ipi)
diff --git a/arch/mips/kernel/smtc-proc.c b/arch/mips/kernel/smtc-proc.c
new file mode 100644
index 00000000000..6f370999617
--- /dev/null
+++ b/arch/mips/kernel/smtc-proc.c
@@ -0,0 +1,93 @@
+/*
+ * /proc hooks for SMTC kernel
+ * Copyright (C) 2005 Mips Technologies, Inc
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+#include <asm/mipsregs.h>
+#include <asm/cacheflush.h>
+#include <linux/proc_fs.h>
+
+#include <asm/smtc_proc.h>
+
+/*
+ * /proc diagnostic and statistics hooks
+ */
+
+/*
+ * Statistics gathered
+ */
+unsigned long selfipis[NR_CPUS];
+
+struct smtc_cpu_proc smtc_cpu_stats[NR_CPUS];
+
+static struct proc_dir_entry *smtc_stats;
+
+atomic_t smtc_fpu_recoveries;
+
+static int proc_read_smtc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int totalen = 0;
+ int len;
+ int i;
+ extern unsigned long ebase;
+
+ len = sprintf(page, "SMTC Status Word: 0x%08x\n", smtc_status);
+ totalen += len;
+ page += len;
+ len = sprintf(page, "Config7: 0x%08x\n", read_c0_config7());
+ totalen += len;
+ page += len;
+ len = sprintf(page, "EBASE: 0x%08lx\n", ebase);
+ totalen += len;
+ page += len;
+ len = sprintf(page, "Counter Interrupts taken per CPU (TC)\n");
+ totalen += len;
+ page += len;
+ for (i=0; i < NR_CPUS; i++) {
+ len = sprintf(page, "%d: %ld\n", i, smtc_cpu_stats[i].timerints);
+ totalen += len;
+ page += len;
+ }
+ len = sprintf(page, "Self-IPIs by CPU:\n");
+ totalen += len;
+ page += len;
+ for(i = 0; i < NR_CPUS; i++) {
+ len = sprintf(page, "%d: %ld\n", i, smtc_cpu_stats[i].selfipis);
+ totalen += len;
+ page += len;
+ }
+ len = sprintf(page, "%d Recoveries of \"stolen\" FPU\n",
+ atomic_read(&smtc_fpu_recoveries));
+ totalen += len;
+ page += len;
+
+ return totalen;
+}
+
+void init_smtc_stats(void)
+{
+ int i;
+
+ for (i=0; i<NR_CPUS; i++) {
+ smtc_cpu_stats[i].timerints = 0;
+ smtc_cpu_stats[i].selfipis = 0;
+ }
+
+ atomic_set(&smtc_fpu_recoveries, 0);
+
+ smtc_stats = create_proc_read_entry("smtc", 0444, NULL,
+ proc_read_smtc, NULL);
+}
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
new file mode 100644
index 00000000000..2e8e52c135e
--- /dev/null
+++ b/arch/mips/kernel/smtc.c
@@ -0,0 +1,1322 @@
+/* Copyright (C) 2004 Mips Technologies, Inc */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/hardirq.h>
+#include <asm/hazards.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+#include <asm/mipsregs.h>
+#include <asm/cacheflush.h>
+#include <asm/time.h>
+#include <asm/addrspace.h>
+#include <asm/smtc.h>
+#include <asm/smtc_ipi.h>
+#include <asm/smtc_proc.h>
+
+/*
+ * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set.
+ */
+
+/*
+ * MIPSCPU_INT_BASE is identically defined in both
+ * asm-mips/mips-boards/maltaint.h and asm-mips/mips-boards/simint.h,
+ * but as yet there's no properly organized include structure that
+ * will ensure that the right *int.h file will be included for a
+ * given platform build.
+ */
+
+#define MIPSCPU_INT_BASE 16
+
+#define MIPS_CPU_IPI_IRQ 1
+
+#define LOCK_MT_PRA() \
+ local_irq_save(flags); \
+ mtflags = dmt()
+
+#define UNLOCK_MT_PRA() \
+ emt(mtflags); \
+ local_irq_restore(flags)
+
+#define LOCK_CORE_PRA() \
+ local_irq_save(flags); \
+ mtflags = dvpe()
+
+#define UNLOCK_CORE_PRA() \
+ evpe(mtflags); \
+ local_irq_restore(flags)
+
+/*
+ * Data structures purely associated with SMTC parallelism
+ */
+
+
+/*
+ * Table for tracking ASIDs whose lifetime is prolonged.
+ */
+
+asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];
+
+/*
+ * Clock interrupt "latch" buffers, per "CPU"
+ */
+
+unsigned int ipi_timer_latch[NR_CPUS];
+
+/*
+ * Number of InterProcessor Interupt (IPI) message buffers to allocate
+ */
+
+#define IPIBUF_PER_CPU 4
+
+struct smtc_ipi_q IPIQ[NR_CPUS];
+struct smtc_ipi_q freeIPIq;
+
+
+/* Forward declarations */
+
+void ipi_decode(struct pt_regs *, struct smtc_ipi *);
+void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
+void setup_cross_vpe_interrupts(void);
+void init_smtc_stats(void);
+
+/* Global SMTC Status */
+
+unsigned int smtc_status = 0;
+
+/* Boot command line configuration overrides */
+
+static int vpelimit = 0;
+static int tclimit = 0;
+static int ipibuffers = 0;
+static int nostlb = 0;
+static int asidmask = 0;
+unsigned long smtc_asid_mask = 0xff;
+
+static int __init maxvpes(char *str)
+{
+ get_option(&str, &vpelimit);
+ return 1;
+}
+
+static int __init maxtcs(char *str)
+{
+ get_option(&str, &tclimit);
+ return 1;
+}
+
+static int __init ipibufs(char *str)
+{
+ get_option(&str, &ipibuffers);
+ return 1;
+}
+
+static int __init stlb_disable(char *s)
+{
+ nostlb = 1;
+ return 1;
+}
+
+static int __init asidmask_set(char *str)
+{
+ get_option(&str, &asidmask);
+ switch(asidmask) {
+ case 0x1:
+ case 0x3:
+ case 0x7:
+ case 0xf:
+ case 0x1f:
+ case 0x3f:
+ case 0x7f:
+ case 0xff:
+ smtc_asid_mask = (unsigned long)asidmask;
+ break;
+ default:
+ printk("ILLEGAL ASID mask 0x%x from command line\n", asidmask);
+ }
+ return 1;
+}
+
+__setup("maxvpes=", maxvpes);
+__setup("maxtcs=", maxtcs);
+__setup("ipibufs=", ipibufs);
+__setup("nostlb", stlb_disable);
+__setup("asidmask=", asidmask_set);
+
+/* Enable additional debug checks before going into CPU idle loop */
+#define SMTC_IDLE_HOOK_DEBUG
+
+#ifdef SMTC_IDLE_HOOK_DEBUG
+
+static int hang_trig = 0;
+
+static int __init hangtrig_enable(char *s)
+{
+ hang_trig = 1;
+ return 1;
+}
+
+
+__setup("hangtrig", hangtrig_enable);
+
+#define DEFAULT_BLOCKED_IPI_LIMIT 32
+
+static int timerq_limit = DEFAULT_BLOCKED_IPI_LIMIT;
+
+static int __init tintq(char *str)
+{
+ get_option(&str, &timerq_limit);
+ return 1;
+}
+
+__setup("tintq=", tintq);
+
+int imstuckcount[2][8];
+/* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */
+int vpemask[2][8] = {{0,1,1,0,0,0,0,1},{0,1,0,0,0,0,0,1}};
+int tcnoprog[NR_CPUS];
+static atomic_t idle_hook_initialized = {0};
+static int clock_hang_reported[NR_CPUS];
+
+#endif /* SMTC_IDLE_HOOK_DEBUG */
+
+/* Initialize shared TLB - the should probably migrate to smtc_setup_cpus() */
+
+void __init sanitize_tlb_entries(void)
+{
+ printk("Deprecated sanitize_tlb_entries() invoked\n");
+}
+
+
+/*
+ * Configure shared TLB - VPC configuration bit must be set by caller
+ */
+
+void smtc_configure_tlb(void)
+{
+ int i,tlbsiz,vpes;
+ unsigned long mvpconf0;
+ unsigned long config1val;
+
+ /* Set up ASID preservation table */
+ for (vpes=0; vpes<MAX_SMTC_TLBS; vpes++) {
+ for(i = 0; i < MAX_SMTC_ASIDS; i++) {
+ smtc_live_asid[vpes][i] = 0;
+ }
+ }
+ mvpconf0 = read_c0_mvpconf0();
+
+ if ((vpes = ((mvpconf0 & MVPCONF0_PVPE)
+ >> MVPCONF0_PVPE_SHIFT) + 1) > 1) {
+ /* If we have multiple VPEs, try to share the TLB */
+ if ((mvpconf0 & MVPCONF0_TLBS) && !nostlb) {
+ /*
+ * If TLB sizing is programmable, shared TLB
+ * size is the total available complement.
+ * Otherwise, we have to take the sum of all
+ * static VPE TLB entries.
+ */
+ if ((tlbsiz = ((mvpconf0 & MVPCONF0_PTLBE)
+ >> MVPCONF0_PTLBE_SHIFT)) == 0) {
+ /*
+ * If there's more than one VPE, there had better
+ * be more than one TC, because we need one to bind
+ * to each VPE in turn to be able to read
+ * its configuration state!
+ */
+ settc(1);
+ /* Stop the TC from doing anything foolish */
+ write_tc_c0_tchalt(TCHALT_H);
+ mips_ihb();
+ /* No need to un-Halt - that happens later anyway */
+ for (i=0; i < vpes; i++) {
+ write_tc_c0_tcbind(i);
+ /*
+ * To be 100% sure we're really getting the right
+ * information, we exit the configuration state
+ * and do an IHB after each rebinding.
+ */
+ write_c0_mvpcontrol(
+ read_c0_mvpcontrol() & ~ MVPCONTROL_VPC );
+ mips_ihb();
+ /*
+ * Only count if the MMU Type indicated is TLB
+ */
+ if(((read_vpe_c0_config() & MIPS_CONF_MT) >> 7) == 1) {
+ config1val = read_vpe_c0_config1();
+ tlbsiz += ((config1val >> 25) & 0x3f) + 1;
+ }
+
+ /* Put core back in configuration state */
+ write_c0_mvpcontrol(
+ read_c0_mvpcontrol() | MVPCONTROL_VPC );
+ mips_ihb();
+ }
+ }
+ write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB);
+
+ /*
+ * Setup kernel data structures to use software total,
+ * rather than read the per-VPE Config1 value. The values
+ * for "CPU 0" gets copied to all the other CPUs as part
+ * of their initialization in smtc_cpu_setup().
+ */
+
+ tlbsiz = tlbsiz & 0x3f; /* MIPS32 limits TLB indices to 64 */
+ cpu_data[0].tlbsize = tlbsiz;
+ smtc_status |= SMTC_TLB_SHARED;
+
+ printk("TLB of %d entry pairs shared by %d VPEs\n",
+ tlbsiz, vpes);
+ } else {
+ printk("WARNING: TLB Not Sharable on SMTC Boot!\n");
+ }
+ }
+}
+
+
+/*
+ * Incrementally build the CPU map out of constituent MIPS MT cores,
+ * using the specified available VPEs and TCs. Plaform code needs
+ * to ensure that each MIPS MT core invokes this routine on reset,
+ * one at a time(!).
+ *
+ * This version of the build_cpu_map and prepare_cpus routines assumes
+ * that *all* TCs of a MIPS MT core will be used for Linux, and that
+ * they will be spread across *all* available VPEs (to minimise the
+ * loss of efficiency due to exception service serialization).
+ * An improved version would pick up configuration information and
+ * possibly leave some TCs/VPEs as "slave" processors.
+ *
+ * Use c0_MVPConf0 to find out how many TCs are available, setting up
+ * phys_cpu_present_map and the logical/physical mappings.
+ */
+
+int __init mipsmt_build_cpu_map(int start_cpu_slot)
+{
+ int i, ntcs;
+
+ /*
+ * The CPU map isn't actually used for anything at this point,
+ * so it's not clear what else we should do apart from set
+ * everything up so that "logical" = "physical".
+ */
+ ntcs = ((read_c0_mvpconf0() & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
+ for (i=start_cpu_slot; i<NR_CPUS && i<ntcs; i++) {
+ cpu_set(i, phys_cpu_present_map);
+ __cpu_number_map[i] = i;
+ __cpu_logical_map[i] = i;
+ }
+ /* Initialize map of CPUs with FPUs */
+ cpus_clear(mt_fpu_cpumask);
+
+ /* One of those TC's is the one booting, and not a secondary... */
+ printk("%i available secondary CPU TC(s)\n", i - 1);
+
+ return i;
+}
+
+/*
+ * Common setup before any secondaries are started
+ * Make sure all CPU's are in a sensible state before we boot any of the
+ * secondaries.
+ *
+ * For MIPS MT "SMTC" operation, we set up all TCs, spread as evenly
+ * as possible across the available VPEs.
+ */
+
+static void smtc_tc_setup(int vpe, int tc, int cpu)
+{
+ settc(tc);
+ write_tc_c0_tchalt(TCHALT_H);
+ mips_ihb();
+ write_tc_c0_tcstatus((read_tc_c0_tcstatus()
+ & ~(TCSTATUS_TKSU | TCSTATUS_DA | TCSTATUS_IXMT))
+ | TCSTATUS_A);
+ write_tc_c0_tccontext(0);
+ /* Bind tc to vpe */
+ write_tc_c0_tcbind(vpe);
+ /* In general, all TCs should have the same cpu_data indications */
+ memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips));
+ /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */
+ if (cpu_data[0].cputype == CPU_34K)
+ cpu_data[cpu].options &= ~MIPS_CPU_FPU;
+ cpu_data[cpu].vpe_id = vpe;
+ cpu_data[cpu].tc_id = tc;
+}
+
+
+void mipsmt_prepare_cpus(void)
+{
+ int i, vpe, tc, ntc, nvpe, tcpervpe, slop, cpu;
+ unsigned long flags;
+ unsigned long val;
+ int nipi;
+ struct smtc_ipi *pipi;
+
+ /* disable interrupts so we can disable MT */
+ local_irq_save(flags);
+ /* disable MT so we can configure */
+ dvpe();
+ dmt();
+
+ freeIPIq.lock = SPIN_LOCK_UNLOCKED;
+
+ /*
+ * We probably don't have as many VPEs as we do SMP "CPUs",
+ * but it's possible - and in any case we'll never use more!
+ */
+ for (i=0; i<NR_CPUS; i++) {
+ IPIQ[i].head = IPIQ[i].tail = NULL;
+ IPIQ[i].lock = SPIN_LOCK_UNLOCKED;
+ IPIQ[i].depth = 0;
+ ipi_timer_latch[i] = 0;
+ }
+
+ /* cpu_data index starts at zero */
+ cpu = 0;
+ cpu_data[cpu].vpe_id = 0;
+ cpu_data[cpu].tc_id = 0;
+ cpu++;
+
+ /* Report on boot-time options */
+ mips_mt_set_cpuoptions ();
+ if (vpelimit > 0)
+ printk("Limit of %d VPEs set\n", vpelimit);
+ if (tclimit > 0)
+ printk("Limit of %d TCs set\n", tclimit);
+ if (nostlb) {
+ printk("Shared TLB Use Inhibited - UNSAFE for Multi-VPE Operation\n");
+ }
+ if (asidmask)
+ printk("ASID mask value override to 0x%x\n", asidmask);
+
+ /* Temporary */
+#ifdef SMTC_IDLE_HOOK_DEBUG
+ if (hang_trig)
+ printk("Logic Analyser Trigger on suspected TC hang\n");
+#endif /* SMTC_IDLE_HOOK_DEBUG */
+
+ /* Put MVPE's into 'configuration state' */
+ write_c0_mvpcontrol( read_c0_mvpcontrol() | MVPCONTROL_VPC );
+
+ val = read_c0_mvpconf0();
+ nvpe = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
+ if (vpelimit > 0 && nvpe > vpelimit)
+ nvpe = vpelimit;
+ ntc = ((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
+ if (ntc > NR_CPUS)
+ ntc = NR_CPUS;
+ if (tclimit > 0 && ntc > tclimit)
+ ntc = tclimit;
+ tcpervpe = ntc / nvpe;
+ slop = ntc % nvpe; /* Residual TCs, < NVPE */
+
+ /* Set up shared TLB */
+ smtc_configure_tlb();
+
+ for (tc = 0, vpe = 0 ; (vpe < nvpe) && (tc < ntc) ; vpe++) {
+ /*
+ * Set the MVP bits.
+ */
+ settc(tc);
+ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_MVP);
+ if (vpe != 0)
+ printk(", ");
+ printk("VPE %d: TC", vpe);
+ for (i = 0; i < tcpervpe; i++) {
+ /*
+ * TC 0 is bound to VPE 0 at reset,
+ * and is presumably executing this
+ * code. Leave it alone!
+ */
+ if (tc != 0) {
+ smtc_tc_setup(vpe,tc, cpu);
+ cpu++;
+ }
+ printk(" %d", tc);
+ tc++;
+ }
+ if (slop) {
+ if (tc != 0) {
+ smtc_tc_setup(vpe,tc, cpu);
+ cpu++;
+ }
+ printk(" %d", tc);
+ tc++;
+ slop--;
+ }
+ if (vpe != 0) {
+ /*
+ * Clear any stale software interrupts from VPE's Cause
+ */
+ write_vpe_c0_cause(0);
+
+ /*
+ * Clear ERL/EXL of VPEs other than 0
+ * and set restricted interrupt enable/mask.
+ */
+ write_vpe_c0_status((read_vpe_c0_status()
+ & ~(ST0_BEV | ST0_ERL | ST0_EXL | ST0_IM))
+ | (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP7
+ | ST0_IE));
+ /*
+ * set config to be the same as vpe0,
+ * particularly kseg0 coherency alg
+ */
+ write_vpe_c0_config(read_c0_config());
+ /* Clear any pending timer interrupt */
+ write_vpe_c0_compare(0);
+ /* Propagate Config7 */
+ write_vpe_c0_config7(read_c0_config7());
+ }
+ /* enable multi-threading within VPE */
+ write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() | VPECONTROL_TE);
+ /* enable the VPE */
+ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
+ }
+
+ /*
+ * Pull any physically present but unused TCs out of circulation.
+ */
+ while (tc < (((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1)) {
+ cpu_clear(tc, phys_cpu_present_map);
+ cpu_clear(tc, cpu_present_map);
+ tc++;
+ }
+
+ /* release config state */
+ write_c0_mvpcontrol( read_c0_mvpcontrol() & ~ MVPCONTROL_VPC );
+
+ printk("\n");
+
+ /* Set up coprocessor affinity CPU mask(s) */
+
+ for (tc = 0; tc < ntc; tc++) {
+ if(cpu_data[tc].options & MIPS_CPU_FPU)
+ cpu_set(tc, mt_fpu_cpumask);
+ }
+
+ /* set up ipi interrupts... */
+
+ /* If we have multiple VPEs running, set up the cross-VPE interrupt */
+
+ if (nvpe > 1)
+ setup_cross_vpe_interrupts();
+
+ /* Set up queue of free IPI "messages". */
+ nipi = NR_CPUS * IPIBUF_PER_CPU;
+ if (ipibuffers > 0)
+ nipi = ipibuffers;
+
+ pipi = kmalloc(nipi *sizeof(struct smtc_ipi), GFP_KERNEL);
+ if (pipi == NULL)
+ panic("kmalloc of IPI message buffers failed\n");
+ else
+ printk("IPI buffer pool of %d buffers\n", nipi);
+ for (i = 0; i < nipi; i++) {
+ smtc_ipi_nq(&freeIPIq, pipi);
+ pipi++;
+ }
+
+ /* Arm multithreading and enable other VPEs - but all TCs are Halted */
+ emt(EMT_ENABLE);
+ evpe(EVPE_ENABLE);
+ local_irq_restore(flags);
+ /* Initialize SMTC /proc statistics/diagnostics */
+ init_smtc_stats();
+}
+
+
+/*
+ * Setup the PC, SP, and GP of a secondary processor and start it
+ * running!
+ * smp_bootstrap is the place to resume from
+ * __KSTK_TOS(idle) is apparently the stack pointer
+ * (unsigned long)idle->thread_info the gp
+ *
+ */
+void smtc_boot_secondary(int cpu, struct task_struct *idle)
+{
+ extern u32 kernelsp[NR_CPUS];
+ long flags;
+ int mtflags;
+
+ LOCK_MT_PRA();
+ if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
+ dvpe();
+ }
+ settc(cpu_data[cpu].tc_id);
+
+ /* pc */
+ write_tc_c0_tcrestart((unsigned long)&smp_bootstrap);
+
+ /* stack pointer */
+ kernelsp[cpu] = __KSTK_TOS(idle);
+ write_tc_gpr_sp(__KSTK_TOS(idle));
+
+ /* global pointer */
+ write_tc_gpr_gp((unsigned long)idle->thread_info);
+
+ smtc_status |= SMTC_MTC_ACTIVE;
+ write_tc_c0_tchalt(0);
+ if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
+ evpe(EVPE_ENABLE);
+ }
+ UNLOCK_MT_PRA();
+}
+
+void smtc_init_secondary(void)
+{
+ /*
+ * Start timer on secondary VPEs if necessary.
+ * mips_timer_setup should already have been invoked by init/main
+ * on "boot" TC. Like per_cpu_trap_init() hack, this assumes that
+ * SMTC init code assigns TCs consdecutively and in ascending order
+ * to across available VPEs.
+ */
+ if(((read_c0_tcbind() & TCBIND_CURTC) != 0)
+ && ((read_c0_tcbind() & TCBIND_CURVPE)
+ != cpu_data[smp_processor_id() - 1].vpe_id)){
+ write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ);
+ }
+
+ local_irq_enable();
+}
+
+void smtc_smp_finish(void)
+{
+ printk("TC %d going on-line as CPU %d\n",
+ cpu_data[smp_processor_id()].tc_id, smp_processor_id());
+}
+
+void smtc_cpus_done(void)
+{
+}
+
+/*
+ * Support for SMTC-optimized driver IRQ registration
+ */
+
+/*
+ * SMTC Kernel needs to manipulate low-level CPU interrupt mask
+ * in do_IRQ. These are passed in setup_irq_smtc() and stored
+ * in this table.
+ */
+
+int setup_irq_smtc(unsigned int irq, struct irqaction * new,
+ unsigned long hwmask)
+{
+ irq_hwmask[irq] = hwmask;
+
+ return setup_irq(irq, new);
+}
+
+/*
+ * IPI model for SMTC is tricky, because interrupts aren't TC-specific.
+ * Within a VPE one TC can interrupt another by different approaches.
+ * The easiest to get right would probably be to make all TCs except
+ * the target IXMT and set a software interrupt, but an IXMT-based
+ * scheme requires that a handler must run before a new IPI could
+ * be sent, which would break the "broadcast" loops in MIPS MT.
+ * A more gonzo approach within a VPE is to halt the TC, extract
+ * its Restart, Status, and a couple of GPRs, and program the Restart
+ * address to emulate an interrupt.
+ *
+ * Within a VPE, one can be confident that the target TC isn't in
+ * a critical EXL state when halted, since the write to the Halt
+ * register could not have issued on the writing thread if the
+ * halting thread had EXL set. So k0 and k1 of the target TC
+ * can be used by the injection code. Across VPEs, one can't
+ * be certain that the target TC isn't in a critical exception
+ * state. So we try a two-step process of sending a software
+ * interrupt to the target VPE, which either handles the event
+ * itself (if it was the target) or injects the event within
+ * the VPE.
+ */
+
+void smtc_ipi_qdump(void)
+{
+ int i;
+
+ for (i = 0; i < NR_CPUS ;i++) {
+ printk("IPIQ[%d]: head = 0x%x, tail = 0x%x, depth = %d\n",
+ i, (unsigned)IPIQ[i].head, (unsigned)IPIQ[i].tail,
+ IPIQ[i].depth);
+ }
+}
+
+/*
+ * The standard atomic.h primitives don't quite do what we want
+ * here: We need an atomic add-and-return-previous-value (which
+ * could be done with atomic_add_return and a decrement) and an
+ * atomic set/zero-and-return-previous-value (which can't really
+ * be done with the atomic.h primitives). And since this is
+ * MIPS MT, we can assume that we have LL/SC.
+ */
+static __inline__ int atomic_postincrement(unsigned int *pv)
+{
+ unsigned long result;
+
+ unsigned long temp;
+
+ __asm__ __volatile__(
+ "1: ll %0, %2 \n"
+ " addu %1, %0, 1 \n"
+ " sc %1, %2 \n"
+ " beqz %1, 1b \n"
+ " sync \n"
+ : "=&r" (result), "=&r" (temp), "=m" (*pv)
+ : "m" (*pv)
+ : "memory");
+
+ return result;
+}
+
+/* No longer used in IPI dispatch, but retained for future recycling */
+
+static __inline__ int atomic_postclear(unsigned int *pv)
+{
+ unsigned long result;
+
+ unsigned long temp;
+
+ __asm__ __volatile__(
+ "1: ll %0, %2 \n"
+ " or %1, $0, $0 \n"
+ " sc %1, %2 \n"
+ " beqz %1, 1b \n"
+ " sync \n"
+ : "=&r" (result), "=&r" (temp), "=m" (*pv)
+ : "m" (*pv)
+ : "memory");
+
+ return result;
+}
+
+
+void smtc_send_ipi(int cpu, int type, unsigned int action)
+{
+ int tcstatus;
+ struct smtc_ipi *pipi;
+ long flags;
+ int mtflags;
+
+ if (cpu == smp_processor_id()) {
+ printk("Cannot Send IPI to self!\n");
+ return;
+ }
+ /* Set up a descriptor, to be delivered either promptly or queued */
+ pipi = smtc_ipi_dq(&freeIPIq);
+ if (pipi == NULL) {
+ bust_spinlocks(1);
+ mips_mt_regdump(dvpe());
+ panic("IPI Msg. Buffers Depleted\n");
+ }
+ pipi->type = type;
+ pipi->arg = (void *)action;
+ pipi->dest = cpu;
+ if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
+ /* If not on same VPE, enqueue and send cross-VPE interupt */
+ smtc_ipi_nq(&IPIQ[cpu], pipi);
+ LOCK_CORE_PRA();
+ settc(cpu_data[cpu].tc_id);
+ write_vpe_c0_cause(read_vpe_c0_cause() | C_SW1);
+ UNLOCK_CORE_PRA();
+ } else {
+ /*
+ * Not sufficient to do a LOCK_MT_PRA (dmt) here,
+ * since ASID shootdown on the other VPE may
+ * collide with this operation.
+ */
+ LOCK_CORE_PRA();
+ settc(cpu_data[cpu].tc_id);
+ /* Halt the targeted TC */
+ write_tc_c0_tchalt(TCHALT_H);
+ mips_ihb();
+
+ /*
+ * Inspect TCStatus - if IXMT is set, we have to queue
+ * a message. Otherwise, we set up the "interrupt"
+ * of the other TC
+ */
+ tcstatus = read_tc_c0_tcstatus();
+
+ if ((tcstatus & TCSTATUS_IXMT) != 0) {
+ /*
+ * Spin-waiting here can deadlock,
+ * so we queue the message for the target TC.
+ */
+ write_tc_c0_tchalt(0);
+ UNLOCK_CORE_PRA();
+ /* Try to reduce redundant timer interrupt messages */
+ if(type == SMTC_CLOCK_TICK) {
+ if(atomic_postincrement(&ipi_timer_latch[cpu])!=0) {
+ smtc_ipi_nq(&freeIPIq, pipi);
+ return;
+ }
+ }
+ smtc_ipi_nq(&IPIQ[cpu], pipi);
+ } else {
+ post_direct_ipi(cpu, pipi);
+ write_tc_c0_tchalt(0);
+ UNLOCK_CORE_PRA();
+ }
+ }
+}
+
+/*
+ * Send IPI message to Halted TC, TargTC/TargVPE already having been set
+ */
+void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
+{
+ struct pt_regs *kstack;
+ unsigned long tcstatus;
+ unsigned long tcrestart;
+ extern u32 kernelsp[NR_CPUS];
+ extern void __smtc_ipi_vector(void);
+
+ /* Extract Status, EPC from halted TC */
+ tcstatus = read_tc_c0_tcstatus();
+ tcrestart = read_tc_c0_tcrestart();
+ /* If TCRestart indicates a WAIT instruction, advance the PC */
+ if ((tcrestart & 0x80000000)
+ && ((*(unsigned int *)tcrestart & 0xfe00003f) == 0x42000020)) {
+ tcrestart += 4;
+ }
+ /*
+ * Save on TC's future kernel stack
+ *
+ * CU bit of Status is indicator that TC was
+ * already running on a kernel stack...
+ */
+ if(tcstatus & ST0_CU0) {
+ /* Note that this "- 1" is pointer arithmetic */
+ kstack = ((struct pt_regs *)read_tc_gpr_sp()) - 1;
+ } else {
+ kstack = ((struct pt_regs *)kernelsp[cpu]) - 1;
+ }
+
+ kstack->cp0_epc = (long)tcrestart;
+ /* Save TCStatus */
+ kstack->cp0_tcstatus = tcstatus;
+ /* Pass token of operation to be performed kernel stack pad area */
+ kstack->pad0[4] = (unsigned long)pipi;
+ /* Pass address of function to be called likewise */
+ kstack->pad0[5] = (unsigned long)&ipi_decode;
+ /* Set interrupt exempt and kernel mode */
+ tcstatus |= TCSTATUS_IXMT;
+ tcstatus &= ~TCSTATUS_TKSU;
+ write_tc_c0_tcstatus(tcstatus);
+ ehb();
+ /* Set TC Restart address to be SMTC IPI vector */
+ write_tc_c0_tcrestart(__smtc_ipi_vector);
+}
+
+void ipi_resched_interrupt(struct pt_regs *regs)
+{
+ /* Return from interrupt should be enough to cause scheduler check */
+}
+
+
+void ipi_call_interrupt(struct pt_regs *regs)
+{
+ /* Invoke generic function invocation code in smp.c */
+ smp_call_function_interrupt();
+}
+
+void ipi_decode(struct pt_regs *regs, struct smtc_ipi *pipi)
+{
+ void *arg_copy = pipi->arg;
+ int type_copy = pipi->type;
+ int dest_copy = pipi->dest;
+
+ smtc_ipi_nq(&freeIPIq, pipi);
+ switch (type_copy) {
+ case SMTC_CLOCK_TICK:
+ /* Invoke Clock "Interrupt" */
+ ipi_timer_latch[dest_copy] = 0;
+#ifdef SMTC_IDLE_HOOK_DEBUG
+ clock_hang_reported[dest_copy] = 0;
+#endif /* SMTC_IDLE_HOOK_DEBUG */
+ local_timer_interrupt(0, NULL, regs);
+ break;
+ case LINUX_SMP_IPI:
+ switch ((int)arg_copy) {
+ case SMP_RESCHEDULE_YOURSELF:
+ ipi_resched_interrupt(regs);
+ break;
+ case SMP_CALL_FUNCTION:
+ ipi_call_interrupt(regs);
+ break;
+ default:
+ printk("Impossible SMTC IPI Argument 0x%x\n",
+ (int)arg_copy);
+ break;
+ }
+ break;
+ default:
+ printk("Impossible SMTC IPI Type 0x%x\n", type_copy);
+ break;
+ }
+}
+
+void deferred_smtc_ipi(struct pt_regs *regs)
+{
+ struct smtc_ipi *pipi;
+ unsigned long flags;
+/* DEBUG */
+ int q = smp_processor_id();
+
+ /*
+ * Test is not atomic, but much faster than a dequeue,
+ * and the vast majority of invocations will have a null queue.
+ */
+ if(IPIQ[q].head != NULL) {
+ while((pipi = smtc_ipi_dq(&IPIQ[q])) != NULL) {
+ /* ipi_decode() should be called with interrupts off */
+ local_irq_save(flags);
+ ipi_decode(regs, pipi);
+ local_irq_restore(flags);
+ }
+ }
+}
+
+/*
+ * Send clock tick to all TCs except the one executing the funtion
+ */
+
+void smtc_timer_broadcast(int vpe)
+{
+ int cpu;
+ int myTC = cpu_data[smp_processor_id()].tc_id;
+ int myVPE = cpu_data[smp_processor_id()].vpe_id;
+
+ smtc_cpu_stats[smp_processor_id()].timerints++;
+
+ for_each_online_cpu(cpu) {
+ if (cpu_data[cpu].vpe_id == myVPE &&
+ cpu_data[cpu].tc_id != myTC)
+ smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0);
+ }
+}
+
+/*
+ * Cross-VPE interrupts in the SMTC prototype use "software interrupts"
+ * set via cross-VPE MTTR manipulation of the Cause register. It would be
+ * in some regards preferable to have external logic for "doorbell" hardware
+ * interrupts.
+ */
+
+static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ;
+
+static irqreturn_t ipi_interrupt(int irq, void *dev_idm, struct pt_regs *regs)
+{
+ int my_vpe = cpu_data[smp_processor_id()].vpe_id;
+ int my_tc = cpu_data[smp_processor_id()].tc_id;
+ int cpu;
+ struct smtc_ipi *pipi;
+ unsigned long tcstatus;
+ int sent;
+ long flags;
+ unsigned int mtflags;
+ unsigned int vpflags;
+
+ /*
+ * So long as cross-VPE interrupts are done via
+ * MFTR/MTTR read-modify-writes of Cause, we need
+ * to stop other VPEs whenever the local VPE does
+ * anything similar.
+ */
+ local_irq_save(flags);
+ vpflags = dvpe();
+ clear_c0_cause(0x100 << MIPS_CPU_IPI_IRQ);
+ set_c0_status(0x100 << MIPS_CPU_IPI_IRQ);
+ irq_enable_hazard();
+ evpe(vpflags);
+ local_irq_restore(flags);
+
+ /*
+ * Cross-VPE Interrupt handler: Try to directly deliver IPIs
+ * queued for TCs on this VPE other than the current one.
+ * Return-from-interrupt should cause us to drain the queue
+ * for the current TC, so we ought not to have to do it explicitly here.
+ */
+
+ for_each_online_cpu(cpu) {
+ if (cpu_data[cpu].vpe_id != my_vpe)
+ continue;
+
+ pipi = smtc_ipi_dq(&IPIQ[cpu]);
+ if (pipi != NULL) {
+ if (cpu_data[cpu].tc_id != my_tc) {
+ sent = 0;
+ LOCK_MT_PRA();
+ settc(cpu_data[cpu].tc_id);
+ write_tc_c0_tchalt(TCHALT_H);
+ mips_ihb();
+ tcstatus = read_tc_c0_tcstatus();
+ if ((tcstatus & TCSTATUS_IXMT) == 0) {
+ post_direct_ipi(cpu, pipi);
+ sent = 1;
+ }
+ write_tc_c0_tchalt(0);
+ UNLOCK_MT_PRA();
+ if (!sent) {
+ smtc_ipi_req(&IPIQ[cpu], pipi);
+ }
+ } else {
+ /*
+ * ipi_decode() should be called
+ * with interrupts off
+ */
+ local_irq_save(flags);
+ ipi_decode(regs, pipi);
+ local_irq_restore(flags);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void ipi_irq_dispatch(struct pt_regs *regs)
+{
+ do_IRQ(cpu_ipi_irq, regs);
+}
+
+static struct irqaction irq_ipi;
+
+void setup_cross_vpe_interrupts(void)
+{
+ if (!cpu_has_vint)
+ panic("SMTC Kernel requires Vectored Interupt support");
+
+ set_vi_handler(MIPS_CPU_IPI_IRQ, ipi_irq_dispatch);
+
+ irq_ipi.handler = ipi_interrupt;
+ irq_ipi.flags = SA_INTERRUPT;
+ irq_ipi.name = "SMTC_IPI";
+
+ setup_irq_smtc(cpu_ipi_irq, &irq_ipi, (0x100 << MIPS_CPU_IPI_IRQ));
+
+ irq_desc[cpu_ipi_irq].status |= IRQ_PER_CPU;
+}
+
+/*
+ * SMTC-specific hacks invoked from elsewhere in the kernel.
+ */
+
+void smtc_idle_loop_hook(void)
+{
+#ifdef SMTC_IDLE_HOOK_DEBUG
+ int im;
+ int flags;
+ int mtflags;
+ int bit;
+ int vpe;
+ int tc;
+ int hook_ntcs;
+ /*
+ * printk within DMT-protected regions can deadlock,
+ * so buffer diagnostic messages for later output.
+ */
+ char *pdb_msg;
+ char id_ho_db_msg[768]; /* worst-case use should be less than 700 */
+
+ if (atomic_read(&idle_hook_initialized) == 0) { /* fast test */
+ if (atomic_add_return(1, &idle_hook_initialized) == 1) {
+ int mvpconf0;
+ /* Tedious stuff to just do once */
+ mvpconf0 = read_c0_mvpconf0();
+ hook_ntcs = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
+ if (hook_ntcs > NR_CPUS)
+ hook_ntcs = NR_CPUS;
+ for (tc = 0; tc < hook_ntcs; tc++) {
+ tcnoprog[tc] = 0;
+ clock_hang_reported[tc] = 0;
+ }
+ for (vpe = 0; vpe < 2; vpe++)
+ for (im = 0; im < 8; im++)
+ imstuckcount[vpe][im] = 0;
+ printk("Idle loop test hook initialized for %d TCs\n", hook_ntcs);
+ atomic_set(&idle_hook_initialized, 1000);
+ } else {
+ /* Someone else is initializing in parallel - let 'em finish */
+ while (atomic_read(&idle_hook_initialized) < 1000)
+ ;
+ }
+ }
+
+ /* Have we stupidly left IXMT set somewhere? */
+ if (read_c0_tcstatus() & 0x400) {
+ write_c0_tcstatus(read_c0_tcstatus() & ~0x400);
+ ehb();
+ printk("Dangling IXMT in cpu_idle()\n");
+ }
+
+ /* Have we stupidly left an IM bit turned off? */
+#define IM_LIMIT 2000
+ local_irq_save(flags);
+ mtflags = dmt();
+ pdb_msg = &id_ho_db_msg[0];
+ im = read_c0_status();
+ vpe = cpu_data[smp_processor_id()].vpe_id;
+ for (bit = 0; bit < 8; bit++) {
+ /*
+ * In current prototype, I/O interrupts
+ * are masked for VPE > 0
+ */
+ if (vpemask[vpe][bit]) {
+ if (!(im & (0x100 << bit)))
+ imstuckcount[vpe][bit]++;
+ else
+ imstuckcount[vpe][bit] = 0;
+ if (imstuckcount[vpe][bit] > IM_LIMIT) {
+ set_c0_status(0x100 << bit);
+ ehb();
+ imstuckcount[vpe][bit] = 0;
+ pdb_msg += sprintf(pdb_msg,
+ "Dangling IM %d fixed for VPE %d\n", bit,
+ vpe);
+ }
+ }
+ }
+
+ /*
+ * Now that we limit outstanding timer IPIs, check for hung TC
+ */
+ for (tc = 0; tc < NR_CPUS; tc++) {
+ /* Don't check ourself - we'll dequeue IPIs just below */
+ if ((tc != smp_processor_id()) &&
+ ipi_timer_latch[tc] > timerq_limit) {
+ if (clock_hang_reported[tc] == 0) {
+ pdb_msg += sprintf(pdb_msg,
+ "TC %d looks hung with timer latch at %d\n",
+ tc, ipi_timer_latch[tc]);
+ clock_hang_reported[tc]++;
+ }
+ }
+ }
+ emt(mtflags);
+ local_irq_restore(flags);
+ if (pdb_msg != &id_ho_db_msg[0])
+ printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg);
+#endif /* SMTC_IDLE_HOOK_DEBUG */
+ /*
+ * To the extent that we've ever turned interrupts off,
+ * we may have accumulated deferred IPIs. This is subtle.
+ * If we use the smtc_ipi_qdepth() macro, we'll get an
+ * exact number - but we'll also disable interrupts
+ * and create a window of failure where a new IPI gets
+ * queued after we test the depth but before we re-enable
+ * interrupts. So long as IXMT never gets set, however,
+ * we should be OK: If we pick up something and dispatch
+ * it here, that's great. If we see nothing, but concurrent
+ * with this operation, another TC sends us an IPI, IXMT
+ * is clear, and we'll handle it as a real pseudo-interrupt
+ * and not a pseudo-pseudo interrupt.
+ */
+ if (IPIQ[smp_processor_id()].depth > 0) {
+ struct smtc_ipi *pipi;
+ extern void self_ipi(struct smtc_ipi *);
+
+ if ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()])) != NULL) {
+ self_ipi(pipi);
+ smtc_cpu_stats[smp_processor_id()].selfipis++;
+ }
+ }
+}
+
+void smtc_soft_dump(void)
+{
+ int i;
+
+ printk("Counter Interrupts taken per CPU (TC)\n");
+ for (i=0; i < NR_CPUS; i++) {
+ printk("%d: %ld\n", i, smtc_cpu_stats[i].timerints);
+ }
+ printk("Self-IPI invocations:\n");
+ for (i=0; i < NR_CPUS; i++) {
+ printk("%d: %ld\n", i, smtc_cpu_stats[i].selfipis);
+ }
+ smtc_ipi_qdump();
+ printk("Timer IPI Backlogs:\n");
+ for (i=0; i < NR_CPUS; i++) {
+ printk("%d: %d\n", i, ipi_timer_latch[i]);
+ }
+ printk("%d Recoveries of \"stolen\" FPU\n",
+ atomic_read(&smtc_fpu_recoveries));
+}
+
+
+/*
+ * TLB management routines special to SMTC
+ */
+
+void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
+{
+ unsigned long flags, mtflags, tcstat, prevhalt, asid;
+ int tlb, i;
+
+ /*
+ * It would be nice to be able to use a spinlock here,
+ * but this is invoked from within TLB flush routines
+ * that protect themselves with DVPE, so if a lock is
+ * held by another TC, it'll never be freed.
+ *
+ * DVPE/DMT must not be done with interrupts enabled,
+ * so even so most callers will already have disabled
+ * them, let's be really careful...
+ */
+
+ local_irq_save(flags);
+ if (smtc_status & SMTC_TLB_SHARED) {
+ mtflags = dvpe();
+ tlb = 0;
+ } else {
+ mtflags = dmt();
+ tlb = cpu_data[cpu].vpe_id;
+ }
+ asid = asid_cache(cpu);
+
+ do {
+ if (!((asid += ASID_INC) & ASID_MASK) ) {
+ if (cpu_has_vtag_icache)
+ flush_icache_all();
+ /* Traverse all online CPUs (hack requires contigous range) */
+ for (i = 0; i < num_online_cpus(); i++) {
+ /*
+ * We don't need to worry about our own CPU, nor those of
+ * CPUs who don't share our TLB.
+ */
+ if ((i != smp_processor_id()) &&
+ ((smtc_status & SMTC_TLB_SHARED) ||
+ (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id))) {
+ settc(cpu_data[i].tc_id);
+ prevhalt = read_tc_c0_tchalt() & TCHALT_H;
+ if (!prevhalt) {
+ write_tc_c0_tchalt(TCHALT_H);
+ mips_ihb();
+ }
+ tcstat = read_tc_c0_tcstatus();
+ smtc_live_asid[tlb][(tcstat & ASID_MASK)] |= (asiduse)(0x1 << i);
+ if (!prevhalt)
+ write_tc_c0_tchalt(0);
+ }
+ }
+ if (!asid) /* fix version if needed */
+ asid = ASID_FIRST_VERSION;
+ local_flush_tlb_all(); /* start new asid cycle */
+ }
+ } while (smtc_live_asid[tlb][(asid & ASID_MASK)]);
+
+ /*
+ * SMTC shares the TLB within VPEs and possibly across all VPEs.
+ */
+ for (i = 0; i < num_online_cpus(); i++) {
+ if ((smtc_status & SMTC_TLB_SHARED) ||
+ (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id))
+ cpu_context(i, mm) = asid_cache(i) = asid;
+ }
+
+ if (smtc_status & SMTC_TLB_SHARED)
+ evpe(mtflags);
+ else
+ emt(mtflags);
+ local_irq_restore(flags);
+}
+
+/*
+ * Invoked from macros defined in mmu_context.h
+ * which must already have disabled interrupts
+ * and done a DVPE or DMT as appropriate.
+ */
+
+void smtc_flush_tlb_asid(unsigned long asid)
+{
+ int entry;
+ unsigned long ehi;
+
+ entry = read_c0_wired();
+
+ /* Traverse all non-wired entries */
+ while (entry < current_cpu_data.tlbsize) {
+ write_c0_index(entry);
+ ehb();
+ tlb_read();
+ ehb();
+ ehi = read_c0_entryhi();
+ if((ehi & ASID_MASK) == asid) {
+ /*
+ * Invalidate only entries with specified ASID,
+ * makiing sure all entries differ.
+ */
+ write_c0_entryhi(CKSEG0 + (entry << (PAGE_SHIFT + 1)));
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+ }
+ entry++;
+ }
+ write_c0_index(PARKED_INDEX);
+ tlbw_use_hazard();
+}
+
+/*
+ * Support for single-threading cache flush operations.
+ */
+
+int halt_state_save[NR_CPUS];
+
+/*
+ * To really, really be sure that nothing is being done
+ * by other TCs, halt them all. This code assumes that
+ * a DVPE has already been done, so while their Halted
+ * state is theoretically architecturally unstable, in
+ * practice, it's not going to change while we're looking
+ * at it.
+ */
+
+void smtc_cflush_lockdown(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu) {
+ if (cpu != smp_processor_id()) {
+ settc(cpu_data[cpu].tc_id);
+ halt_state_save[cpu] = read_tc_c0_tchalt();
+ write_tc_c0_tchalt(TCHALT_H);
+ }
+ }
+ mips_ihb();
+}
+
+/* It would be cheating to change the cpu_online states during a flush! */
+
+void smtc_cflush_release(void)
+{
+ int cpu;
+
+ /*
+ * Start with a hazard barrier to ensure
+ * that all CACHE ops have played through.
+ */
+ mips_ihb();
+
+ for_each_online_cpu(cpu) {
+ if (cpu != smp_processor_id()) {
+ settc(cpu_data[cpu].tc_id);
+ write_tc_c0_tchalt(halt_state_save[cpu]);
+ }
+ }
+ mips_ihb();
+}
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 5e51a2d8f3f..13ff4da598c 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -116,8 +116,7 @@ static void c0_timer_ack(void)
write_c0_compare(expirelo);
/* Check to see if we have missed any timer interrupts. */
- count = read_c0_count();
- if ((count - expirelo) < 0x7fffffff) {
+ while (((count = read_c0_count()) - expirelo) < 0x7fffffff) {
/* missed_timer_count++; */
expirelo = count + cycles_per_jiffy;
write_c0_compare(expirelo);
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index bed0eb6cf55..4901f0a37fc 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -42,6 +42,7 @@
#include <asm/watch.h>
#include <asm/types.h>
+extern asmlinkage void handle_int(void);
extern asmlinkage void handle_tlbm(void);
extern asmlinkage void handle_tlbl(void);
extern asmlinkage void handle_tlbs(void);
@@ -279,9 +280,16 @@ static DEFINE_SPINLOCK(die_lock);
NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs)
{
static int die_counter;
+#ifdef CONFIG_MIPS_MT_SMTC
+ unsigned long dvpret = dvpe();
+#endif /* CONFIG_MIPS_MT_SMTC */
console_verbose();
spin_lock_irq(&die_lock);
+ bust_spinlocks(1);
+#ifdef CONFIG_MIPS_MT_SMTC
+ mips_mt_regdump(dvpret);
+#endif /* CONFIG_MIPS_MT_SMTC */
printk("%s[#%d]:\n", str, ++die_counter);
show_registers(regs);
spin_unlock_irq(&die_lock);
@@ -750,12 +758,43 @@ asmlinkage void do_cpu(struct pt_regs *regs)
&current->thread.fpu.soft);
if (sig)
force_sig(sig, current);
+#ifdef CONFIG_MIPS_MT_FPAFF
+ else {
+ /*
+ * MIPS MT processors may have fewer FPU contexts
+ * than CPU threads. If we've emulated more than
+ * some threshold number of instructions, force
+ * migration to a "CPU" that has FP support.
+ */
+ if(mt_fpemul_threshold > 0
+ && ((current->thread.emulated_fp++
+ > mt_fpemul_threshold))) {
+ /*
+ * If there's no FPU present, or if the
+ * application has already restricted
+ * the allowed set to exclude any CPUs
+ * with FPUs, we'll skip the procedure.
+ */
+ if (cpus_intersects(current->cpus_allowed,
+ mt_fpu_cpumask)) {
+ cpumask_t tmask;
+
+ cpus_and(tmask,
+ current->thread.user_cpus_allowed,
+ mt_fpu_cpumask);
+ set_cpus_allowed(current, tmask);
+ current->thread.mflags |= MF_FPUBOUND;
+ }
+ }
+ }
+#endif /* CONFIG_MIPS_MT_FPAFF */
}
return;
case 2:
case 3:
+ die_if_kernel("do_cpu invoked from kernel context!", regs);
break;
}
@@ -793,6 +832,36 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
asmlinkage void do_mt(struct pt_regs *regs)
{
+ int subcode;
+
+ die_if_kernel("MIPS MT Thread exception in kernel", regs);
+
+ subcode = (read_vpe_c0_vpecontrol() & VPECONTROL_EXCPT)
+ >> VPECONTROL_EXCPT_SHIFT;
+ switch (subcode) {
+ case 0:
+ printk(KERN_ERR "Thread Underflow\n");
+ break;
+ case 1:
+ printk(KERN_ERR "Thread Overflow\n");
+ break;
+ case 2:
+ printk(KERN_ERR "Invalid YIELD Qualifier\n");
+ break;
+ case 3:
+ printk(KERN_ERR "Gating Storage Exception\n");
+ break;
+ case 4:
+ printk(KERN_ERR "YIELD Scheduler Exception\n");
+ break;
+ case 5:
+ printk(KERN_ERR "Gating Storage Schedulier Exception\n");
+ break;
+ default:
+ printk(KERN_ERR "*** UNKNOWN THREAD EXCEPTION %d ***\n",
+ subcode);
+ break;
+ }
die_if_kernel("MIPS MT Thread exception in kernel", regs);
force_sig(SIGILL, current);
@@ -928,7 +997,15 @@ void ejtag_exception_handler(struct pt_regs *regs)
*/
void nmi_exception_handler(struct pt_regs *regs)
{
+#ifdef CONFIG_MIPS_MT_SMTC
+ unsigned long dvpret = dvpe();
+ bust_spinlocks(1);
+ printk("NMI taken!!!!\n");
+ mips_mt_regdump(dvpret);
+#else
+ bust_spinlocks(1);
printk("NMI taken!!!!\n");
+#endif /* CONFIG_MIPS_MT_SMTC */
die("NMI", regs);
while(1) ;
}
@@ -960,27 +1037,29 @@ void *set_except_vector(int n, void *addr)
#ifdef CONFIG_CPU_MIPSR2
/*
- * Shadow register allocation
+ * MIPSR2 shadow register set allocation
* FIXME: SMP...
*/
-/* MIPSR2 shadow register sets */
-struct shadow_registers {
- spinlock_t sr_lock; /* */
- int sr_supported; /* Number of shadow register sets supported */
- int sr_allocated; /* Bitmap of allocated shadow registers */
+static struct shadow_registers {
+ /*
+ * Number of shadow register sets supported
+ */
+ unsigned long sr_supported;
+ /*
+ * Bitmap of allocated shadow registers
+ */
+ unsigned long sr_allocated;
} shadow_registers;
-void mips_srs_init(void)
+static void mips_srs_init(void)
{
#ifdef CONFIG_CPU_MIPSR2_SRS
shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
- printk ("%d MIPSR2 register sets available\n", shadow_registers.sr_supported);
-#else
- shadow_registers.sr_supported = 1;
+ printk(KERN_INFO "%d MIPSR2 register sets available\n",
+ shadow_registers.sr_supported);
#endif
shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */
- spin_lock_init(&shadow_registers.sr_lock);
}
int mips_srs_max(void)
@@ -988,38 +1067,30 @@ int mips_srs_max(void)
return shadow_registers.sr_supported;
}
-int mips_srs_alloc (void)
+int mips_srs_alloc(void)
{
struct shadow_registers *sr = &shadow_registers;
- unsigned long flags;
int set;
- spin_lock_irqsave(&sr->sr_lock, flags);
+again:
+ set = find_first_zero_bit(&sr->sr_allocated, sr->sr_supported);
+ if (set >= sr->sr_supported)
+ return -1;
- for (set = 0; set < sr->sr_supported; set++) {
- if ((sr->sr_allocated & (1 << set)) == 0) {
- sr->sr_allocated |= 1 << set;
- spin_unlock_irqrestore(&sr->sr_lock, flags);
- return set;
- }
- }
+ if (test_and_set_bit(set, &sr->sr_allocated))
+ goto again;
- /* None available */
- spin_unlock_irqrestore(&sr->sr_lock, flags);
- return -1;
+ return set;
}
-void mips_srs_free (int set)
+void mips_srs_free(int set)
{
struct shadow_registers *sr = &shadow_registers;
- unsigned long flags;
- spin_lock_irqsave(&sr->sr_lock, flags);
- sr->sr_allocated &= ~(1 << set);
- spin_unlock_irqrestore(&sr->sr_lock, flags);
+ clear_bit(set, &sr->sr_allocated);
}
-void *set_vi_srs_handler (int n, void *addr, int srs)
+static void *set_vi_srs_handler(int n, void *addr, int srs)
{
unsigned long handler;
unsigned long old_handler = vi_handlers[n];
@@ -1032,8 +1103,7 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
if (addr == NULL) {
handler = (unsigned long) do_default_vi;
srs = 0;
- }
- else
+ } else
handler = (unsigned long) addr;
vi_handlers[n] = (unsigned long) addr;
@@ -1045,8 +1115,7 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
if (cpu_has_veic) {
if (board_bind_eic_interrupt)
board_bind_eic_interrupt (n, srs);
- }
- else if (cpu_has_vint) {
+ } else if (cpu_has_vint) {
/* SRSMap is only defined if shadow sets are implemented */
if (mips_srs_max() > 1)
change_c0_srsmap (0xf << n*4, srs << n*4);
@@ -1060,6 +1129,15 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
extern char except_vec_vi, except_vec_vi_lui;
extern char except_vec_vi_ori, except_vec_vi_end;
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * We need to provide the SMTC vectored interrupt handler
+ * not only with the address of the handler, but with the
+ * Status.IM bit to be masked before going there.
+ */
+ extern char except_vec_vi_mori;
+ const int mori_offset = &except_vec_vi_mori - &except_vec_vi;
+#endif /* CONFIG_MIPS_MT_SMTC */
const int handler_len = &except_vec_vi_end - &except_vec_vi;
const int lui_offset = &except_vec_vi_lui - &except_vec_vi;
const int ori_offset = &except_vec_vi_ori - &except_vec_vi;
@@ -1073,6 +1151,12 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
}
memcpy (b, &except_vec_vi, handler_len);
+#ifdef CONFIG_MIPS_MT_SMTC
+ if (n > 7)
+ printk("Vector index %d exceeds SMTC maximum\n", n);
+ w = (u32 *)(b + mori_offset);
+ *w = (*w & 0xffff0000) | (0x100 << n);
+#endif /* CONFIG_MIPS_MT_SMTC */
w = (u32 *)(b + lui_offset);
*w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff);
w = (u32 *)(b + ori_offset);
@@ -1095,9 +1179,9 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
return (void *)old_handler;
}
-void *set_vi_handler (int n, void *addr)
+void *set_vi_handler(int n, void *addr)
{
- return set_vi_srs_handler (n, addr, 0);
+ return set_vi_srs_handler(n, addr, 0);
}
#endif
@@ -1113,8 +1197,29 @@ extern asmlinkage int _restore_fp_context(struct sigcontext *sc);
extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc);
extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc);
+#ifdef CONFIG_SMP
+static int smp_save_fp_context(struct sigcontext *sc)
+{
+ return cpu_has_fpu
+ ? _save_fp_context(sc)
+ : fpu_emulator_save_context(sc);
+}
+
+static int smp_restore_fp_context(struct sigcontext *sc)
+{
+ return cpu_has_fpu
+ ? _restore_fp_context(sc)
+ : fpu_emulator_restore_context(sc);
+}
+#endif
+
static inline void signal_init(void)
{
+#ifdef CONFIG_SMP
+ /* For now just do the cpu_has_fpu check when the functions are invoked */
+ save_fp_context = smp_save_fp_context;
+ restore_fp_context = smp_restore_fp_context;
+#else
if (cpu_has_fpu) {
save_fp_context = _save_fp_context;
restore_fp_context = _restore_fp_context;
@@ -1122,6 +1227,7 @@ static inline void signal_init(void)
save_fp_context = fpu_emulator_save_context;
restore_fp_context = fpu_emulator_restore_context;
}
+#endif
}
#ifdef CONFIG_MIPS32_COMPAT
@@ -1158,6 +1264,20 @@ void __init per_cpu_trap_init(void)
{
unsigned int cpu = smp_processor_id();
unsigned int status_set = ST0_CU0;
+#ifdef CONFIG_MIPS_MT_SMTC
+ int secondaryTC = 0;
+ int bootTC = (cpu == 0);
+
+ /*
+ * Only do per_cpu_trap_init() for first TC of Each VPE.
+ * Note that this hack assumes that the SMTC init code
+ * assigns TCs consecutively and in ascending order.
+ */
+
+ if (((read_c0_tcbind() & TCBIND_CURTC) != 0) &&
+ ((read_c0_tcbind() & TCBIND_CURVPE) == cpu_data[cpu - 1].vpe_id))
+ secondaryTC = 1;
+#endif /* CONFIG_MIPS_MT_SMTC */
/*
* Disable coprocessors and select 32-bit or 64-bit addressing
@@ -1180,6 +1300,10 @@ void __init per_cpu_trap_init(void)
write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */
#endif
+#ifdef CONFIG_MIPS_MT_SMTC
+ if (!secondaryTC) {
+#endif /* CONFIG_MIPS_MT_SMTC */
+
/*
* Interrupt handling.
*/
@@ -1196,6 +1320,9 @@ void __init per_cpu_trap_init(void)
} else
set_c0_cause(CAUSEF_IV);
}
+#ifdef CONFIG_MIPS_MT_SMTC
+ }
+#endif /* CONFIG_MIPS_MT_SMTC */
cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
TLBMISS_HANDLER_SETUP();
@@ -1205,8 +1332,14 @@ void __init per_cpu_trap_init(void)
BUG_ON(current->mm);
enter_lazy_tlb(&init_mm, current);
- cpu_cache_init();
- tlb_init();
+#ifdef CONFIG_MIPS_MT_SMTC
+ if (bootTC) {
+#endif /* CONFIG_MIPS_MT_SMTC */
+ cpu_cache_init();
+ tlb_init();
+#ifdef CONFIG_MIPS_MT_SMTC
+ }
+#endif /* CONFIG_MIPS_MT_SMTC */
}
/* Install CPU exception handler */
@@ -1278,7 +1411,7 @@ void __init trap_init(void)
if (cpu_has_veic || cpu_has_vint) {
int nvec = cpu_has_veic ? 64 : 8;
for (i = 0; i < nvec; i++)
- set_vi_handler (i, NULL);
+ set_vi_handler(i, NULL);
}
else if (cpu_has_divec)
set_handler(0x200, &except_vec4, 0x8);
@@ -1297,6 +1430,7 @@ void __init trap_init(void)
if (board_be_init)
board_be_init();
+ set_except_vector(0, handle_int);
set_except_vector(1, handle_tlbm);
set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs);
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 2ad0cedf29f..14fa00e3cdf 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -2,7 +2,7 @@
#include <asm/asm-offsets.h>
#include <asm-generic/vmlinux.lds.h>
-#undef mips /* CPP really sucks for this job */
+#undef mips
#define mips mips
OUTPUT_ARCH(mips)
ENTRY(kernel_entry)
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index ae83b755cf4..80ffaa6d50a 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -13,7 +13,6 @@
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
*/
/*
@@ -27,11 +26,8 @@
*
* To load and run, simply cat a SP 'program file' to /dev/vpe1.
* i.e cat spapp >/dev/vpe1.
- *
- * You'll need to have the following device files.
- * mknod /dev/vpe0 c 63 0
- * mknod /dev/vpe1 c 63 1
*/
+
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -55,6 +51,8 @@
#include <asm/cpu.h>
#include <asm/processor.h>
#include <asm/system.h>
+#include <asm/vpe.h>
+#include <asm/kspd.h>
typedef void *vpe_handle;
@@ -68,6 +66,11 @@ typedef void *vpe_handle;
static char module_name[] = "vpe";
static int major;
+#ifdef CONFIG_MIPS_APSP_KSPD
+ static struct kspd_notifications kspd_events;
+static int kspd_events_reqd = 0;
+#endif
+
/* grab the likely amount of memory we will need. */
#ifdef CONFIG_MIPS_VPE_LOADER_TOM
#define P_SIZE (2 * 1024 * 1024)
@@ -76,7 +79,10 @@ static int major;
#define P_SIZE (256 * 1024)
#endif
+extern unsigned long physical_memsize;
+
#define MAX_VPES 16
+#define VPE_PATH_MAX 256
enum vpe_state {
VPE_STATE_UNUSED = 0,
@@ -102,6 +108,8 @@ struct vpe {
unsigned long len;
char *pbuffer;
unsigned long plen;
+ unsigned int uid, gid;
+ char cwd[VPE_PATH_MAX];
unsigned long __start;
@@ -113,6 +121,9 @@ struct vpe {
/* shared symbol address */
void *shared_ptr;
+
+ /* the list of who wants to know when something major happens */
+ struct list_head notify;
};
struct tc {
@@ -138,7 +149,7 @@ struct vpecontrol_ {
} vpecontrol;
static void release_progmem(void *ptr);
-static void dump_vpe(struct vpe * v);
+/* static __attribute_used__ void dump_vpe(struct vpe * v); */
extern void save_gp_address(unsigned int secbase, unsigned int rel);
/* get the vpe associated with this minor */
@@ -146,12 +157,14 @@ struct vpe *get_vpe(int minor)
{
struct vpe *v;
+ if (!cpu_has_mipsmt)
+ return NULL;
+
list_for_each_entry(v, &vpecontrol.vpe_list, list) {
if (v->minor == minor)
return v;
}
- printk(KERN_DEBUG "VPE: get_vpe minor %d not found\n", minor);
return NULL;
}
@@ -165,8 +178,6 @@ struct tc *get_tc(int index)
return t;
}
- printk(KERN_DEBUG "VPE: get_tc index %d not found\n", index);
-
return NULL;
}
@@ -179,8 +190,6 @@ struct tc *get_tc_unused(void)
return t;
}
- printk(KERN_DEBUG "VPE: All TC's are in use\n");
-
return NULL;
}
@@ -190,13 +199,13 @@ struct vpe *alloc_vpe(int minor)
struct vpe *v;
if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) {
- printk(KERN_WARNING "VPE: alloc_vpe no mem\n");
return NULL;
}
INIT_LIST_HEAD(&v->tc);
list_add_tail(&v->list, &vpecontrol.vpe_list);
+ INIT_LIST_HEAD(&v->notify);
v->minor = minor;
return v;
}
@@ -207,7 +216,6 @@ struct tc *alloc_tc(int index)
struct tc *t;
if ((t = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) {
- printk(KERN_WARNING "VPE: alloc_tc no mem\n");
return NULL;
}
@@ -236,20 +244,16 @@ void dump_mtregs(void)
printk("config3 0x%lx MT %ld\n", val,
(val & CONFIG3_MT) >> CONFIG3_MT_SHIFT);
- val = read_c0_mvpconf0();
- printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
- (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
- val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
-
val = read_c0_mvpcontrol();
printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val,
(val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT,
(val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT,
(val & MVPCONTROL_EVP));
- val = read_c0_vpeconf0();
- printk("VPEConf0 0x%lx MVP %ld\n", val,
- (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT);
+ val = read_c0_mvpconf0();
+ printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
+ (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
+ val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
}
/* Find some VPE program space */
@@ -354,9 +358,9 @@ static int apply_r_mips_gprel16(struct module *me, uint32_t *location,
}
if( (rel > 32768) || (rel < -32768) ) {
- printk(KERN_ERR
- "apply_r_mips_gprel16: relative address out of range 0x%x %d\n",
- rel, rel);
+ printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: "
+ "relative address 0x%x out of range of gp register\n",
+ rel);
return -ENOEXEC;
}
@@ -374,8 +378,8 @@ static int apply_r_mips_pc16(struct module *me, uint32_t *location,
rel -= 1; // and one instruction less due to the branch delay slot.
if( (rel > 32768) || (rel < -32768) ) {
- printk(KERN_ERR
- "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
+ printk(KERN_DEBUG "VPE loader: "
+ "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
return -ENOEXEC;
}
@@ -396,7 +400,8 @@ static int apply_r_mips_26(struct module *me, uint32_t *location,
Elf32_Addr v)
{
if (v % 4) {
- printk(KERN_ERR "module %s: dangerous relocation mod4\n", me->name);
+ printk(KERN_DEBUG "VPE loader: apply_r_mips_26 "
+ " unaligned relocation\n");
return -ENOEXEC;
}
@@ -459,12 +464,13 @@ static int apply_r_mips_lo16(struct module *me, uint32_t *location,
/*
* The value for the HI16 had best be the same.
*/
- if (v != l->value) {
- printk("%d != %d\n", v, l->value);
- goto out_danger;
+ if (v != l->value) {
+ printk(KERN_DEBUG "VPE loader: "
+ "apply_r_mips_lo16/hi16: "
+ "inconsistent value information\n");
+ return -ENOEXEC;
}
-
/*
* Do the HI16 relocation. Note that we actually don't
* need to know anything about the LO16 itself, except
@@ -500,11 +506,6 @@ static int apply_r_mips_lo16(struct module *me, uint32_t *location,
*location = insnlo;
return 0;
-
-out_danger:
- printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name);
-
- return -ENOEXEC;
}
static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
@@ -518,6 +519,15 @@ static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
[R_MIPS_PC16] = apply_r_mips_pc16
};
+static char *rstrs[] = {
+ [R_MIPS_NONE] = "MIPS_NONE",
+ [R_MIPS_32] = "MIPS_32",
+ [R_MIPS_26] = "MIPS_26",
+ [R_MIPS_HI16] = "MIPS_HI16",
+ [R_MIPS_LO16] = "MIPS_LO16",
+ [R_MIPS_GPREL16] = "MIPS_GPREL16",
+ [R_MIPS_PC16] = "MIPS_PC16"
+};
int apply_relocations(Elf32_Shdr *sechdrs,
const char *strtab,
@@ -552,15 +562,13 @@ int apply_relocations(Elf32_Shdr *sechdrs,
res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
if( res ) {
- printk(KERN_DEBUG
- "relocation error 0x%x sym refer <%s> value 0x%x "
- "type 0x%x r_info 0x%x\n",
- (unsigned int)location, strtab + sym->st_name, v,
- r_info, ELF32_R_TYPE(r_info));
- }
-
- if (res)
+ char *r = rstrs[ELF32_R_TYPE(r_info)];
+ printk(KERN_WARNING "VPE loader: .text+0x%x "
+ "relocation type %s for symbol \"%s\" failed\n",
+ rel[i].r_offset, r ? r : "UNKNOWN",
+ strtab + sym->st_name);
return res;
+ }
}
return 0;
@@ -576,7 +584,7 @@ void save_gp_address(unsigned int secbase, unsigned int rel)
/* Change all symbols so that sh_value encodes the pointer directly. */
-static int simplify_symbols(Elf_Shdr * sechdrs,
+static void simplify_symbols(Elf_Shdr * sechdrs,
unsigned int symindex,
const char *strtab,
const char *secstrings,
@@ -585,18 +593,21 @@ static int simplify_symbols(Elf_Shdr * sechdrs,
Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
unsigned long secbase, bssbase = 0;
unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
- int ret = 0, size;
+ int size;
/* find the .bss section for COMMON symbols */
for (i = 0; i < nsecs; i++) {
- if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0)
+ if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) {
bssbase = sechdrs[i].sh_addr;
+ break;
+ }
}
for (i = 1; i < n; i++) {
switch (sym[i].st_shndx) {
case SHN_COMMON:
- /* Allocate space for the symbol in the .bss section. st_value is currently size.
+ /* Allocate space for the symbol in the .bss section.
+ st_value is currently size.
We want it to have the address of the symbol. */
size = sym[i].st_value;
@@ -614,11 +625,9 @@ static int simplify_symbols(Elf_Shdr * sechdrs,
break;
case SHN_MIPS_SCOMMON:
-
- printk(KERN_DEBUG
- "simplify_symbols: ignoring SHN_MIPS_SCOMMON symbol <%s> st_shndx %d\n",
- strtab + sym[i].st_name, sym[i].st_shndx);
-
+ printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON"
+ "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name,
+ sym[i].st_shndx);
// .sbss section
break;
@@ -632,10 +641,7 @@ static int simplify_symbols(Elf_Shdr * sechdrs,
sym[i].st_value += secbase;
break;
}
-
}
-
- return ret;
}
#ifdef DEBUG_ELFLOADER
@@ -655,9 +661,26 @@ static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
static void dump_tc(struct tc *t)
{
- printk(KERN_WARNING "VPE: TC index %d TCStatus 0x%lx halt 0x%lx\n",
- t->index, read_tc_c0_tcstatus(), read_tc_c0_tchalt());
- printk(KERN_WARNING "VPE: tcrestart 0x%lx\n", read_tc_c0_tcrestart());
+ unsigned long val;
+
+ settc(t->index);
+ printk(KERN_DEBUG "VPE loader: TC index %d targtc %ld "
+ "TCStatus 0x%lx halt 0x%lx\n",
+ t->index, read_c0_vpecontrol() & VPECONTROL_TARGTC,
+ read_tc_c0_tcstatus(), read_tc_c0_tchalt());
+
+ printk(KERN_DEBUG " tcrestart 0x%lx\n", read_tc_c0_tcrestart());
+ printk(KERN_DEBUG " tcbind 0x%lx\n", read_tc_c0_tcbind());
+
+ val = read_c0_vpeconf0();
+ printk(KERN_DEBUG " VPEConf0 0x%lx MVP %ld\n", val,
+ (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT);
+
+ printk(KERN_DEBUG " c0 status 0x%lx\n", read_vpe_c0_status());
+ printk(KERN_DEBUG " c0 cause 0x%lx\n", read_vpe_c0_cause());
+
+ printk(KERN_DEBUG " c0 badvaddr 0x%lx\n", read_vpe_c0_badvaddr());
+ printk(KERN_DEBUG " c0 epc 0x%lx\n", read_vpe_c0_epc());
}
static void dump_tclist(void)
@@ -672,96 +695,108 @@ static void dump_tclist(void)
/* We are prepared so configure and start the VPE... */
int vpe_run(struct vpe * v)
{
- unsigned long val;
+ struct vpe_notifications *n;
+ unsigned long val, dmt_flag;
struct tc *t;
/* check we are the Master VPE */
val = read_c0_vpeconf0();
if (!(val & VPECONF0_MVP)) {
printk(KERN_WARNING
- "VPE: only Master VPE's are allowed to configure MT\n");
+ "VPE loader: only Master VPE's are allowed to configure MT\n");
return -1;
}
/* disable MT (using dvpe) */
dvpe();
+ if (!list_empty(&v->tc)) {
+ if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
+ printk(KERN_WARNING "VPE loader: TC %d is already in use.\n",
+ t->index);
+ return -ENOEXEC;
+ }
+ } else {
+ printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n",
+ v->minor);
+ return -ENOEXEC;
+ }
+
/* Put MVPE's into 'configuration state' */
set_c0_mvpcontrol(MVPCONTROL_VPC);
- if (!list_empty(&v->tc)) {
- if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
- printk(KERN_WARNING "VPE: TC %d is already in use.\n",
- t->index);
- return -ENOEXEC;
- }
- } else {
- printk(KERN_WARNING "VPE: No TC's associated with VPE %d\n",
- v->minor);
- return -ENOEXEC;
- }
-
settc(t->index);
- val = read_vpe_c0_vpeconf0();
-
/* should check it is halted, and not activated */
if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
- printk(KERN_WARNING "VPE: TC %d is already doing something!\n",
+ printk(KERN_WARNING "VPE loader: TC %d is already doing something!\n",
t->index);
-
dump_tclist();
return -ENOEXEC;
}
+ /*
+ * Disable multi-threaded execution whilst we activate, clear the
+ * halt bit and bound the tc to the other VPE...
+ */
+ dmt_flag = dmt();
+
/* Write the address we want it to start running from in the TCPC register. */
write_tc_c0_tcrestart((unsigned long)v->__start);
-
- /* write the sivc_info address to tccontext */
write_tc_c0_tccontext((unsigned long)0);
-
- /* Set up the XTC bit in vpeconf0 to point at our tc */
- write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (t->index << VPECONF0_XTC_SHIFT));
-
- /* mark the TC as activated, not interrupt exempt and not dynamically allocatable */
+ /*
+ * Mark the TC as activated, not interrupt exempt and not dynamically
+ * allocatable
+ */
val = read_tc_c0_tcstatus();
val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
write_tc_c0_tcstatus(val);
write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
- /* set up VPE1 */
- write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); // no multiple TC's
- write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); // enable this VPE
-
/*
* The sde-kit passes 'memsize' to __start in $a3, so set something
- * here...
- * Or set $a3 (register 7) to zero and define DFLT_STACK_SIZE and
+ * here... Or set $a3 to zero and define DFLT_STACK_SIZE and
* DFLT_HEAP_SIZE when you compile your program
*/
+ mttgpr(7, physical_memsize);
+
+
+ /* set up VPE1 */
+ /*
+ * bind the TC to VPE 1 as late as possible so we only have the final
+ * VPE registers to set up, and so an EJTAG probe can trigger on it
+ */
+ write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor);
- mttgpr(7, 0);
+ /* Set up the XTC bit in vpeconf0 to point at our tc */
+ write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
+ | (t->index << VPECONF0_XTC_SHIFT));
- /* set config to be the same as vpe0, particularly kseg0 coherency alg */
- write_vpe_c0_config(read_c0_config());
+ /* enable this VPE */
+ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
/* clear out any left overs from a previous program */
+ write_vpe_c0_status(0);
write_vpe_c0_cause(0);
/* take system out of configuration state */
clear_c0_mvpcontrol(MVPCONTROL_VPC);
- /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */
- write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE | ST0_EXL));
+ /* now safe to re-enable multi-threading */
+ emt(dmt_flag);
/* set it running */
evpe(EVPE_ENABLE);
+ list_for_each_entry(n, &v->notify, list) {
+ n->start(v->minor);
+ }
+
return 0;
}
-static unsigned long find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
+static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
unsigned int symindex, const char *strtab,
struct module *mod)
{
@@ -778,26 +813,28 @@ static unsigned long find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
}
}
+ if ( (v->__start == 0) || (v->shared_ptr == NULL))
+ return -1;
+
return 0;
}
/*
- * Allocates a VPE with some program code space(the load address), copies
- * the contents of the program (p)buffer performing relocatations/etc,
- * free's it when finished.
-*/
+ * Allocates a VPE with some program code space(the load address), copies the
+ * contents of the program (p)buffer performing relocatations/etc, free's it
+ * when finished.
+ */
int vpe_elfload(struct vpe * v)
{
Elf_Ehdr *hdr;
Elf_Shdr *sechdrs;
long err = 0;
char *secstrings, *strtab = NULL;
- unsigned int len, i, symindex = 0, strindex = 0;
-
+ unsigned int len, i, symindex = 0, strindex = 0, relocate = 0;
struct module mod; // so we can re-use the relocations code
memset(&mod, 0, sizeof(struct module));
- strcpy(mod.name, "VPE dummy prog module");
+ strcpy(mod.name, "VPE loader");
hdr = (Elf_Ehdr *) v->pbuffer;
len = v->plen;
@@ -805,16 +842,22 @@ int vpe_elfload(struct vpe * v)
/* Sanity checks against insmoding binaries or wrong arch,
weird elf version */
if (memcmp(hdr->e_ident, ELFMAG, 4) != 0
- || hdr->e_type != ET_REL || !elf_check_arch(hdr)
+ || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC)
+ || !elf_check_arch(hdr)
|| hdr->e_shentsize != sizeof(*sechdrs)) {
printk(KERN_WARNING
- "VPE program, wrong arch or weird elf version\n");
+ "VPE loader: program wrong arch or weird elf version\n");
return -ENOEXEC;
}
+ if (hdr->e_type == ET_REL)
+ relocate = 1;
+
if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
- printk(KERN_ERR "VPE program length %u truncated\n", len);
+ printk(KERN_ERR "VPE loader: program length %u truncated\n",
+ len);
+
return -ENOEXEC;
}
@@ -826,82 +869,126 @@ int vpe_elfload(struct vpe * v)
/* And these should exist, but gcc whinges if we don't init them */
symindex = strindex = 0;
- for (i = 1; i < hdr->e_shnum; i++) {
-
- if (sechdrs[i].sh_type != SHT_NOBITS
- && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
- printk(KERN_ERR "VPE program length %u truncated\n",
- len);
- return -ENOEXEC;
- }
+ if (relocate) {
+ for (i = 1; i < hdr->e_shnum; i++) {
+ if (sechdrs[i].sh_type != SHT_NOBITS
+ && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
+ printk(KERN_ERR "VPE program length %u truncated\n",
+ len);
+ return -ENOEXEC;
+ }
- /* Mark all sections sh_addr with their address in the
- temporary image. */
- sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
+ /* Mark all sections sh_addr with their address in the
+ temporary image. */
+ sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
- /* Internal symbols and strings. */
- if (sechdrs[i].sh_type == SHT_SYMTAB) {
- symindex = i;
- strindex = sechdrs[i].sh_link;
- strtab = (char *)hdr + sechdrs[strindex].sh_offset;
+ /* Internal symbols and strings. */
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ symindex = i;
+ strindex = sechdrs[i].sh_link;
+ strtab = (char *)hdr + sechdrs[strindex].sh_offset;
+ }
}
+ layout_sections(&mod, hdr, sechdrs, secstrings);
}
- layout_sections(&mod, hdr, sechdrs, secstrings);
-
v->load_addr = alloc_progmem(mod.core_size);
memset(v->load_addr, 0, mod.core_size);
- printk("VPE elf_loader: loading to %p\n", v->load_addr);
+ printk("VPE loader: loading to %p\n", v->load_addr);
- for (i = 0; i < hdr->e_shnum; i++) {
- void *dest;
+ if (relocate) {
+ for (i = 0; i < hdr->e_shnum; i++) {
+ void *dest;
- if (!(sechdrs[i].sh_flags & SHF_ALLOC))
- continue;
+ if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+ continue;
- dest = v->load_addr + sechdrs[i].sh_entsize;
+ dest = v->load_addr + sechdrs[i].sh_entsize;
- if (sechdrs[i].sh_type != SHT_NOBITS)
- memcpy(dest, (void *)sechdrs[i].sh_addr,
- sechdrs[i].sh_size);
- /* Update sh_addr to point to copy in image. */
- sechdrs[i].sh_addr = (unsigned long)dest;
- }
+ if (sechdrs[i].sh_type != SHT_NOBITS)
+ memcpy(dest, (void *)sechdrs[i].sh_addr,
+ sechdrs[i].sh_size);
+ /* Update sh_addr to point to copy in image. */
+ sechdrs[i].sh_addr = (unsigned long)dest;
- /* Fix up syms, so that st_value is a pointer to location. */
- err =
- simplify_symbols(sechdrs, symindex, strtab, secstrings,
- hdr->e_shnum, &mod);
- if (err < 0) {
- printk(KERN_WARNING "VPE: unable to simplify symbols\n");
- goto cleanup;
- }
+ printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n",
+ secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
+ }
- /* Now do relocations. */
- for (i = 1; i < hdr->e_shnum; i++) {
- const char *strtab = (char *)sechdrs[strindex].sh_addr;
- unsigned int info = sechdrs[i].sh_info;
-
- /* Not a valid relocation section? */
- if (info >= hdr->e_shnum)
- continue;
-
- /* Don't bother with non-allocated sections */
- if (!(sechdrs[info].sh_flags & SHF_ALLOC))
- continue;
-
- if (sechdrs[i].sh_type == SHT_REL)
- err =
- apply_relocations(sechdrs, strtab, symindex, i, &mod);
- else if (sechdrs[i].sh_type == SHT_RELA)
- err = apply_relocate_add(sechdrs, strtab, symindex, i,
- &mod);
- if (err < 0) {
- printk(KERN_WARNING
- "vpe_elfload: error in relocations err %ld\n",
- err);
- goto cleanup;
+ /* Fix up syms, so that st_value is a pointer to location. */
+ simplify_symbols(sechdrs, symindex, strtab, secstrings,
+ hdr->e_shnum, &mod);
+
+ /* Now do relocations. */
+ for (i = 1; i < hdr->e_shnum; i++) {
+ const char *strtab = (char *)sechdrs[strindex].sh_addr;
+ unsigned int info = sechdrs[i].sh_info;
+
+ /* Not a valid relocation section? */
+ if (info >= hdr->e_shnum)
+ continue;
+
+ /* Don't bother with non-allocated sections */
+ if (!(sechdrs[info].sh_flags & SHF_ALLOC))
+ continue;
+
+ if (sechdrs[i].sh_type == SHT_REL)
+ err = apply_relocations(sechdrs, strtab, symindex, i,
+ &mod);
+ else if (sechdrs[i].sh_type == SHT_RELA)
+ err = apply_relocate_add(sechdrs, strtab, symindex, i,
+ &mod);
+ if (err < 0)
+ return err;
+
+ }
+ } else {
+ for (i = 0; i < hdr->e_shnum; i++) {
+
+ /* Internal symbols and strings. */
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ symindex = i;
+ strindex = sechdrs[i].sh_link;
+ strtab = (char *)hdr + sechdrs[strindex].sh_offset;
+
+ /* mark the symtab's address for when we try to find the
+ magic symbols */
+ sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
+ }
+
+ /* filter sections we dont want in the final image */
+ if (!(sechdrs[i].sh_flags & SHF_ALLOC) ||
+ (sechdrs[i].sh_type == SHT_MIPS_REGINFO)) {
+ printk( KERN_DEBUG " ignoring section, "
+ "name %s type %x address 0x%x \n",
+ secstrings + sechdrs[i].sh_name,
+ sechdrs[i].sh_type, sechdrs[i].sh_addr);
+ continue;
+ }
+
+ if (sechdrs[i].sh_addr < (unsigned int)v->load_addr) {
+ printk( KERN_WARNING "VPE loader: "
+ "fully linked image has invalid section, "
+ "name %s type %x address 0x%x, before load "
+ "address of 0x%x\n",
+ secstrings + sechdrs[i].sh_name,
+ sechdrs[i].sh_type, sechdrs[i].sh_addr,
+ (unsigned int)v->load_addr);
+ return -ENOEXEC;
+ }
+
+ printk(KERN_DEBUG " copying section sh_name %s, sh_addr 0x%x "
+ "size 0x%x0 from x%p\n",
+ secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr,
+ sechdrs[i].sh_size, hdr + sechdrs[i].sh_offset);
+
+ if (sechdrs[i].sh_type != SHT_NOBITS)
+ memcpy((void *)sechdrs[i].sh_addr,
+ (char *)hdr + sechdrs[i].sh_offset,
+ sechdrs[i].sh_size);
+ else
+ memset((void *)sechdrs[i].sh_addr, 0, sechdrs[i].sh_size);
}
}
@@ -910,71 +997,104 @@ int vpe_elfload(struct vpe * v)
(unsigned long)v->load_addr + v->len);
if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
+ if (v->__start == 0) {
+ printk(KERN_WARNING "VPE loader: program does not contain "
+ "a __start symbol\n");
+ return -ENOEXEC;
+ }
- printk(KERN_WARNING
- "VPE: program doesn't contain __start or vpe_shared symbols\n");
- err = -ENOEXEC;
+ if (v->shared_ptr == NULL)
+ printk(KERN_WARNING "VPE loader: "
+ "program does not contain vpe_shared symbol.\n"
+ " Unable to use AMVP (AP/SP) facilities.\n");
}
printk(" elf loaded\n");
-
-cleanup:
- return err;
+ return 0;
}
-static void dump_vpe(struct vpe * v)
+__attribute_used__ void dump_vpe(struct vpe * v)
{
struct tc *t;
+ settc(v->minor);
+
printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol());
printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0());
- list_for_each_entry(t, &vpecontrol.tc_list, list) {
+ list_for_each_entry(t, &vpecontrol.tc_list, list)
dump_tc(t);
- }
}
-/* checks for VPE is unused and gets ready to load program */
+static void cleanup_tc(struct tc *tc)
+{
+ int tmp;
+
+ /* Put MVPE's into 'configuration state' */
+ set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+ settc(tc->index);
+ tmp = read_tc_c0_tcstatus();
+
+ /* mark not allocated and not dynamically allocatable */
+ tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
+ tmp |= TCSTATUS_IXMT; /* interrupt exempt */
+ write_tc_c0_tcstatus(tmp);
+
+ write_tc_c0_tchalt(TCHALT_H);
+
+ /* bind it to anything other than VPE1 */
+ write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
+
+ clear_c0_mvpcontrol(MVPCONTROL_VPC);
+}
+
+static int getcwd(char *buff, int size)
+{
+ mm_segment_t old_fs;
+ int ret;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ ret = sys_getcwd(buff,size);
+
+ set_fs(old_fs);
+
+ return ret;
+}
+
+/* checks VPE is unused and gets ready to load program */
static int vpe_open(struct inode *inode, struct file *filp)
{
- int minor;
+ int minor, ret;
struct vpe *v;
+ struct vpe_notifications *not;
/* assume only 1 device at the mo. */
if ((minor = MINOR(inode->i_rdev)) != 1) {
- printk(KERN_WARNING "VPE: only vpe1 is supported\n");
+ printk(KERN_WARNING "VPE loader: only vpe1 is supported\n");
return -ENODEV;
}
if ((v = get_vpe(minor)) == NULL) {
- printk(KERN_WARNING "VPE: unable to get vpe\n");
+ printk(KERN_WARNING "VPE loader: unable to get vpe\n");
return -ENODEV;
}
if (v->state != VPE_STATE_UNUSED) {
- unsigned long tmp;
- struct tc *t;
-
- printk(KERN_WARNING "VPE: device %d already in use\n", minor);
-
dvpe();
- dump_vpe(v);
-
- printk(KERN_WARNING "VPE: re-initialising %d\n", minor);
-
- release_progmem(v->load_addr);
- t = get_tc(minor);
- settc(minor);
- tmp = read_tc_c0_tcstatus();
+ printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
- /* mark not allocated and not dynamically allocatable */
- tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
- tmp |= TCSTATUS_IXMT; /* interrupt exempt */
- write_tc_c0_tcstatus(tmp);
+ dump_tc(get_tc(minor));
- write_tc_c0_tchalt(TCHALT_H);
+ list_for_each_entry(not, &v->notify, list) {
+ not->stop(minor);
+ }
+ release_progmem(v->load_addr);
+ cleanup_tc(get_tc(minor));
}
// allocate it so when we get write ops we know it's expected.
@@ -986,6 +1106,24 @@ static int vpe_open(struct inode *inode, struct file *filp)
v->load_addr = NULL;
v->len = 0;
+ v->uid = filp->f_uid;
+ v->gid = filp->f_gid;
+
+#ifdef CONFIG_MIPS_APSP_KSPD
+ /* get kspd to tell us when a syscall_exit happens */
+ if (!kspd_events_reqd) {
+ kspd_notify(&kspd_events);
+ kspd_events_reqd++;
+ }
+#endif
+
+ v->cwd[0] = 0;
+ ret = getcwd(v->cwd, VPE_PATH_MAX);
+ if (ret < 0)
+ printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret);
+
+ v->shared_ptr = NULL;
+ v->__start = 0;
return 0;
}
@@ -1006,14 +1144,22 @@ static int vpe_release(struct inode *inode, struct file *filp)
if (vpe_elfload(v) >= 0)
vpe_run(v);
else {
- printk(KERN_WARNING "VPE: ELF load failed.\n");
+ printk(KERN_WARNING "VPE loader: ELF load failed.\n");
ret = -ENOEXEC;
}
} else {
- printk(KERN_WARNING "VPE: only elf files are supported\n");
+ printk(KERN_WARNING "VPE loader: only elf files are supported\n");
ret = -ENOEXEC;
}
+ /* It's good to be able to run the SP and if it chokes have a look at
+ the /dev/rt?. But if we reset the pointer to the shared struct we
+ loose what has happened. So perhaps if garbage is sent to the vpe
+ device, use it as a trigger for the reset. Hopefully a nice
+ executable will be along shortly. */
+ if (ret < 0)
+ v->shared_ptr = NULL;
+
// cleanup any temp buffers
if (v->pbuffer)
vfree(v->pbuffer);
@@ -1033,21 +1179,19 @@ static ssize_t vpe_write(struct file *file, const char __user * buffer,
return -ENODEV;
if (v->pbuffer == NULL) {
- printk(KERN_ERR "vpe_write: no pbuffer\n");
+ printk(KERN_ERR "VPE loader: no buffer for program\n");
return -ENOMEM;
}
if ((count + v->len) > v->plen) {
printk(KERN_WARNING
- "VPE Loader: elf size too big. Perhaps strip uneeded symbols\n");
+ "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
return -ENOMEM;
}
count -= copy_from_user(v->pbuffer + v->len, buffer, count);
- if (!count) {
- printk("vpe_write: copy_to_user failed\n");
+ if (!count)
return -EFAULT;
- }
v->len += count;
return ret;
@@ -1149,16 +1293,70 @@ void *vpe_get_shared(int index)
{
struct vpe *v;
- if ((v = get_vpe(index)) == NULL) {
- printk(KERN_WARNING "vpe: invalid vpe index %d\n", index);
+ if ((v = get_vpe(index)) == NULL)
return NULL;
- }
return v->shared_ptr;
}
EXPORT_SYMBOL(vpe_get_shared);
+int vpe_getuid(int index)
+{
+ struct vpe *v;
+
+ if ((v = get_vpe(index)) == NULL)
+ return -1;
+
+ return v->uid;
+}
+
+EXPORT_SYMBOL(vpe_getuid);
+
+int vpe_getgid(int index)
+{
+ struct vpe *v;
+
+ if ((v = get_vpe(index)) == NULL)
+ return -1;
+
+ return v->gid;
+}
+
+EXPORT_SYMBOL(vpe_getgid);
+
+int vpe_notify(int index, struct vpe_notifications *notify)
+{
+ struct vpe *v;
+
+ if ((v = get_vpe(index)) == NULL)
+ return -1;
+
+ list_add(&notify->list, &v->notify);
+ return 0;
+}
+
+EXPORT_SYMBOL(vpe_notify);
+
+char *vpe_getcwd(int index)
+{
+ struct vpe *v;
+
+ if ((v = get_vpe(index)) == NULL)
+ return NULL;
+
+ return v->cwd;
+}
+
+EXPORT_SYMBOL(vpe_getcwd);
+
+#ifdef CONFIG_MIPS_APSP_KSPD
+static void kspd_sp_exit( int sp_id)
+{
+ cleanup_tc(get_tc(sp_id));
+}
+#endif
+
static int __init vpe_module_init(void)
{
struct vpe *v = NULL;
@@ -1201,7 +1399,8 @@ static int __init vpe_module_init(void)
return -ENODEV;
}
- list_add(&t->tc, &v->tc); /* add the tc to the list of this vpe's tc's. */
+ /* add the tc to the list of this vpe's tc's. */
+ list_add(&t->tc, &v->tc);
/* deactivate all but vpe0 */
if (i != 0) {
@@ -1222,10 +1421,12 @@ static int __init vpe_module_init(void)
~(ST0_IM | ST0_IE | ST0_KSU))
| ST0_CU0);
- /* set config to be the same as vpe0, particularly kseg0 coherency alg */
+ /*
+ * Set config to be the same as vpe0,
+ * particularly kseg0 coherency alg
+ */
write_vpe_c0_config(read_c0_config());
}
-
}
/* TC's */
@@ -1234,23 +1435,28 @@ static int __init vpe_module_init(void)
if (i != 0) {
unsigned long tmp;
- /* tc 0 will of course be running.... */
- if (i == 0)
- t->state = TC_STATE_RUNNING;
-
settc(i);
- /* bind a TC to each VPE, May as well put all excess TC's
- on the last VPE */
- if (i >= (((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1))
- write_tc_c0_tcbind(read_tc_c0_tcbind() |
- ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT));
- else
- write_tc_c0_tcbind(read_tc_c0_tcbind() | i);
+ /* Any TC that is bound to VPE0 gets left as is - in case
+ we are running SMTC on VPE0. A TC that is bound to any
+ other VPE gets bound to VPE0, ideally I'd like to make
+ it homeless but it doesn't appear to let me bind a TC
+ to a non-existent VPE. Which is perfectly reasonable.
+
+ The (un)bound state is visible to an EJTAG probe so may
+ notify GDB...
+ */
+
+ if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {
+ /* tc is bound >vpe0 */
+ write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
+
+ t->pvpe = get_vpe(0); /* set the parent vpe */
+ }
tmp = read_tc_c0_tcstatus();
- /* mark not allocated and not dynamically allocatable */
+ /* mark not activated and not dynamically allocatable */
tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
tmp |= TCSTATUS_IXMT; /* interrupt exempt */
write_tc_c0_tcstatus(tmp);
@@ -1262,6 +1468,9 @@ static int __init vpe_module_init(void)
/* release config state */
clear_c0_mvpcontrol(MVPCONTROL_VPC);
+#ifdef CONFIG_MIPS_APSP_KSPD
+ kspd_events.kspd_sp_exit = kspd_sp_exit;
+#endif
return 0;
}
@@ -1281,5 +1490,5 @@ static void __exit vpe_module_exit(void)
module_init(vpe_module_init);
module_exit(vpe_module_exit);
MODULE_DESCRIPTION("MIPS VPE Loader");
-MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc");
+MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
MODULE_LICENSE("GPL");
diff --git a/arch/mips/lasat/Makefile b/arch/mips/lasat/Makefile
index 0d5aec43672..99f5046fdf4 100644
--- a/arch/mips/lasat/Makefile
+++ b/arch/mips/lasat/Makefile
@@ -3,7 +3,7 @@
#
obj-y += reset.o setup.o prom.o lasat_board.o \
- at93c.o interrupt.o lasatIRQ.o
+ at93c.o interrupt.o
obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o
obj-$(CONFIG_DS1603) += ds1603.o
diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c
index 852a41901a5..2d3472b21eb 100644
--- a/arch/mips/lasat/interrupt.c
+++ b/arch/mips/lasat/interrupt.c
@@ -27,14 +27,13 @@
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/lasat/lasatint.h>
+#include <asm/time.h>
#include <asm/gdb-stub.h>
static volatile int *lasat_int_status = NULL;
static volatile int *lasat_int_mask = NULL;
static volatile int lasat_int_mask_shift;
-extern asmlinkage void lasatIRQ(void);
-
void disable_lasat_irq(unsigned int irq_nr)
{
unsigned long flags;
@@ -109,11 +108,17 @@ static unsigned long get_int_status_200(void)
return int_status;
}
-void lasat_hw0_irqdispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned long int_status;
+ unsigned int cause = read_c0_cause();
int irq;
+ if (cause & CAUSEF_IP7) { /* R4000 count / compare IRQ */
+ ll_timer_interrupt(7, regs);
+ return;
+ }
+
int_status = get_int_status();
/* if int_status == 0, then the interrupt has already been cleared */
@@ -147,9 +152,6 @@ void __init arch_init_irq(void)
panic("arch_init_irq: mips_machtype incorrect");
}
- /* Now safe to set the exception vector. */
- set_except_vector(0, lasatIRQ);
-
for (i = 0; i <= LASATINT_END; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
diff --git a/arch/mips/lasat/lasatIRQ.S b/arch/mips/lasat/lasatIRQ.S
deleted file mode 100644
index 2a2b0d05656..00000000000
--- a/arch/mips/lasat/lasatIRQ.S
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Interrupt exception dispatch code.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
- .text
- .set noreorder
- .align 5
- NESTED(lasatIRQ, PT_SIZE, sp)
- .set noat
- SAVE_ALL
- CLI
- .set at
- .set noreorder
-
- mfc0 s0, CP0_CAUSE # get irq mask
-
- /* First we check for r4k counter/timer IRQ. */
- andi a0, s0, CAUSEF_IP7
- beq a0, zero, 1f
- andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt
-
- /* Wheee, a timer interrupt. */
- li a0, 7
- jal ll_timer_interrupt
- move a1, sp
-
- j ret_from_irq
- nop
-
-1:
- /* Wheee, combined hardware level zero interrupt. */
- jal lasat_hw0_irqdispatch
- move a0, sp # delay slot
-
- j ret_from_irq
- nop # delay slot
-
-1:
- /*
- * Here by mistake? This is possible, what can happen is that by the
- * time we take the exception the IRQ pin goes low, so just leave if
- * this is the case.
- */
- move a1,s0
- mfc0 a1, CP0_EPC
-
- j ret_from_irq
- nop
- END(lasatIRQ)
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c
index bc0ebc69bfb..db53950b7cf 100644
--- a/arch/mips/mips-boards/atlas/atlas_int.c
+++ b/arch/mips/mips-boards/atlas/atlas_int.c
@@ -39,8 +39,6 @@
static struct atlas_ictrl_regs *atlas_hw0_icregs;
-extern asmlinkage void mipsIRQ(void);
-
#if 0
#define DEBUG_INT(x...) printk(x)
#else
@@ -98,7 +96,7 @@ static inline int ls1bit32(unsigned int x)
return b;
}
-void atlas_hw0_irqdispatch(struct pt_regs *regs)
+static inline void atlas_hw0_irqdispatch(struct pt_regs *regs)
{
unsigned long int_status;
int irq;
@@ -116,6 +114,91 @@ void atlas_hw0_irqdispatch(struct pt_regs *regs)
do_IRQ(irq, regs);
}
+static inline int clz(unsigned long x)
+{
+ __asm__ (
+ " .set push \n"
+ " .set mips32 \n"
+ " clz %0, %1 \n"
+ " .set pop \n"
+ : "=r" (x)
+ : "r" (x));
+
+ return x;
+}
+
+/*
+ * Version of ffs that only looks at bits 12..15.
+ */
+static inline unsigned int irq_ffs(unsigned int pending)
+{
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+ return -clz(pending) + 31 - CAUSEB_IP;
+#else
+ unsigned int a0 = 7;
+ unsigned int t0;
+
+ t0 = s0 & 0xf000;
+ t0 = t0 < 1;
+ t0 = t0 << 2;
+ a0 = a0 - t0;
+ s0 = s0 << t0;
+
+ t0 = s0 & 0xc000;
+ t0 = t0 < 1;
+ t0 = t0 << 1;
+ a0 = a0 - t0;
+ s0 = s0 << t0;
+
+ t0 = s0 & 0x8000;
+ t0 = t0 < 1;
+ //t0 = t0 << 2;
+ a0 = a0 - t0;
+ //s0 = s0 << t0;
+
+ return a0;
+#endif
+}
+
+/*
+ * IRQs on the Atlas board look basically (barring software IRQs which we
+ * don't use at all and all external interrupt sources are combined together
+ * on hardware interrupt 0 (MIPS IRQ 2)) like:
+ *
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Combined hardware interrupt (hw0)
+ * 3 Hardware (ignored)
+ * 4 Hardware (ignored)
+ * 5 Hardware (ignored)
+ * 6 Hardware (ignored)
+ * 7 R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+ * Lowest ---- Combined hardware interrupt
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ int irq;
+
+ irq = irq_ffs(pending);
+
+ if (irq == MIPSCPU_INT_ATLAS)
+ atlas_hw0_irqdispatch(regs);
+ else if (irq > 0)
+ do_IRQ(MIPSCPU_INT_BASE + irq, regs);
+ else
+ spurious_interrupt(regs);
+}
+
void __init arch_init_irq(void)
{
int i;
@@ -128,9 +211,6 @@ void __init arch_init_irq(void)
*/
atlas_hw0_icregs->intrsten = 0xffffffff;
- /* Now safe to set the exception vector. */
- set_except_vector(0, mipsIRQ);
-
for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
diff --git a/arch/mips/mips-boards/generic/Makefile b/arch/mips/mips-boards/generic/Makefile
index b21bc6887fa..be47c1c2bc8 100644
--- a/arch/mips/mips-boards/generic/Makefile
+++ b/arch/mips/mips-boards/generic/Makefile
@@ -18,8 +18,8 @@
# Makefile for the MIPS boards generic routines under Linux.
#
-obj-y := mipsIRQ.o reset.o display.o init.o memory.o \
- printf.o cmdline.o time.o
+obj-y := reset.o display.o init.o memory.o printf.o \
+ cmdline.o time.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_KGDB) += gdb_hook.o
diff --git a/arch/mips/mips-boards/generic/gdb_hook.c b/arch/mips/mips-boards/generic/gdb_hook.c
index 91a2ccbe373..6a1854de457 100644
--- a/arch/mips/mips-boards/generic/gdb_hook.c
+++ b/arch/mips/mips-boards/generic/gdb_hook.c
@@ -25,7 +25,7 @@
#include <asm/serial.h>
#include <asm/io.h>
-static struct serial_state rs_table[RS_TABLE_SIZE] = {
+static struct serial_state rs_table[] = {
SERIAL_PORT_DFNS /* Defined in serial.h */
};
diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c
index eab5a705e98..17dfe6a8cab 100644
--- a/arch/mips/mips-boards/generic/init.c
+++ b/arch/mips/mips-boards/generic/init.c
@@ -220,7 +220,6 @@ void __init kgdb_config (void)
generic_putDebugChar (*s++);
}
- kgdb_enabled = 1;
/* Breakpoint is invoked after interrupts are initialised */
}
}
diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c
index 32c9210373a..bc4d093685b 100644
--- a/arch/mips/mips-boards/generic/memory.c
+++ b/arch/mips/mips-boards/generic/memory.c
@@ -22,10 +22,12 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
+#include <linux/pfn.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
#include <asm/page.h>
+#include <asm/sections.h>
#include <asm/mips-boards/prom.h>
@@ -46,9 +48,6 @@ static char *mtypes[3] = {
};
#endif
-/* References to section boundaries */
-extern char _end;
-
struct prom_pmemblock * __init prom_getmdesc(void)
{
char *memsize_str;
@@ -106,10 +105,10 @@ struct prom_pmemblock * __init prom_getmdesc(void)
mdesc[3].type = yamon_dontuse;
mdesc[3].base = 0x00100000;
- mdesc[3].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[3].base;
+ mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) - mdesc[3].base;
mdesc[4].type = yamon_free;
- mdesc[4].base = CPHYSADDR(PAGE_ALIGN(&_end));
+ mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
mdesc[4].size = memsize - mdesc[4].base;
return &mdesc[0];
diff --git a/arch/mips/mips-boards/generic/mipsIRQ.S b/arch/mips/mips-boards/generic/mipsIRQ.S
deleted file mode 100644
index ddd5c73a297..00000000000
--- a/arch/mips/mips-boards/generic/mipsIRQ.S
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
- *
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- * Interrupt exception dispatch code.
- *
- */
-#include <linux/config.h>
-
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-#ifdef CONFIG_MIPS_ATLAS
-#include <asm/mips-boards/atlasint.h>
-#define CASCADE_IRQ MIPSCPU_INT_ATLAS
-#define CASCADE_DISPATCH atlas_hw0_irqdispatch
-#endif
-#ifdef CONFIG_MIPS_MALTA
-#include <asm/mips-boards/maltaint.h>
-#define CASCADE_IRQ MIPSCPU_INT_I8259A
-#define CASCADE_DISPATCH malta_hw0_irqdispatch
-#endif
-#ifdef CONFIG_MIPS_SEAD
-#include <asm/mips-boards/seadint.h>
-#endif
-
-/* A lot of complication here is taken away because:
- *
- * 1) We handle one interrupt and return, sitting in a loop and moving across
- * all the pending IRQ bits in the cause register is _NOT_ the answer, the
- * common case is one pending IRQ so optimize in that direction.
- *
- * 2) We need not check against bits in the status register IRQ mask, that
- * would make this routine slow as hell.
- *
- * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
- * between like BSD spl() brain-damage.
- *
- * Furthermore, the IRQs on the MIPS board look basically (barring software
- * IRQs which we don't use at all and all external interrupt sources are
- * combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
- *
- * MIPS IRQ Source
- * -------- ------
- * 0 Software (ignored)
- * 1 Software (ignored)
- * 2 Combined hardware interrupt (hw0)
- * 3 Hardware (ignored)
- * 4 Hardware (ignored)
- * 5 Hardware (ignored)
- * 6 Hardware (ignored)
- * 7 R4k timer (what we use)
- *
- * Note: On the SEAD board thing are a little bit different.
- * Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
- * wired to UART1.
- *
- * We handle the IRQ according to _our_ priority which is:
- *
- * Highest ---- R4k Timer
- * Lowest ---- Combined hardware interrupt
- *
- * then we just return, if multiple IRQs are pending then we will just take
- * another exception, big deal.
- */
-
- .text
- .set noreorder
- .set noat
- .align 5
- NESTED(mipsIRQ, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
-
- mfc0 s0, CP0_CAUSE # get irq bits
- mfc0 s1, CP0_STATUS # get irq mask
- andi s0, ST0_IM # CAUSE.CE may be non-zero!
- and s0, s1
-
-#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
- .set mips32
- clz a0, s0
- .set mips0
- negu a0
- addu a0, 31-CAUSEB_IP
- bltz a0, spurious
-#else
- beqz s0, spurious
- li a0, 7
-
- and t0, s0, 0xf000
- sltiu t0, t0, 1
- sll t0, 2
- subu a0, t0
- sll s0, t0
-
- and t0, s0, 0xc000
- sltiu t0, t0, 1
- sll t0, 1
- subu a0, t0
- sll s0, t0
-
- and t0, s0, 0x8000
- sltiu t0, t0, 1
- # sll t0, 0
- subu a0, t0
- # sll s0, t0
-#endif
-
-#ifdef CASCADE_IRQ
- li a1, CASCADE_IRQ
- bne a0, a1, 1f
- addu a0, MIPSCPU_INT_BASE
-
- jal CASCADE_DISPATCH
- move a0, sp
-
- j ret_from_irq
- nop
-1:
-#else
- addu a0, MIPSCPU_INT_BASE
-#endif
-
- jal do_IRQ
- move a1, sp
-
- j ret_from_irq
- nop
-
-
-spurious:
- j spurious_interrupt
- nop
- END(mipsIRQ)
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 93f3bf2c2b2..a9f6124b3a2 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -30,6 +30,7 @@
#include <linux/mc146818rtc.h>
#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
#include <asm/ptrace.h>
#include <asm/hardirq.h>
#include <asm/irq.h>
@@ -50,16 +51,23 @@ unsigned long cpu_khz;
static char display_string[] = " LINUX ON ATLAS ";
#endif
#if defined(CONFIG_MIPS_MALTA)
+#if defined(CONFIG_MIPS_MT_SMTC)
+static char display_string[] = " SMTC LINUX ON MALTA ";
+#else
static char display_string[] = " LINUX ON MALTA ";
+#endif /* CONFIG_MIPS_MT_SMTC */
#endif
#if defined(CONFIG_MIPS_SEAD)
static char display_string[] = " LINUX ON SEAD ";
#endif
-static unsigned int display_count = 0;
+static unsigned int display_count;
#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8)
-static unsigned int timer_tick_count=0;
+#define CPUCTR_IMASKBIT (0x100 << MIPSCPU_INT_CPUCTR)
+
+static unsigned int timer_tick_count;
static int mips_cpu_timer_irq;
+extern void smtc_timer_broadcast(int);
static inline void scroll_display_message(void)
{
@@ -75,15 +83,55 @@ static void mips_timer_dispatch (struct pt_regs *regs)
do_IRQ (mips_cpu_timer_irq, regs);
}
+/*
+ * Redeclare until I get around mopping the timer code insanity on MIPS.
+ */
extern int null_perf_irq(struct pt_regs *regs);
extern int (*perf_irq)(struct pt_regs *regs);
irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- int r2 = cpu_has_mips_r2;
int cpu = smp_processor_id();
+ int r2 = cpu_has_mips_r2;
+
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * In an SMTC system, one Count/Compare set exists per VPE.
+ * Which TC within a VPE gets the interrupt is essentially
+ * random - we only know that it shouldn't be one with
+ * IXMT set. Whichever TC gets the interrupt needs to
+ * send special interprocessor interrupts to the other
+ * TCs to make sure that they schedule, etc.
+ *
+ * That code is specific to the SMTC kernel, not to
+ * the a particular platform, so it's invoked from
+ * the general MIPS timer_interrupt routine.
+ */
+
+ /*
+ * DVPE is necessary so long as cross-VPE interrupts
+ * are done via read-modify-write of Cause register.
+ */
+ int vpflags = dvpe();
+ write_c0_compare (read_c0_count() - 1);
+ clear_c0_cause(CPUCTR_IMASKBIT);
+ evpe(vpflags);
+
+ if (cpu_data[cpu].vpe_id == 0) {
+ timer_interrupt(irq, dev_id, regs);
+ scroll_display_message();
+ } else
+ write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
+ smtc_timer_broadcast(cpu_data[cpu].vpe_id);
+ if (cpu != 0)
+ /*
+ * Other CPUs should do profiling and process accounting
+ */
+ local_timer_interrupt(irq, dev_id, regs);
+
+#else /* CONFIG_MIPS_MT_SMTC */
if (cpu == 0) {
/*
* CPU 0 handles the global timer interrupt job and process
@@ -107,12 +155,14 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* More support needs to be added to kernel/time for
* counter/timer interrupts on multiple CPU's
*/
- write_c0_compare (read_c0_count() + (mips_hpt_frequency/HZ));
+ write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
+
/*
- * other CPUs should do profiling and process accounting
+ * Other CPUs should do profiling and process accounting
*/
- local_timer_interrupt (irq, dev_id, regs);
+ local_timer_interrupt(irq, dev_id, regs);
}
+#endif /* CONFIG_MIPS_MT_SMTC */
out:
return IRQ_HANDLED;
@@ -126,7 +176,7 @@ static unsigned int __init estimate_cpu_frequency(void)
unsigned int prid = read_c0_prid() & 0xffff00;
unsigned int count;
-#ifdef CONFIG_MIPS_SEAD
+#if defined(CONFIG_MIPS_SEAD) || defined(CONFIG_MIPS_SIM)
/*
* The SEAD board doesn't have a real time clock, so we can't
* really calculate the timer frequency
@@ -211,7 +261,11 @@ void __init mips_timer_setup(struct irqaction *irq)
/* we are using the cpu counter for timer interrupts */
irq->handler = mips_timer_interrupt; /* we use our own handler */
+#ifdef CONFIG_MIPS_MT_SMTC
+ setup_irq_smtc(mips_cpu_timer_irq, irq, CPUCTR_IMASKBIT);
+#else
setup_irq(mips_cpu_timer_irq, irq);
+#endif /* CONFIG_MIPS_MT_SMTC */
#ifdef CONFIG_SMP
/* irq_desc(riptor) is a global resource, when the interrupt overlaps
diff --git a/arch/mips/mips-boards/malta/Makefile b/arch/mips/mips-boards/malta/Makefile
index fd4c143c0e2..77ee5c6d33c 100644
--- a/arch/mips/mips-boards/malta/Makefile
+++ b/arch/mips/mips-boards/malta/Makefile
@@ -20,3 +20,4 @@
#
obj-y := malta_int.o malta_setup.o
+obj-$(CONFIG_SMP) += malta_smp.o
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index d06dc5ad6c9..64db07d4dbe 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -40,7 +40,6 @@
#include <asm/mips-boards/msc01_pci.h>
#include <asm/msc01_ic.h>
-extern asmlinkage void mipsIRQ(void);
extern void mips_timer_interrupt(void);
static DEFINE_SPINLOCK(mips_irq_lock);
@@ -114,13 +113,14 @@ static inline int get_int(void)
return irq;
}
-void malta_hw0_irqdispatch(struct pt_regs *regs)
+static void malta_hw0_irqdispatch(struct pt_regs *regs)
{
int irq;
irq = get_int();
- if (irq < 0)
+ if (irq < 0) {
return; /* interrupt has already been cleared */
+ }
do_IRQ(MALTA_INT_BASE+irq, regs);
}
@@ -182,6 +182,92 @@ void corehi_irqdispatch(struct pt_regs *regs)
die("CoreHi interrupt", regs);
}
+static inline int clz(unsigned long x)
+{
+ __asm__ (
+ " .set push \n"
+ " .set mips32 \n"
+ " clz %0, %1 \n"
+ " .set pop \n"
+ : "=r" (x)
+ : "r" (x));
+
+ return x;
+}
+
+/*
+ * Version of ffs that only looks at bits 12..15.
+ */
+static inline unsigned int irq_ffs(unsigned int pending)
+{
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+ return -clz(pending) + 31 - CAUSEB_IP;
+#else
+ unsigned int a0 = 7;
+ unsigned int t0;
+
+ t0 = s0 & 0xf000;
+ t0 = t0 < 1;
+ t0 = t0 << 2;
+ a0 = a0 - t0;
+ s0 = s0 << t0;
+
+ t0 = s0 & 0xc000;
+ t0 = t0 < 1;
+ t0 = t0 << 1;
+ a0 = a0 - t0;
+ s0 = s0 << t0;
+
+ t0 = s0 & 0x8000;
+ t0 = t0 < 1;
+ //t0 = t0 << 2;
+ a0 = a0 - t0;
+ //s0 = s0 << t0;
+
+ return a0;
+#endif
+}
+
+/*
+ * IRQs on the Malta board look basically (barring software IRQs which we
+ * don't use at all and all external interrupt sources are combined together
+ * on hardware interrupt 0 (MIPS IRQ 2)) like:
+ *
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Combined hardware interrupt (hw0)
+ * 3 Hardware (ignored)
+ * 4 Hardware (ignored)
+ * 5 Hardware (ignored)
+ * 6 Hardware (ignored)
+ * 7 R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+ * Lowest ---- Combined hardware interrupt
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ int irq;
+
+ irq = irq_ffs(pending);
+
+ if (irq == MIPSCPU_INT_I8259A)
+ malta_hw0_irqdispatch(regs);
+ else if (irq > 0)
+ do_IRQ(MIPSCPU_INT_BASE + irq, regs);
+ else
+ spurious_interrupt(regs);
+}
+
static struct irqaction i8259irq = {
.handler = no_action,
.name = "XT-PIC cascade"
@@ -214,7 +300,6 @@ int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t);
void __init arch_init_irq(void)
{
- set_except_vector(0, mipsIRQ);
init_i8259_irqs();
if (!cpu_has_veic)
@@ -240,12 +325,17 @@ void __init arch_init_irq(void)
else if (cpu_has_vint) {
set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch);
-
+#ifdef CONFIG_MIPS_MT_SMTC
+ setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq,
+ (0x100 << MIPSCPU_INT_I8259A));
+ setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI,
+ &corehi_irqaction, (0x100 << MIPSCPU_INT_COREHI));
+#else /* Not SMTC */
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
+#endif /* CONFIG_MIPS_MT_SMTC */
}
else {
- set_except_vector(0, mipsIRQ);
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
}
diff --git a/arch/mips/mips-boards/malta/malta_smp.c b/arch/mips/mips-boards/malta/malta_smp.c
new file mode 100644
index 00000000000..6c6c8eeedbc
--- /dev/null
+++ b/arch/mips/mips-boards/malta/malta_smp.c
@@ -0,0 +1,128 @@
+/*
+ * Malta Platform-specific hooks for SMP operation
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+
+#include <asm/atomic.h>
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+#ifdef CONFIG_MIPS_MT_SMTC
+#include <asm/smtc_ipi.h>
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+/* VPE/SMP Prototype implements platform interfaces directly */
+#if !defined(CONFIG_MIPS_MT_SMP)
+
+/*
+ * Cause the specified action to be performed on a targeted "CPU"
+ */
+
+void core_send_ipi(int cpu, unsigned int action)
+{
+/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
+#ifdef CONFIG_MIPS_MT_SMTC
+ smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Detect available CPUs/VPEs/TCs and populate phys_cpu_present_map
+ */
+
+void __init prom_build_cpu_map(void)
+{
+ int nextslot;
+
+ /*
+ * As of November, 2004, MIPSsim only simulates one core
+ * at a time. However, that core may be a MIPS MT core
+ * with multiple virtual processors and thread contexts.
+ */
+
+ if (read_c0_config3() & (1<<2)) {
+ nextslot = mipsmt_build_cpu_map(1);
+ }
+}
+
+/*
+ * Platform "CPU" startup hook
+ */
+
+void prom_boot_secondary(int cpu, struct task_struct *idle)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ smtc_boot_secondary(cpu, idle);
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Post-config but pre-boot cleanup entry point
+ */
+
+void prom_init_secondary(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ void smtc_init_secondary(void);
+ int myvpe;
+
+ /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
+ myvpe = read_c0_tcbind() & TCBIND_CURVPE;
+ if (myvpe != 0) {
+ /* Ideally, this should be done only once per VPE, but... */
+ clear_c0_status(STATUSF_IP2);
+ set_c0_status(STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP3
+ | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6
+ | STATUSF_IP7);
+ }
+
+ smtc_init_secondary();
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Platform SMP pre-initialization
+ *
+ * As noted above, we can assume a single CPU for now
+ * but it may be multithreaded.
+ */
+
+void plat_smp_setup(void)
+{
+ if (read_c0_config3() & (1<<2))
+ mipsmt_build_cpu_map(0);
+}
+
+void __init plat_prepare_cpus(unsigned int max_cpus)
+{
+ if (read_c0_config3() & (1<<2))
+ mipsmt_prepare_cpus();
+}
+
+/*
+ * SMP initialization finalization entry point
+ */
+
+void prom_smp_finish(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ smtc_smp_finish();
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Hook for after all CPUs are online
+ */
+
+void prom_cpus_done(void)
+{
+}
+
+#endif /* CONFIG_MIPS32R2_MT_SMP */
diff --git a/arch/mips/mips-boards/sead/sead_int.c b/arch/mips/mips-boards/sead/sead_int.c
index 90fda0d9915..9168d934c66 100644
--- a/arch/mips/mips-boards/sead/sead_int.c
+++ b/arch/mips/mips-boards/sead/sead_int.c
@@ -24,16 +24,94 @@
#include <linux/irq.h>
#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/mips-boards/seadint.h>
-extern asmlinkage void mipsIRQ(void);
+static inline int clz(unsigned long x)
+{
+ __asm__ (
+ " .set push \n"
+ " .set mips32 \n"
+ " clz %0, %1 \n"
+ " .set pop \n"
+ : "=r" (x)
+ : "r" (x));
+
+ return x;
+}
+
+/*
+ * Version of ffs that only looks at bits 12..15.
+ */
+static inline unsigned int irq_ffs(unsigned int pending)
+{
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+ return -clz(pending) + 31 - CAUSEB_IP;
+#else
+ unsigned int a0 = 7;
+ unsigned int t0;
+
+ t0 = s0 & 0xf000;
+ t0 = t0 < 1;
+ t0 = t0 << 2;
+ a0 = a0 - t0;
+ s0 = s0 << t0;
+
+ t0 = s0 & 0xc000;
+ t0 = t0 < 1;
+ t0 = t0 << 1;
+ a0 = a0 - t0;
+ s0 = s0 << t0;
+
+ t0 = s0 & 0x8000;
+ t0 = t0 < 1;
+ //t0 = t0 << 2;
+ a0 = a0 - t0;
+ //s0 = s0 << t0;
+
+ return a0;
+#endif
+}
+
+/*
+ * IRQs on the SEAD board look basically are combined together on hardware
+ * interrupt 0 (MIPS IRQ 2)) like:
+ *
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 UART0 (hw0)
+ * 3 UART1 (hw1)
+ * 4 Hardware (ignored)
+ * 5 Hardware (ignored)
+ * 6 Hardware (ignored)
+ * 7 R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+ * Lowest ---- Combined hardware interrupt
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ int irq;
+
+ irq = irq_ffs(pending);
+
+ if (irq >= 0)
+ do_IRQ(MIPSCPU_INT_BASE + irq, regs);
+ else
+ spurious_interrupt(regs);
+}
void __init arch_init_irq(void)
{
mips_cpu_irq_init(MIPSCPU_INT_BASE);
-
- /* Now safe to set the exception vector. */
- set_except_vector(0, mipsIRQ);
}
diff --git a/arch/mips/mips-boards/sim/cmdline.c b/arch/mips/mips-boards/sim/cmdline.c
deleted file mode 100644
index fef9fbd8e71..00000000000
--- a/arch/mips/mips-boards/sim/cmdline.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Kernel command line creation using the prom monitor (YAMON) argc/argv.
- */
-#include <linux/init.h>
-#include <linux/string.h>
-
-#include <asm/bootinfo.h>
-
-extern int prom_argc;
-extern int *_prom_argv;
-
-/*
- * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
- * This macro take care of sign extension.
- */
-#define prom_argv(index) ((char *)(((int *)(int)_prom_argv)[(index)]))
-
-char arcs_cmdline[CL_SIZE];
-
-char * __init prom_getcmdline(void)
-{
- return &(arcs_cmdline[0]);
-}
-
-
-void __init prom_init_cmdline(void)
-{
- char *cp;
- int actr;
-
- actr = 1; /* Always ignore argv[0] */
-
- cp = &(arcs_cmdline[0]);
- while(actr < prom_argc) {
- strcpy(cp, prom_argv(actr));
- cp += strlen(prom_argv(actr));
- *cp++ = ' ';
- actr++;
- }
- if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
- --cp;
- *cp = '\0';
-}
diff --git a/arch/mips/mips-boards/sim/sim_cmdline.c b/arch/mips/mips-boards/sim/sim_cmdline.c
index 9df37c6fca3..c63021a5dc6 100644
--- a/arch/mips/mips-boards/sim/sim_cmdline.c
+++ b/arch/mips/mips-boards/sim/sim_cmdline.c
@@ -26,8 +26,10 @@ char * __init prom_getcmdline(void)
return arcs_cmdline;
}
-
void __init prom_init_cmdline(void)
{
- /* nothing to do */
+ char *cp;
+ cp = arcs_cmdline;
+ /* Get boot line from environment? */
+ *cp = '\0';
}
diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c
index a4d0a2c0503..2c15c8efec4 100644
--- a/arch/mips/mips-boards/sim/sim_int.c
+++ b/arch/mips/mips-boards/sim/sim_int.c
@@ -25,17 +25,71 @@
extern void mips_cpu_irq_init(int);
-extern asmlinkage void simIRQ(void);
+static inline int clz(unsigned long x)
+{
+ __asm__ (
+ " .set push \n"
+ " .set mips32 \n"
+ " clz %0, %1 \n"
+ " .set pop \n"
+ : "=r" (x)
+ : "r" (x));
+
+ return x;
+}
+
+/*
+ * Version of ffs that only looks at bits 12..15.
+ */
+static inline unsigned int irq_ffs(unsigned int pending)
+{
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+ return -clz(pending) + 31 - CAUSEB_IP;
+#else
+ unsigned int a0 = 7;
+ unsigned int t0;
+
+ t0 = s0 & 0xf000;
+ t0 = t0 < 1;
+ t0 = t0 << 2;
+ a0 = a0 - t0;
+ s0 = s0 << t0;
+
+ t0 = s0 & 0xc000;
+ t0 = t0 < 1;
+ t0 = t0 << 1;
+ a0 = a0 - t0;
+ s0 = s0 << t0;
-asmlinkage void sim_hw0_irqdispatch(struct pt_regs *regs)
+ t0 = s0 & 0x8000;
+ t0 = t0 < 1;
+ //t0 = t0 << 2;
+ a0 = a0 - t0;
+ //s0 = s0 << t0;
+
+ return a0;
+#endif
+}
+
+static inline void sim_hw0_irqdispatch(struct pt_regs *regs)
{
do_IRQ(2, regs);
}
-void __init arch_init_irq(void)
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
- /* Now safe to set the exception vector. */
- set_except_vector(0, simIRQ);
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ int irq;
+
+ irq = irq_ffs(pending);
+ if (irq > 0)
+ do_IRQ(MIPSCPU_INT_BASE + irq, regs);
+ else
+ spurious_interrupt(regs);
+}
+
+void __init arch_init_irq(void)
+{
mips_cpu_irq_init(MIPSCPU_INT_BASE);
}
diff --git a/arch/mips/mips-boards/sim/sim_irq.S b/arch/mips/mips-boards/sim/sim_irq.S
index da52297a221..d16cf382207 100644
--- a/arch/mips/mips-boards/sim/sim_irq.S
+++ b/arch/mips/mips-boards/sim/sim_irq.S
@@ -94,6 +94,8 @@
spurious:
- j spurious_interrupt
+ jal spurious_interrupt
+ nop
+ j ret_from_irq
nop
END(simIRQ)
diff --git a/arch/mips/mips-boards/sim/sim_mem.c b/arch/mips/mips-boards/sim/sim_mem.c
index e57f737bab1..f7ce7698332 100644
--- a/arch/mips/mips-boards/sim/sim_mem.c
+++ b/arch/mips/mips-boards/sim/sim_mem.c
@@ -18,9 +18,11 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
+#include <linux/pfn.h>
#include <asm/bootinfo.h>
#include <asm/page.h>
+#include <asm/sections.h>
#include <asm/mips-boards/prom.h>
@@ -39,9 +41,6 @@ static char *mtypes[3] = {
};
#endif
-/* References to section boundaries */
-extern char _end;
-
struct prom_pmemblock * __init prom_getmdesc(void)
{
unsigned int memsize;
@@ -61,10 +60,10 @@ struct prom_pmemblock * __init prom_getmdesc(void)
mdesc[2].type = simmem_reserved;
mdesc[2].base = 0x00100000;
- mdesc[2].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[2].base;
+ mdesc[2].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[2].base;
mdesc[3].type = simmem_free;
- mdesc[3].base = CPHYSADDR(PAGE_ALIGN(&_end));
+ mdesc[3].base = CPHYSADDR(PFN_ALIGN(&_end));
mdesc[3].size = memsize - mdesc[3].base;
return &mdesc[0];
diff --git a/arch/mips/mips-boards/sim/sim_smp.c b/arch/mips/mips-boards/sim/sim_smp.c
index a9f0c2bfe4a..b7084e7c4bf 100644
--- a/arch/mips/mips-boards/sim/sim_smp.c
+++ b/arch/mips/mips-boards/sim/sim_smp.c
@@ -44,8 +44,6 @@
void core_send_ipi(int cpu, unsigned int action)
{
#ifdef CONFIG_MIPS_MT_SMTC
- void smtc_send_ipi(int, int, unsigned int);
-
smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
#endif /* CONFIG_MIPS_MT_SMTC */
/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
@@ -59,15 +57,8 @@ void core_send_ipi(int cpu, unsigned int action)
void __init prom_build_cpu_map(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
- extern int mipsmt_build_cpu_map(int startslot);
int nextslot;
- cpus_clear(phys_cpu_present_map);
-
- /* Register the boot CPU */
-
- smp_prepare_boot_cpu();
-
/*
* As of November, 2004, MIPSsim only simulates one core
* at a time. However, that core may be a MIPS MT core
@@ -87,8 +78,6 @@ void __init prom_build_cpu_map(void)
void prom_boot_secondary(int cpu, struct task_struct *idle)
{
#ifdef CONFIG_MIPS_MT_SMTC
- extern void smtc_boot_secondary(int cpu, struct task_struct *t);
-
smtc_boot_secondary(cpu, idle);
#endif /* CONFIG_MIPS_MT_SMTC */
}
@@ -113,7 +102,6 @@ void prom_init_secondary(void)
void prom_prepare_cpus(unsigned int max_cpus)
{
#ifdef CONFIG_MIPS_MT_SMTC
- void mipsmt_prepare_cpus(int c);
/*
* As noted above, we can assume a single CPU for now
* but it may be multithreaded.
@@ -132,8 +120,6 @@ void prom_prepare_cpus(unsigned int max_cpus)
void prom_smp_finish(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
- void smtc_smp_finish(void);
-
smtc_smp_finish();
#endif /* CONFIG_MIPS_MT_SMTC */
}
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c
index 9dd1352d574..bb041a22f20 100644
--- a/arch/mips/mm/c-r3k.c
+++ b/arch/mips/mm/c-r3k.c
@@ -260,6 +260,10 @@ static void r3k_flush_cache_page(struct vm_area_struct *vma, unsigned long page,
{
}
+static void local_r3k_flush_data_cache_page(unsigned long addr)
+{
+}
+
static void r3k_flush_data_cache_page(unsigned long addr)
{
}
@@ -335,6 +339,7 @@ void __init r3k_cache_init(void)
flush_icache_range = r3k_flush_icache_range;
flush_cache_sigtramp = r3k_flush_cache_sigtramp;
+ local_flush_data_cache_page = local_r3k_flush_data_cache_page;
flush_data_cache_page = r3k_flush_data_cache_page;
_dma_cache_wback_inv = r3k_dma_cache_wback_inv;
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 32b7f6aeb98..4182e1176fa 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -154,7 +154,8 @@ static inline void blast_icache32_r4600_v1_page_indexed(unsigned long page)
static inline void tx49_blast_icache32_page_indexed(unsigned long page)
{
- unsigned long start = page;
+ unsigned long indexmask = current_cpu_data.icache.waysize - 1;
+ unsigned long start = INDEX_BASE + (page & indexmask);
unsigned long end = start + PAGE_SIZE;
unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit;
unsigned long ws_end = current_cpu_data.icache.ways <<
@@ -749,12 +750,12 @@ static void __init probe_pcache(void)
icache_size = 1 << (12 + ((config & CONF_IC) >> 9));
c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
c->icache.ways = 2;
- c->icache.waybit = ffs(icache_size/2) - 1;
+ c->icache.waybit = __ffs(icache_size/2);
dcache_size = 1 << (12 + ((config & CONF_DC) >> 6));
c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
c->dcache.ways = 2;
- c->dcache.waybit= ffs(dcache_size/2) - 1;
+ c->dcache.waybit= __ffs(dcache_size/2);
c->options |= MIPS_CPU_CACHE_CDEX_P;
break;
@@ -837,12 +838,12 @@ static void __init probe_pcache(void)
icache_size = 1 << (10 + ((config & CONF_IC) >> 9));
c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
c->icache.ways = 2;
- c->icache.waybit = ffs(icache_size/2) - 1;
+ c->icache.waybit = __ffs(icache_size/2);
dcache_size = 1 << (10 + ((config & CONF_DC) >> 6));
c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
c->dcache.ways = 2;
- c->dcache.waybit = ffs(dcache_size/2) - 1;
+ c->dcache.waybit = __ffs(dcache_size/2);
c->options |= MIPS_CPU_CACHE_CDEX_P;
break;
@@ -873,12 +874,12 @@ static void __init probe_pcache(void)
icache_size = 1 << (12 + ((config & CONF_IC) >> 9));
c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
c->icache.ways = 4;
- c->icache.waybit = ffs(icache_size / c->icache.ways) - 1;
+ c->icache.waybit = __ffs(icache_size / c->icache.ways);
dcache_size = 1 << (12 + ((config & CONF_DC) >> 6));
c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
c->dcache.ways = 4;
- c->dcache.waybit = ffs(dcache_size / c->dcache.ways) - 1;
+ c->dcache.waybit = __ffs(dcache_size / c->dcache.ways);
#if !defined(CONFIG_SMP) || !defined(RM9000_CDEX_SMP_WAR)
c->options |= MIPS_CPU_CACHE_CDEX_P;
@@ -906,7 +907,7 @@ static void __init probe_pcache(void)
icache_size = c->icache.sets *
c->icache.ways *
c->icache.linesz;
- c->icache.waybit = ffs(icache_size/c->icache.ways) - 1;
+ c->icache.waybit = __ffs(icache_size/c->icache.ways);
if (config & 0x8) /* VI bit */
c->icache.flags |= MIPS_CACHE_VTAG;
@@ -926,7 +927,7 @@ static void __init probe_pcache(void)
dcache_size = c->dcache.sets *
c->dcache.ways *
c->dcache.linesz;
- c->dcache.waybit = ffs(dcache_size/c->dcache.ways) - 1;
+ c->dcache.waybit = __ffs(dcache_size/c->dcache.ways);
c->options |= MIPS_CPU_PREFETCH;
break;
@@ -1198,6 +1199,7 @@ void __init r4k_cache_init(void)
flush_cache_sigtramp = r4k_flush_cache_sigtramp;
flush_icache_all = r4k_flush_icache_all;
+ local_flush_data_cache_page = local_r4k_flush_data_cache_page;
flush_data_cache_page = r4k_flush_data_cache_page;
flush_icache_range = r4k_flush_icache_range;
diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c
index 2f08b535f20..f9b129491b1 100644
--- a/arch/mips/mm/c-sb1.c
+++ b/arch/mips/mm/c-sb1.c
@@ -528,6 +528,7 @@ void sb1_cache_init(void)
flush_cache_page = sb1_flush_cache_page;
flush_cache_sigtramp = sb1_flush_cache_sigtramp;
+ local_flush_data_cache_page = (void *) sb1_nop;
flush_data_cache_page = (void *) sb1_nop;
/* Full flush */
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c
index fe232e3988e..5dfc9b1901f 100644
--- a/arch/mips/mm/c-tx39.c
+++ b/arch/mips/mm/c-tx39.c
@@ -216,6 +216,11 @@ static void tx39_flush_cache_page(struct vm_area_struct *vma, unsigned long page
tx39_blast_icache_page_indexed(page);
}
+static void local_tx39_flush_data_cache_page(void * addr)
+{
+ tx39_blast_dcache_page(addr);
+}
+
static void tx39_flush_data_cache_page(unsigned long addr)
{
tx39_blast_dcache_page(addr);
@@ -381,6 +386,7 @@ void __init tx39_cache_init(void)
flush_icache_range = (void *) tx39h_flush_icache_all;
flush_cache_sigtramp = (void *) tx39h_flush_icache_all;
+ local_flush_data_cache_page = (void *) tx39h_flush_icache_all;
flush_data_cache_page = (void *) tx39h_flush_icache_all;
_dma_cache_wback_inv = tx39h_dma_cache_wback_inv;
@@ -406,6 +412,7 @@ void __init tx39_cache_init(void)
flush_icache_range = tx39_flush_icache_range;
flush_cache_sigtramp = tx39_flush_cache_sigtramp;
+ local_flush_data_cache_page = local_tx39_flush_data_cache_page;
flush_data_cache_page = tx39_flush_data_cache_page;
_dma_cache_wback_inv = tx39_dma_cache_wback_inv;
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 591c22b080e..83a56296be8 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -30,6 +30,7 @@ void (*flush_icache_page)(struct vm_area_struct *vma, struct page *page);
/* MIPS specific cache operations */
void (*flush_cache_sigtramp)(unsigned long addr);
+void (*local_flush_data_cache_page)(void * addr);
void (*flush_data_cache_page)(unsigned long addr);
void (*flush_icache_all)(void);
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 2d9624fd10e..e3a61722486 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -157,7 +157,6 @@ no_context:
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
-
bust_spinlocks(1);
printk(KERN_ALERT "CPU %d Unable to handle kernel paging request at "
@@ -188,11 +187,20 @@ do_sigbus:
/* Kernel mode? Handle exceptions or die */
if (!user_mode(regs))
goto no_context;
-
+ else
/*
* Send a sigbus, regardless of whether we were in kernel
* or user mode.
*/
+#if 0
+ printk("do_page_fault() #3: sending SIGBUS to %s for "
+ "invalid %s\n%0*lx (epc == %0*lx, ra == %0*lx)\n",
+ tsk->comm,
+ write ? "write access to" : "read access from",
+ field, address,
+ field, (unsigned long) regs->cp0_epc,
+ field, (unsigned long) regs->regs[31]);
+#endif
tsk->thread.cp0_badvaddr = address;
info.si_signo = SIGBUS;
info.si_errno = 0;
@@ -201,7 +209,6 @@ do_sigbus:
force_sig_info(SIGBUS, &info, tsk);
return;
-
vmalloc_fault:
{
/*
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
index 1f7b37b38f5..0c544375b85 100644
--- a/arch/mips/mm/highmem.c
+++ b/arch/mips/mm/highmem.c
@@ -83,6 +83,7 @@ void __kunmap_atomic(void *kvaddr, enum km_type type)
preempt_check_resched();
}
+#ifndef CONFIG_LIMITED_DMA
/*
* This is the same as kmap_atomic() but can map memory that doesn't
* have a struct page associated with it.
@@ -101,6 +102,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
return (void*) vaddr;
}
+#endif /* CONFIG_LIMITED_DMA */
struct page *__kmap_atomic_to_page(void *ptr)
{
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index ad89c442f29..c22308b93ff 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -276,6 +276,20 @@ void __init mem_init(void)
}
#endif /* !CONFIG_NEED_MULTIPLE_NODES */
+void free_init_pages(char *what, unsigned long begin, unsigned long end)
+{
+ unsigned long addr;
+
+ for (addr = begin; addr < end; addr += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(addr));
+ init_page_count(virt_to_page(addr));
+ memset((void *)addr, 0xcc, PAGE_SIZE);
+ free_page(addr);
+ totalram_pages++;
+ }
+ printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+}
+
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
@@ -284,16 +298,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
start = (unsigned long)phys_to_virt(CPHYSADDR(start));
end = (unsigned long)phys_to_virt(CPHYSADDR(end));
#endif
- if (start < end)
- printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
- (end - start) >> 10);
-
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- }
+ free_init_pages("initrd memory", start, end);
}
#endif
@@ -301,24 +306,17 @@ extern unsigned long prom_free_prom_memory(void);
void free_initmem(void)
{
- unsigned long addr, page, freed;
+ unsigned long start, end, freed;
freed = prom_free_prom_memory();
+ if (freed)
+ printk(KERN_INFO "Freeing firmware memory: %ldk freed\n",freed);
- addr = (unsigned long) &__init_begin;
- while (addr < (unsigned long) &__init_end) {
+ start = (unsigned long)(&__init_begin);
+ end = (unsigned long)(&__init_end);
#ifdef CONFIG_64BIT
- page = PAGE_OFFSET | CPHYSADDR(addr);
-#else
- page = addr;
+ start = PAGE_OFFSET | CPHYSADDR(start);
+ end = PAGE_OFFSET | CPHYSADDR(end);
#endif
- ClearPageReserved(virt_to_page(page));
- init_page_count(virt_to_page(page));
- free_page(page);
- totalram_pages++;
- freed += PAGE_SIZE;
- addr += PAGE_SIZE;
- }
- printk(KERN_INFO "Freeing unused kernel memory: %ldk freed\n",
- freed >> 10);
+ free_init_pages("unused kernel memory", start, end);
}
diff --git a/arch/mips/mm/sc-rm7k.c b/arch/mips/mm/sc-rm7k.c
index 3b6cc9ba1b0..31ec7305242 100644
--- a/arch/mips/mm/sc-rm7k.c
+++ b/arch/mips/mm/sc-rm7k.c
@@ -138,7 +138,7 @@ void __init rm7k_sc_init(void)
c->scache.linesz = sc_lsize;
c->scache.ways = 4;
- c->scache.waybit= ffs(scache_size / c->scache.ways) - 1;
+ c->scache.waybit= __ffs(scache_size / c->scache.ways);
c->scache.waysize = scache_size / c->scache.ways;
c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways);
printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n",
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index a865f2394cb..9dca099ba16 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -32,13 +32,35 @@ extern void build_tlb_refill_handler(void);
"nop; nop; nop; nop; nop; nop;\n\t" \
".set reorder\n\t")
+/* Atomicity and interruptability */
+#ifdef CONFIG_MIPS_MT_SMTC
+
+#include <asm/smtc.h>
+#include <asm/mipsmtregs.h>
+
+#define ENTER_CRITICAL(flags) \
+ { \
+ unsigned int mvpflags; \
+ local_irq_save(flags);\
+ mvpflags = dvpe()
+#define EXIT_CRITICAL(flags) \
+ evpe(mvpflags); \
+ local_irq_restore(flags); \
+ }
+#else
+
+#define ENTER_CRITICAL(flags) local_irq_save(flags)
+#define EXIT_CRITICAL(flags) local_irq_restore(flags)
+
+#endif /* CONFIG_MIPS_MT_SMTC */
+
void local_flush_tlb_all(void)
{
unsigned long flags;
unsigned long old_ctx;
int entry;
- local_irq_save(flags);
+ ENTER_CRITICAL(flags);
/* Save old context and create impossible VPN2 value */
old_ctx = read_c0_entryhi();
write_c0_entrylo0(0);
@@ -57,7 +79,7 @@ void local_flush_tlb_all(void)
}
tlbw_use_hazard();
write_c0_entryhi(old_ctx);
- local_irq_restore(flags);
+ EXIT_CRITICAL(flags);
}
/* All entries common to a mm share an asid. To effectively flush
@@ -87,6 +109,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long flags;
int size;
+ ENTER_CRITICAL(flags);
size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
size = (size + 1) >> 1;
local_irq_save(flags);
@@ -120,7 +143,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
} else {
drop_mmu_context(mm, cpu);
}
- local_irq_restore(flags);
+ EXIT_CRITICAL(flags);
}
}
@@ -129,9 +152,9 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
unsigned long flags;
int size;
+ ENTER_CRITICAL(flags);
size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
size = (size + 1) >> 1;
- local_irq_save(flags);
if (size <= current_cpu_data.tlbsize / 2) {
int pid = read_c0_entryhi();
@@ -162,7 +185,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
} else {
local_flush_tlb_all();
}
- local_irq_restore(flags);
+ EXIT_CRITICAL(flags);
}
void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
@@ -175,7 +198,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
newpid = cpu_asid(cpu, vma->vm_mm);
page &= (PAGE_MASK << 1);
- local_irq_save(flags);
+ ENTER_CRITICAL(flags);
oldpid = read_c0_entryhi();
write_c0_entryhi(page | newpid);
mtc0_tlbw_hazard();
@@ -194,7 +217,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
finish:
write_c0_entryhi(oldpid);
- local_irq_restore(flags);
+ EXIT_CRITICAL(flags);
}
}
@@ -207,7 +230,7 @@ void local_flush_tlb_one(unsigned long page)
unsigned long flags;
int oldpid, idx;
- local_irq_save(flags);
+ ENTER_CRITICAL(flags);
oldpid = read_c0_entryhi();
page &= (PAGE_MASK << 1);
write_c0_entryhi(page);
@@ -226,7 +249,7 @@ void local_flush_tlb_one(unsigned long page)
}
write_c0_entryhi(oldpid);
- local_irq_restore(flags);
+ EXIT_CRITICAL(flags);
}
/*
@@ -249,7 +272,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
if (current->active_mm != vma->vm_mm)
return;
- local_irq_save(flags);
+ ENTER_CRITICAL(flags);
pid = read_c0_entryhi() & ASID_MASK;
address &= (PAGE_MASK << 1);
@@ -277,7 +300,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
else
tlb_write_indexed();
tlbw_use_hazard();
- local_irq_restore(flags);
+ EXIT_CRITICAL(flags);
}
#if 0
@@ -291,7 +314,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma,
pte_t *ptep;
int idx;
- local_irq_save(flags);
+ ENTER_CRITICAL(flags);
address &= (PAGE_MASK << 1);
asid = read_c0_entryhi() & ASID_MASK;
write_c0_entryhi(address | asid);
@@ -310,7 +333,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma,
else
tlb_write_indexed();
tlbw_use_hazard();
- local_irq_restore(flags);
+ EXIT_CRITICAL(flags);
}
#endif
@@ -322,7 +345,7 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
unsigned long old_pagemask;
unsigned long old_ctx;
- local_irq_save(flags);
+ ENTER_CRITICAL(flags);
/* Save old context and create impossible VPN2 value */
old_ctx = read_c0_entryhi();
old_pagemask = read_c0_pagemask();
@@ -342,7 +365,7 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
BARRIER;
write_c0_pagemask(old_pagemask);
local_flush_tlb_all();
- local_irq_restore(flags);
+ EXIT_CRITICAL(flags);
}
/*
@@ -362,7 +385,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
unsigned long old_pagemask;
unsigned long old_ctx;
- local_irq_save(flags);
+ ENTER_CRITICAL(flags);
/* Save old context and create impossible VPN2 value */
old_ctx = read_c0_entryhi();
old_pagemask = read_c0_pagemask();
@@ -386,10 +409,11 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
write_c0_entryhi(old_ctx);
write_c0_pagemask(old_pagemask);
out:
- local_irq_restore(flags);
+ EXIT_CRITICAL(flags);
return ret;
}
+extern void __init sanitize_tlb_entries(void);
static void __init probe_tlb(unsigned long config)
{
struct cpuinfo_mips *c = &current_cpu_data;
@@ -402,6 +426,14 @@ static void __init probe_tlb(unsigned long config)
*/
if ((c->processor_id & 0xff0000) == PRID_COMP_LEGACY)
return;
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * If TLB is shared in SMTC system, total size already
+ * has been calculated and written into cpu_data tlbsize
+ */
+ if((smtc_status & SMTC_TLB_SHARED) == SMTC_TLB_SHARED)
+ return;
+#endif /* CONFIG_MIPS_MT_SMTC */
reg = read_c0_config1();
if (!((config >> 7) & 3))
@@ -410,6 +442,15 @@ static void __init probe_tlb(unsigned long config)
c->tlbsize = ((reg >> 25) & 0x3f) + 1;
}
+static int __initdata ntlb = 0;
+static int __init set_ntlb(char *str)
+{
+ get_option(&str, &ntlb);
+ return 1;
+}
+
+__setup("ntlb=", set_ntlb);
+
void __init tlb_init(void)
{
unsigned int config = read_c0_config();
@@ -432,5 +473,15 @@ void __init tlb_init(void)
/* Did I tell you that ARC SUCKS? */
+ if (ntlb) {
+ if (ntlb > 1 && ntlb <= current_cpu_data.tlbsize) {
+ int wired = current_cpu_data.tlbsize - ntlb;
+ write_c0_wired(wired);
+ write_c0_index(wired-1);
+ printk ("Restricting TLB to %d entries\n", ntlb);
+ } else
+ printk("Ignoring invalid argument ntlb=%d\n", ntlb);
+ }
+
build_tlb_refill_handler();
}
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 599b3c29718..053dbacac56 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -7,6 +7,16 @@
*
* Copyright (C) 2004,2005 by Thiemo Seufer
* Copyright (C) 2005 Maciej W. Rozycki
+ * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ *
+ * ... and the days got worse and worse and now you see
+ * I've gone completly out of my mind.
+ *
+ * They're coming to take me a away haha
+ * they're coming to take me a away hoho hihi haha
+ * to the funny farm where code is beautiful all the time ...
+ *
+ * (Condolences to Napoleon XIV)
*/
#include <stdarg.h>
@@ -68,6 +78,7 @@ enum fields
BIMM = 0x040,
JIMM = 0x080,
FUNC = 0x100,
+ SET = 0x200
};
#define OP_MASK 0x2f
@@ -86,6 +97,8 @@ enum fields
#define JIMM_SH 0
#define FUNC_MASK 0x2f
#define FUNC_SH 0
+#define SET_MASK 0x7
+#define SET_SH 0
enum opcode {
insn_invalid,
@@ -129,8 +142,8 @@ static __initdata struct insn insn_table[] = {
{ insn_bne, M(bne_op,0,0,0,0,0), RS | RT | BIMM },
{ insn_daddiu, M(daddiu_op,0,0,0,0,0), RS | RT | SIMM },
{ insn_daddu, M(spec_op,0,0,0,0,daddu_op), RS | RT | RD },
- { insn_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD },
- { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD },
+ { insn_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD | SET},
+ { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD | SET},
{ insn_dsll, M(spec_op,0,0,0,0,dsll_op), RT | RD | RE },
{ insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE },
{ insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE },
@@ -145,8 +158,8 @@ static __initdata struct insn insn_table[] = {
{ insn_lld, M(lld_op,0,0,0,0,0), RS | RT | SIMM },
{ insn_lui, M(lui_op,0,0,0,0,0), RT | SIMM },
{ insn_lw, M(lw_op,0,0,0,0,0), RS | RT | SIMM },
- { insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD },
- { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD },
+ { insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD | SET},
+ { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD | SET},
{ insn_ori, M(ori_op,0,0,0,0,0), RS | RT | UIMM },
{ insn_rfe, M(cop0_op,cop_op,0,0,0,rfe_op), 0 },
{ insn_sc, M(sc_op,0,0,0,0,0), RS | RT | SIMM },
@@ -242,6 +255,14 @@ static __init u32 build_func(u32 arg)
return arg & FUNC_MASK;
}
+static __init u32 build_set(u32 arg)
+{
+ if (arg & ~SET_MASK)
+ printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+ return arg & SET_MASK;
+}
+
/*
* The order of opcode arguments is implicitly left to right,
* starting with RS and ending with FUNC or IMM.
@@ -273,6 +294,7 @@ static void __init build_insn(u32 **buf, enum opcode opc, ...)
if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32));
if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32));
if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32));
+ if (ip->fields & SET) op |= build_set(va_arg(ap, u32));
va_end(ap);
**buf = op;
@@ -358,8 +380,8 @@ I_u1s2(_bgezl);
I_u1s2(_bltz);
I_u1s2(_bltzl);
I_u1u2s3(_bne);
-I_u1u2(_dmfc0);
-I_u1u2(_dmtc0);
+I_u1u2u3(_dmfc0);
+I_u1u2u3(_dmtc0);
I_u2u1s3(_daddiu);
I_u3u1u2(_daddu);
I_u2u1u3(_dsll);
@@ -376,8 +398,8 @@ I_u2s3u1(_ll);
I_u2s3u1(_lld);
I_u1s2(_lui);
I_u2s3u1(_lw);
-I_u1u2(_mfc0);
-I_u1u2(_mtc0);
+I_u1u2u3(_mfc0);
+I_u1u2u3(_mtc0);
I_u2u1u3(_ori);
I_0(_rfe);
I_u2s3u1(_sc);
@@ -451,8 +473,8 @@ L_LA(_r3000_write_probe_fail)
# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh)
# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh)
-# define i_MFC0(buf, rt, rd) i_dmfc0(buf, rt, rd)
-# define i_MTC0(buf, rt, rd) i_dmtc0(buf, rt, rd)
+# define i_MFC0(buf, rt, rd...) i_dmfc0(buf, rt, rd)
+# define i_MTC0(buf, rt, rd...) i_dmtc0(buf, rt, rd)
# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val)
# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd)
# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd)
@@ -464,8 +486,8 @@ L_LA(_r3000_write_probe_fail)
# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh)
# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh)
# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh)
-# define i_MFC0(buf, rt, rd) i_mfc0(buf, rt, rd)
-# define i_MTC0(buf, rt, rd) i_mtc0(buf, rt, rd)
+# define i_MFC0(buf, rt, rd...) i_mfc0(buf, rt, rd)
+# define i_MTC0(buf, rt, rd...) i_mtc0(buf, rt, rd)
# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val)
# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd)
# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd)
@@ -670,14 +692,15 @@ static void __init il_bgezl(u32 **p, struct reloc **r, unsigned int reg,
#define K1 27
/* Some CP0 registers */
-#define C0_INDEX 0
-#define C0_ENTRYLO0 2
-#define C0_ENTRYLO1 3
-#define C0_CONTEXT 4
-#define C0_BADVADDR 8
-#define C0_ENTRYHI 10
-#define C0_EPC 14
-#define C0_XCONTEXT 20
+#define C0_INDEX 0, 0
+#define C0_ENTRYLO0 2, 0
+#define C0_TCBIND 2, 2
+#define C0_ENTRYLO1 3, 0
+#define C0_CONTEXT 4, 0
+#define C0_BADVADDR 8, 0
+#define C0_ENTRYHI 10, 0
+#define C0_EPC 14, 0
+#define C0_XCONTEXT 20, 0
#ifdef CONFIG_64BIT
# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
@@ -742,7 +765,7 @@ static void __init build_r3000_tlb_refill_handler(void)
}
#endif
- memcpy((void *)CAC_BASE, tlb_handler, 0x80);
+ memcpy((void *)ebase, tlb_handler, 0x80);
}
/*
@@ -951,12 +974,20 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
/* No i_nop needed here, since the next insn doesn't touch TMP. */
#ifdef CONFIG_SMP
+# ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * SMTC uses TCBind value as "CPU" index
+ */
+ i_mfc0(p, ptr, C0_TCBIND);
+ i_dsrl(p, ptr, ptr, 19);
+# else
/*
* 64 bit SMP running in XKPHYS has smp_processor_id() << 3
* stored in CONTEXT.
*/
i_dmfc0(p, ptr, C0_CONTEXT);
i_dsrl(p, ptr, ptr, 23);
+#endif
i_LA_mostly(p, tmp, pgdc);
i_daddu(p, ptr, ptr, tmp);
i_dmfc0(p, tmp, C0_BADVADDR);
@@ -1014,9 +1045,21 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
/* 32 bit SMP has smp_processor_id() stored in CONTEXT. */
#ifdef CONFIG_SMP
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * SMTC uses TCBind value as "CPU" index
+ */
+ i_mfc0(p, ptr, C0_TCBIND);
+ i_LA_mostly(p, tmp, pgdc);
+ i_srl(p, ptr, ptr, 19);
+#else
+ /*
+ * smp_processor_id() << 3 is stored in CONTEXT.
+ */
i_mfc0(p, ptr, C0_CONTEXT);
i_LA_mostly(p, tmp, pgdc);
i_srl(p, ptr, ptr, 23);
+#endif
i_addu(p, ptr, tmp, ptr);
#else
i_LA_mostly(p, ptr, pgdc);
@@ -1247,7 +1290,7 @@ static void __init build_r4000_tlb_refill_handler(void)
}
#endif
- memcpy((void *)CAC_BASE, final_handler, 0x100);
+ memcpy((void *)ebase, final_handler, 0x100);
}
/*
diff --git a/arch/mips/momentum/jaguar_atx/Makefile b/arch/mips/momentum/jaguar_atx/Makefile
index 20bbd3ea44a..67372f3f965 100644
--- a/arch/mips/momentum/jaguar_atx/Makefile
+++ b/arch/mips/momentum/jaguar_atx/Makefile
@@ -6,7 +6,7 @@
# unless it's something special (ie not a .c file).
#
-obj-y += int-handler.o irq.o prom.o reset.o setup.o
+obj-y += irq.o prom.o reset.o setup.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o
obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
diff --git a/arch/mips/momentum/jaguar_atx/int-handler.S b/arch/mips/momentum/jaguar_atx/int-handler.S
deleted file mode 100644
index 55bc789733f..00000000000
--- a/arch/mips/momentum/jaguar_atx/int-handler.S
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2002 Momentum Computer Inc.
- * Author: Matthew Dharm <mdharm@momenco.com>
- *
- * Based on work:
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * First-level interrupt dispatcher for Jaguar-ATX board.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-/*
- * First level interrupt dispatcher for Ocelot-CS board
- */
- .align 5
- NESTED(jaguar_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- mfc0 t0, CP0_CAUSE
- mfc0 t2, CP0_STATUS
-
- and t0, t2
-
- andi t1, t0, STATUSF_IP0 /* sw0 software interrupt */
- bnez t1, ll_sw0_irq
- andi t1, t0, STATUSF_IP1 /* sw1 software interrupt */
- bnez t1, ll_sw1_irq
- andi t1, t0, STATUSF_IP2 /* int0 hardware line */
- bnez t1, ll_pcixa_irq
- andi t1, t0, STATUSF_IP3 /* int1 hardware line */
- bnez t1, ll_pcixb_irq
- andi t1, t0, STATUSF_IP4 /* int2 hardware line */
- bnez t1, ll_pcia_irq
- andi t1, t0, STATUSF_IP5 /* int3 hardware line */
- bnez t1, ll_pcib_irq
- andi t1, t0, STATUSF_IP6 /* int4 hardware line */
- bnez t1, ll_uart_irq
- andi t1, t0, STATUSF_IP7 /* cpu timer */
- bnez t1, ll_cputimer_irq
-
- nop
- nop
-
- /* now look at extended interrupts */
- mfc0 t0, CP0_CAUSE
- cfc0 t1, CP0_S1_INTCONTROL
-
- /* shift the mask 8 bits left to line up the bits */
- sll t2, t1, 8
-
- and t0, t2
- srl t0, t0, 16
-
- andi t1, t0, STATUSF_IP8 /* int6 hardware line */
- bnez t1, ll_mv64340_decode_irq
-
- nop
- nop
-
- .set reorder
-
- /* wrong alarm or masked ... */
- j spurious_interrupt
- nop
- END(jaguar_handle_int)
-
- .align 5
-ll_sw0_irq:
- li a0, 0
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-ll_sw1_irq:
- li a0, 1
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-ll_pcixa_irq:
- li a0, 2
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pcixb_irq:
- li a0, 3
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pcia_irq:
- li a0, 4
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pcib_irq:
- li a0, 5
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_uart_irq:
- li a0, 6
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cputimer_irq:
- li a0, 7
- move a1, sp
- jal ll_timer_interrupt
- j ret_from_irq
-
-ll_mv64340_decode_irq:
- move a0, sp
- jal ll_mv64340_irq
- j ret_from_irq
diff --git a/arch/mips/momentum/jaguar_atx/irq.c b/arch/mips/momentum/jaguar_atx/irq.c
index 15588f91ace..ec4032b38f1 100644
--- a/arch/mips/momentum/jaguar_atx/irq.c
+++ b/arch/mips/momentum/jaguar_atx/irq.c
@@ -10,7 +10,7 @@
* Copyright 2001 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
- * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 2000, 01, 06 Ralf Baechle (ralf@linux-mips.org)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -38,8 +38,37 @@
#include <linux/types.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
+#include <asm/time.h>
-extern asmlinkage void jaguar_handle_int(void);
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP0)
+ do_IRQ(0, regs);
+ else if (pending & STATUSF_IP1)
+ do_IRQ(1, regs);
+ else if (pending & STATUSF_IP2)
+ do_IRQ(2, regs);
+ else if (pending & STATUSF_IP3)
+ do_IRQ(3, regs);
+ else if (pending & STATUSF_IP4)
+ do_IRQ(4, regs);
+ else if (pending & STATUSF_IP5)
+ do_IRQ(5, regs);
+ else if (pending & STATUSF_IP6)
+ do_IRQ(6, regs);
+ else if (pending & STATUSF_IP7)
+ ll_timer_interrupt(7, regs);
+ else {
+ /*
+ * Now look at the extended interrupts
+ */
+ pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
+ if (pending & STATUSF_IP8)
+ ll_mv64340_irq(regs);
+ }
+}
static struct irqaction cascade_mv64340 = {
no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL
@@ -53,8 +82,6 @@ void __init arch_init_irq(void)
*/
clear_c0_status(ST0_IM);
- /* Sets the first-level interrupt dispatcher. */
- set_except_vector(0, jaguar_handle_int);
mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8);
diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c
index 91d9637143d..1379c76845d 100644
--- a/arch/mips/momentum/jaguar_atx/setup.c
+++ b/arch/mips/momentum/jaguar_atx/setup.c
@@ -381,24 +381,24 @@ void __init plat_setup(void)
* shut down ethernet ports, just to be sure our memory doesn't get
* corrupted by random ethernet traffic.
*/
- MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8);
- MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8);
- MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(2), 0xff << 8);
- MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8);
- MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8);
- MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(2), 0xff << 8);
- while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff);
- while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff);
- while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(2)) & 0xff);
- while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff);
- while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff);
- while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(2)) & 0xff);
- MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0),
- MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1);
- MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1),
- MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1);
- MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(2),
- MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(2)) & ~1);
+ MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8);
+ MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8);
+ MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(2), 0xff << 8);
+ MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8);
+ MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8);
+ MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(2), 0xff << 8);
+ while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff);
+ while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff);
+ while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(2)) & 0xff);
+ while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff);
+ while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff);
+ while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(2)) & 0xff);
+ MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0),
+ MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1);
+ MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1),
+ MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1);
+ MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(2),
+ MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(2)) & ~1);
/* Turn off the Bit-Error LED */
JAGUAR_FPGA_WRITE(0x80, CLR);
diff --git a/arch/mips/momentum/ocelot_3/Makefile b/arch/mips/momentum/ocelot_3/Makefile
index aab8fd89f83..8bcea64dd27 100644
--- a/arch/mips/momentum/ocelot_3/Makefile
+++ b/arch/mips/momentum/ocelot_3/Makefile
@@ -5,4 +5,4 @@
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
-obj-y += int-handler.o irq.o prom.o reset.o setup.o
+obj-y += irq.o prom.o reset.o setup.o
diff --git a/arch/mips/momentum/ocelot_3/int-handler.S b/arch/mips/momentum/ocelot_3/int-handler.S
deleted file mode 100644
index 4522f09ed76..00000000000
--- a/arch/mips/momentum/ocelot_3/int-handler.S
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2002 Momentum Computer Inc.
- * Author: Matthew Dharm <mdharm@momenco.com>
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * Copyright 2004 PMC-Sierra
- * Author: Manish Lachwani (lachwani@pmc-sierra.com)
- *
- * Copyright (C) 2004 MontaVista Software Inc.
- * Author: Manish Lachwani, mlachwani@mvista.com
- *
- * First-level interrupt dispatcher for Ocelot-3 board.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-/*
- * First level interrupt dispatcher for Ocelot-3 board
- */
- .align 5
- NESTED(ocelot3_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
-
- mfc0 t0, CP0_CAUSE
- mfc0 t2, CP0_STATUS
-
- and t0, t2
-
- andi t1, t0, STATUSF_IP0 /* sw0 software interrupt (IRQ0) */
- bnez t1, ll_sw0_irq
-
- andi t1, t0, STATUSF_IP1 /* sw1 software interrupt (IRQ1) */
- bnez t1, ll_sw1_irq
-
- andi t1, t0, STATUSF_IP2 /* int0 hardware line (IRQ2) */
- bnez t1, ll_pci0slot1_irq
-
- andi t1, t0, STATUSF_IP3 /* int1 hardware line (IRQ3) */
- bnez t1, ll_pci0slot2_irq
-
- andi t1, t0, STATUSF_IP4 /* int2 hardware line (IRQ4) */
- bnez t1, ll_pci1slot1_irq
-
- andi t1, t0, STATUSF_IP5 /* int3 hardware line (IRQ5) */
- bnez t1, ll_pci1slot2_irq
-
- andi t1, t0, STATUSF_IP6 /* int4 hardware line (IRQ6) */
- bnez t1, ll_uart_irq
-
- andi t1, t0, STATUSF_IP7 /* cpu timer (IRQ7) */
- bnez t1, ll_cputimer_irq
-
- /* now look at extended interrupts */
- mfc0 t0, CP0_CAUSE
- cfc0 t1, CP0_S1_INTCONTROL
-
- /* shift the mask 8 bits left to line up the bits */
- sll t2, t1, 8
-
- and t0, t2
- srl t0, t0, 16
-
- andi t1, t0, STATUSF_IP8 /* int6 hardware line (IRQ9) */
- bnez t1, ll_mv64340_decode_irq
-
- .set reorder
-
- /* wrong alarm or masked ... */
- j spurious_interrupt
- nop
- END(ocelot3_handle_int)
-
- .align 5
-ll_sw0_irq:
- li a0, 0 /* IRQ 1 */
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-ll_sw1_irq:
- li a0, 1 /* IRQ 2 */
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pci0slot1_irq:
- li a0, 2 /* IRQ 3 */
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pci0slot2_irq:
- li a0, 3 /* IRQ 4 */
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pci1slot1_irq:
- li a0, 4 /* IRQ 5 */
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pci1slot2_irq:
- li a0, 5 /* IRQ 6 */
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_uart_irq:
- li a0, 6 /* IRQ 7 */
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cputimer_irq:
- li a0, 7 /* IRQ 8 */
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_mv64340_decode_irq:
- move a0, sp
- jal ll_mv64340_irq
- j ret_from_irq
-
diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c
index 42464dbd4ad..87c63c340ae 100644
--- a/arch/mips/momentum/ocelot_3/irq.c
+++ b/arch/mips/momentum/ocelot_3/irq.c
@@ -53,8 +53,6 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
-extern asmlinkage void ocelot3_handle_int(void);
-
static struct irqaction cascade_mv64340 = {
no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL
};
@@ -67,9 +65,6 @@ void __init arch_init_irq(void)
*/
clear_c0_status(ST0_IM | ST0_BEV);
- /* Sets the first-level interrupt dispatcher. */
- set_except_vector(0, ocelot3_handle_int);
- mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8);
/* set up the cascading interrupts */
@@ -79,3 +74,36 @@ void __init arch_init_irq(void)
set_c0_status(ST0_IM); /* IE in the status register */
}
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP0)
+ do_IRQ(0, regs);
+ else if (pending & STATUSF_IP1)
+ do_IRQ(1, regs);
+ else if (pending & STATUSF_IP2)
+ do_IRQ(2, regs);
+ else if (pending & STATUSF_IP3)
+ do_IRQ(3, regs);
+ else if (pending & STATUSF_IP4)
+ do_IRQ(4, regs);
+ else if (pending & STATUSF_IP5)
+ do_IRQ(5, regs);
+ else if (pending & STATUSF_IP6)
+ do_IRQ(6, regs);
+ else if (pending & STATUSF_IP7)
+ do_IRQ(7, regs);
+ else {
+ /*
+ * Now look at the extended interrupts
+ */
+ pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
+
+ if (pending & STATUSF_IP8)
+ ll_mv64340_irq(regs);
+ else
+ spurious_interrupt(regs);
+ }
+}
diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c
index 370e75d0e75..c6919523430 100644
--- a/arch/mips/momentum/ocelot_3/setup.c
+++ b/arch/mips/momentum/ocelot_3/setup.c
@@ -329,22 +329,22 @@ void __init plat_setup(void)
/* shut down ethernet ports, just to be sure our memory doesn't get
* corrupted by random ethernet traffic.
*/
- MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8);
- MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8);
- MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8);
- MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8);
+ MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8);
+ MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8);
+ MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8);
+ MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8);
do {}
- while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff);
+ while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff);
do {}
- while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff);
+ while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff);
do {}
- while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff);
+ while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff);
do {}
- while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff);
- MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0),
- MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1);
- MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1),
- MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1);
+ while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff);
+ MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0),
+ MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1);
+ MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1),
+ MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1);
/* Turn off the Bit-Error LED */
OCELOT_FPGA_WRITE(0x80, CLR);
diff --git a/arch/mips/momentum/ocelot_c/Makefile b/arch/mips/momentum/ocelot_c/Makefile
index 91240777f97..94802b4db47 100644
--- a/arch/mips/momentum/ocelot_c/Makefile
+++ b/arch/mips/momentum/ocelot_c/Makefile
@@ -2,7 +2,7 @@
# Makefile for Momentum Computer's Ocelot-C and -CS boards.
#
-obj-y += cpci-irq.o int-handler.o irq.o prom.o reset.o \
+obj-y += cpci-irq.o irq.o prom.o reset.o \
setup.o uart-irq.o
obj-$(CONFIG_KGDB) += dbg_io.o
diff --git a/arch/mips/momentum/ocelot_c/int-handler.S b/arch/mips/momentum/ocelot_c/int-handler.S
deleted file mode 100644
index 52349d9bf1b..00000000000
--- a/arch/mips/momentum/ocelot_c/int-handler.S
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2002 Momentum Computer Inc.
- * Author: Matthew Dharm <mdharm@momenco.com>
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * First-level interrupt dispatcher for Ocelot-CS board.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include "ocelot_c_fpga.h"
-
-/*
- * First level interrupt dispatcher for Ocelot-CS board
- */
- .align 5
- NESTED(ocelot_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- mfc0 t0, CP0_CAUSE
- mfc0 t2, CP0_STATUS
-
- and t0, t2
-
- andi t1, t0, STATUSF_IP0 /* sw0 software interrupt */
- bnez t1, ll_sw0_irq
- andi t1, t0, STATUSF_IP1 /* sw1 software interrupt */
- bnez t1, ll_sw1_irq
- andi t1, t0, STATUSF_IP2 /* int0 hardware line */
- bnez t1, ll_scsi_irq
- andi t1, t0, STATUSF_IP3 /* int1 hardware line */
- bnez t1, ll_uart_decode_irq
- andi t1, t0, STATUSF_IP4 /* int2 hardware line */
- bnez t1, ll_pmc_irq
- andi t1, t0, STATUSF_IP5 /* int3 hardware line */
- bnez t1, ll_cpci_decode_irq
- andi t1, t0, STATUSF_IP6 /* int4 hardware line */
- bnez t1, ll_mv64340_decode_irq
- andi t1, t0, STATUSF_IP7 /* cpu timer */
- bnez t1, ll_cputimer_irq
-
- .set reorder
-
- /* wrong alarm or masked ... */
- j spurious_interrupt
- nop
- END(ocelot_handle_int)
-
- .align 5
-ll_sw0_irq:
- li a0, 0
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-ll_sw1_irq:
- li a0, 1
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-ll_scsi_irq:
- li a0, 2
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_uart_decode_irq:
- move a0, sp
- jal ll_uart_irq
- j ret_from_irq
-
-ll_pmc_irq:
- li a0, 4
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpci_decode_irq:
- move a0, sp
- jal ll_cpci_irq
- j ret_from_irq
-
-ll_mv64340_decode_irq:
- move a0, sp
- jal ll_mv64340_irq
- j ret_from_irq
-
-ll_cputimer_irq:
- li a0, 7
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c
index a5764bc20e3..86f61ce59e5 100644
--- a/arch/mips/momentum/ocelot_c/irq.c
+++ b/arch/mips/momentum/ocelot_c/irq.c
@@ -48,7 +48,6 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
-extern asmlinkage void ocelot_handle_int(void);
extern void uart_irq_init(void);
extern void cpci_irq_init(void);
@@ -60,6 +59,33 @@ static struct irqaction cascade_mv64340 = {
no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade via MV64340", NULL, NULL
};
+extern void ll_uart_irq(struct pt_regs *regs);
+extern void ll_cpci_irq(struct pt_regs *regs);
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP0)
+ do_IRQ(0, regs);
+ else if (pending & STATUSF_IP1)
+ do_IRQ(1, regs);
+ else if (pending & STATUSF_IP2)
+ do_IRQ(2, regs);
+ else if (pending & STATUSF_IP3)
+ ll_uart_irq(regs);
+ else if (pending & STATUSF_IP4)
+ do_IRQ(4, regs);
+ else if (pending & STATUSF_IP5)
+ ll_cpci_irq(regs);
+ else if (pending & STATUSF_IP6)
+ ll_mv64340_irq(regs);
+ else if (pending & STATUSF_IP7)
+ do_IRQ(7, regs);
+ else
+ spurious_interrupt(regs);
+}
+
void __init arch_init_irq(void)
{
/*
@@ -68,8 +94,6 @@ void __init arch_init_irq(void)
*/
clear_c0_status(ST0_IM);
- /* Sets the first-level interrupt dispatcher. */
- set_except_vector(0, ocelot_handle_int);
mips_cpu_irq_init(0);
/* set up the cascading interrupts */
diff --git a/arch/mips/momentum/ocelot_g/Makefile b/arch/mips/momentum/ocelot_g/Makefile
index e5f1cb08697..adb5665d40a 100644
--- a/arch/mips/momentum/ocelot_g/Makefile
+++ b/arch/mips/momentum/ocelot_g/Makefile
@@ -2,7 +2,7 @@
# Makefile for Momentum Computer's Ocelot-G board.
#
-obj-y += int-handler.o irq.o gt-irq.o prom.o reset.o setup.o
+obj-y += irq.o gt-irq.o prom.o reset.o setup.o
obj-$(CONFIG_KGDB) += dbg_io.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/momentum/ocelot_g/int-handler.S b/arch/mips/momentum/ocelot_g/int-handler.S
deleted file mode 100644
index 772e8f71317..00000000000
--- a/arch/mips/momentum/ocelot_g/int-handler.S
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * First-level interrupt dispatcher for ocelot board.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-/*
- * first level interrupt dispatcher for ocelot board -
- * We check for the timer first, then check PCI ints A and D.
- * Then check for serial IRQ and fall through.
- */
- .align 5
- NESTED(ocelot_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- mfc0 t0, CP0_CAUSE
- mfc0 t2, CP0_STATUS
-
- and t0, t2
-
- andi t1, t0, STATUSF_IP2 /* int0 hardware line */
- bnez t1, ll_pri_enet_irq
- andi t1, t0, STATUSF_IP3 /* int1 hardware line */
- bnez t1, ll_sec_enet_irq
- andi t1, t0, STATUSF_IP4 /* int2 hardware line */
- bnez t1, ll_uart_irq
- andi t1, t0, STATUSF_IP5 /* int3 hardware line */
- bnez t1, ll_cpci_irq
- andi t1, t0, STATUSF_IP6 /* int4 hardware line */
- bnez t1, ll_galileo_p0_irq
- andi t1, t0, STATUSF_IP7 /* cpu timer */
- bnez t1, ll_cputimer_irq
-
- /* now look at the extended interrupts */
- mfc0 t0, CP0_CAUSE
- cfc0 t1, CP0_S1_INTCONTROL
-
- /* shift the mask 8 bits left to line up the bits */
- sll t2, t1, 8
-
- and t0, t2
- srl t0, t0, 16
-
- andi t1, t0, STATUSF_IP8 /* int6 hardware line */
- bnez t1, ll_galileo_p1_irq
- andi t1, t0, STATUSF_IP9 /* int7 hardware line */
- bnez t1, ll_pmc_irq
- andi t1, t0, STATUSF_IP10 /* int8 hardware line */
- bnez t1, ll_cpci_abcd_irq
- andi t1, t0, STATUSF_IP11 /* int9 hardware line */
- bnez t1, ll_testpoint_irq
-
- .set reorder
-
- /* wrong alarm or masked ... */
- j spurious_interrupt
- nop
- END(ocelot_handle_int)
-
- .align 5
-ll_pri_enet_irq:
- li a0, 2
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_sec_enet_irq:
- li a0, 3
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_uart_irq:
- li a0, 4
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpci_irq:
- li a0, 5
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_galileo_p0_irq:
- li a0, 6
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cputimer_irq:
- li a0, 7
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_galileo_p1_irq:
- li a0, 8
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_pmc_irq:
- li a0, 9
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_cpci_abcd_irq:
- li a0, 10
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_testpoint_irq:
- li a0, 11
- move a1, sp
- jal do_IRQ
- j ret_from_irq
diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c
index 5eb85b16420..7a4a419804f 100644
--- a/arch/mips/momentum/ocelot_g/irq.c
+++ b/arch/mips/momentum/ocelot_g/irq.c
@@ -48,7 +48,41 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
-extern asmlinkage void ocelot_handle_int(void);
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP2)
+ do_IRQ(2, regs);
+ else if (pending & STATUSF_IP3)
+ do_IRQ(3, regs);
+ else if (pending & STATUSF_IP4)
+ do_IRQ(4, regs);
+ else if (pending & STATUSF_IP5)
+ do_IRQ(5, regs);
+ else if (pending & STATUSF_IP6)
+ do_IRQ(6, regs);
+ else if (pending & STATUSF_IP7)
+ do_IRQ(7, regs);
+ else {
+ /*
+ * Now look at the extended interrupts
+ */
+ pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
+
+ if (pending & STATUSF_IP8)
+ do_IRQ(8, regs);
+ else if (pending & STATUSF_IP9)
+ do_IRQ(9, regs);
+ else if (pending & STATUSF_IP10)
+ do_IRQ(10, regs);
+ else if (pending & STATUSF_IP11)
+ do_IRQ(11, regs);
+ else
+ spurious_interrupt(regs);
+ }
+}
+
extern void gt64240_irq_init(void);
void __init arch_init_irq(void)
@@ -60,8 +94,6 @@ void __init arch_init_irq(void)
clear_c0_status(ST0_IM);
local_irq_disable();
- /* Sets the first-level interrupt dispatcher. */
- set_except_vector(0, ocelot_handle_int);
mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8);
diff --git a/arch/mips/philips/pnx8550/common/Makefile b/arch/mips/philips/pnx8550/common/Makefile
index 6e38f3bc443..b7c638166e9 100644
--- a/arch/mips/philips/pnx8550/common/Makefile
+++ b/arch/mips/philips/pnx8550/common/Makefile
@@ -22,6 +22,6 @@
# under Linux.
#
-obj-y := setup.o prom.o mipsIRQ.o int.o reset.o time.o proc.o platform.o
+obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_KGDB) += gdb_hook.o
diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c
index c500e2d41f2..39ee6314f62 100644
--- a/arch/mips/philips/pnx8550/common/int.c
+++ b/arch/mips/philips/pnx8550/common/int.c
@@ -38,8 +38,6 @@
#include <int.h>
#include <uart.h>
-extern asmlinkage void cp0_irqdispatch(void);
-
static DEFINE_SPINLOCK(irq_lock);
/* default prio for interrupts */
@@ -55,7 +53,7 @@ static char gic_prio[PNX8550_INT_GIC_TOTINT] = {
1 // 70
};
-void hw0_irqdispatch(int irq, struct pt_regs *regs)
+static void hw0_irqdispatch(int irq, struct pt_regs *regs)
{
/* find out which interrupt */
irq = PNX8550_GIC_VECTOR_0 >> 3;
@@ -68,7 +66,7 @@ void hw0_irqdispatch(int irq, struct pt_regs *regs)
}
-void timer_irqdispatch(int irq, struct pt_regs *regs)
+static void timer_irqdispatch(int irq, struct pt_regs *regs)
{
irq = (0x01c0 & read_c0_config7()) >> 6;
@@ -88,6 +86,20 @@ void timer_irqdispatch(int irq, struct pt_regs *regs)
}
}
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP2)
+ do_IRQ(2, regs);
+ else if (pending & STATUSF_IP7) {
+ if (read_c0_config7() & 0x01c0)
+ timer_irqdispatch(7, regs);
+ }
+
+ spurious_interrupt(regs);
+}
+
static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
{
unsigned long status = read_c0_status();
@@ -223,9 +235,6 @@ void __init arch_init_irq(void)
int i;
int configPR;
- /* init of cp0 interrupts */
- set_except_vector(0, cp0_irqdispatch);
-
for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) {
irq_desc[i].handler = &level_irq_type;
pnx8550_ack(i); /* mask the irq just in case */
diff --git a/arch/mips/philips/pnx8550/common/mipsIRQ.S b/arch/mips/philips/pnx8550/common/mipsIRQ.S
deleted file mode 100644
index 338bffda3fa..00000000000
--- a/arch/mips/philips/pnx8550/common/mipsIRQ.S
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2002 Philips, Inc. All rights.
- * Copyright (c) 2002 Red Hat, Inc. All rights.
- *
- * This software may be freely redistributed under the terms of the
- * GNU General Public License.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Based upon arch/mips/galileo-boards/ev64240/int-handler.S
- *
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-/*
- * cp0_irqdispatch
- *
- * Code to handle in-core interrupt exception.
- */
-
- .align 5
- .set reorder
- .set noat
- NESTED(cp0_irqdispatch, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- mfc0 t0,CP0_CAUSE
- mfc0 t2,CP0_STATUS
-
- and t0,t2
-
- andi t1,t0,STATUSF_IP2 /* int0 hardware line */
- bnez t1,ll_hw0_irq
- nop
-
- andi t1,t0,STATUSF_IP7 /* int5 hardware line */
- bnez t1,ll_timer_irq
- nop
-
- /* wrong alarm or masked ... */
-
- j spurious_interrupt
- nop
- END(cp0_irqdispatch)
-
- .align 5
- .set reorder
-ll_hw0_irq:
- li a0,2
- move a1,sp
- jal hw0_irqdispatch
- nop
- j ret_from_irq
- nop
-
- .align 5
- .set reorder
-ll_timer_irq:
- mfc0 t3,CP0_CONFIG,7
- andi t4,t3,0x01c0
- beqz t4,ll_timer_out
- nop
- li a0,7
- move a1,sp
- jal timer_irqdispatch
- nop
-
-ll_timer_out: j ret_from_irq
- nop
diff --git a/arch/mips/philips/pnx8550/common/platform.c b/arch/mips/philips/pnx8550/common/platform.c
index a592260fd67..5436b4b9745 100644
--- a/arch/mips/philips/pnx8550/common/platform.c
+++ b/arch/mips/philips/pnx8550/common/platform.c
@@ -18,6 +18,7 @@
#include <linux/resource.h>
#include <linux/serial.h>
#include <linux/serial_ip3106.h>
+#include <linux/platform_device.h>
#include <int.h>
#include <usb.h>
diff --git a/arch/mips/pmc-sierra/yosemite/Makefile b/arch/mips/pmc-sierra/yosemite/Makefile
index ae96a71a308..e931e0d4422 100644
--- a/arch/mips/pmc-sierra/yosemite/Makefile
+++ b/arch/mips/pmc-sierra/yosemite/Makefile
@@ -2,7 +2,7 @@
# Makefile for the PMC-Sierra Titan
#
-obj-y += irq-handler.o irq.o i2c-yosemite.o prom.o py-console.o setup.o
+obj-y += irq.o i2c-yosemite.o prom.o py-console.o setup.o
obj-$(CONFIG_KGDB) += dbg_io.o
obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/mips/pmc-sierra/yosemite/irq-handler.S b/arch/mips/pmc-sierra/yosemite/irq-handler.S
deleted file mode 100644
index 33b9c40d4f5..00000000000
--- a/arch/mips/pmc-sierra/yosemite/irq-handler.S
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2003, 04 PMC-Sierra Inc.
- * Author: Manish Lachwani (lachwani@pmc-sierra.com
- * Copyright 2004 Ralf Baechle (ralf@linux-mips.org)
- *
- * First-level interrupt router for the PMC-Sierra Titan board
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * Titan supports Hypertransport or PCI but not both. Hence, one interrupt
- * line is shared between the PCI slot A and Hypertransport. This is the
- * Processor INTB #0.
- */
-
-#include <linux/config.h>
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
- .align 5
- NESTED(titan_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- .set noreorder
- la ra, ret_from_irq
- mfc0 t0, CP0_CAUSE
- mfc0 t2, CP0_STATUS
-
- and t0, t2
-
- andi t2, t0, STATUSF_IP7 /* INTB5 hardware line */
- bnez t2, ll_timer_irq /* Timer */
- andi t1, t0, STATUSF_IP2 /* INTB0 hardware line */
- bnez t1, ll_pcia_irq /* 64-bit PCI */
- andi t2, t0, STATUSF_IP3 /* INTB1 hardware line */
- bnez t2, ll_pcib_irq /* second 64-bit PCI slot */
- andi t1, t0, STATUSF_IP4 /* INTB2 hardware line */
- bnez t1, ll_duart_irq /* UART */
- andi t2, t0, STATUSF_IP5 /* SMP inter-core interrupts */
- bnez t2, ll_smp_irq
- andi t1, t0, STATUSF_IP6
- bnez t1, ll_ht_irq /* Hypertransport */
-
- move a0, sp
- j do_extended_irq
- END(titan_handle_int)
-
- .set reorder
- .align 5
-
-ll_pcia_irq:
- li a0, 2
- move a1, sp
-#ifdef CONFIG_HYPERTRANSPORT
- j ll_ht_smp_irq_handler
-#else
- j do_IRQ
-#endif
-
-ll_pcib_irq:
- li a0, 3
- move a1, sp
- j do_IRQ
-
-ll_duart_irq:
- li a0, 4
- move a1, sp
- j do_IRQ
-
-ll_smp_irq:
- li a0, 5
- move a1, sp
-#ifdef CONFIG_SMP
- j titan_mailbox_irq
-#else
- j do_IRQ
-#endif
-
-ll_ht_irq:
- li a0, 6
- move a1, sp
- j ll_ht_smp_irq_handler
-
-ll_timer_irq:
- li a0, 7
- move a1, sp
- j do_IRQ
diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c
index f4e2897d9bf..a1f524fc4c1 100644
--- a/arch/mips/pmc-sierra/yosemite/irq.c
+++ b/arch/mips/pmc-sierra/yosemite/irq.c
@@ -2,6 +2,8 @@
* Copyright (C) 2003 PMC-Sierra Inc.
* Author: Manish Lachwani (lachwani@pmc-sierra.com)
*
+ * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
@@ -55,7 +57,6 @@
#define HYPERTRANSPORT_INTC 0x7a /* INTC# */
#define HYPERTRANSPORT_INTD 0x7b /* INTD# */
-extern asmlinkage void titan_handle_int(void);
extern void jaguar_mailbox_irq(struct pt_regs *);
/*
@@ -125,6 +126,35 @@ asmlinkage void do_extended_irq(struct pt_regs *regs)
}
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int cause = read_c0_cause();
+ unsigned int status = read_c0_status();
+ unsigned int pending = cause & status;
+
+ if (pending & STATUSF_IP7) {
+ do_IRQ(7, regs);
+ } else if (pending & STATUSF_IP2) {
+#ifdef CONFIG_HYPERTRANSPORT
+ ll_ht_smp_irq_handler(2, regs);
+#else
+ do_IRQ(2, regs);
+#endif
+ } else if (pending & STATUSF_IP3) {
+ do_IRQ(3, regs);
+ } else if (pending & STATUSF_IP4) {
+ do_IRQ(4, regs);
+ } else if (pending & STATUSF_IP5) {
+#ifdef CONFIG_SMP
+ titan_mailbox_irq(regs);
+#else
+ do_IRQ(5, regs);
+#endif
+ } else if (pending & STATUSF_IP6) {
+ do_IRQ(4, regs);
+ }
+}
+
#ifdef CONFIG_KGDB
extern void init_second_port(void);
#endif
@@ -136,7 +166,6 @@ void __init arch_init_irq(void)
{
clear_c0_status(ST0_IM);
- set_except_vector(0, titan_handle_int);
mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8);
rm9k_cpu_irq_init(12);
diff --git a/arch/mips/qemu/Makefile b/arch/mips/qemu/Makefile
index 6a8e8bcef55..730f459f3e9 100644
--- a/arch/mips/qemu/Makefile
+++ b/arch/mips/qemu/Makefile
@@ -2,6 +2,6 @@
# Makefile for Qemu specific kernel interface routines under Linux.
#
-obj-y = q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o
+obj-y = q-firmware.o q-irq.o q-mem.o q-setup.o
obj-$(CONFIG_SMP) += q-smp.o
diff --git a/arch/mips/qemu/q-int.S b/arch/mips/qemu/q-int.S
deleted file mode 100644
index 6e3dfe5eb14..00000000000
--- a/arch/mips/qemu/q-int.S
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Qemu interrupt handler code.
- *
- * Copyright (C) 2005 by Ralf Baechle
- */
-#include <asm/asm.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
- .align 5
- NESTED(qemu_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- move a0, sp
- PTR_LA ra, ret_from_irq
- j do_qemu_int
- END(qemu_handle_int)
diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c
index 2c4e0704ff1..3352374c4c7 100644
--- a/arch/mips/qemu/q-irq.c
+++ b/arch/mips/qemu/q-irq.c
@@ -9,7 +9,7 @@
extern asmlinkage void qemu_handle_int(void);
-asmlinkage void do_qemu_int(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_status() & read_c0_cause();
@@ -29,7 +29,6 @@ asmlinkage void do_qemu_int(struct pt_regs *regs)
void __init arch_init_irq(void)
{
- set_except_vector(0, qemu_handle_int);
mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK; /* 100MHz */
init_i8259_irqs();
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
index eb0820fe50b..6aa4c0cd169 100644
--- a/arch/mips/sgi-ip22/Makefile
+++ b/arch/mips/sgi-ip22/Makefile
@@ -3,7 +3,7 @@
# under Linux.
#
-obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-irq.o ip22-berr.o \
+obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-berr.o \
ip22-time.o ip22-nvram.o ip22-reset.o ip22-setup.o
obj-$(CONFIG_EISA) += ip22-eisa.o
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index d16fb43b1a9..fc6a7e2b189 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -37,7 +37,6 @@ static char lc1msk_to_irqnr[256];
static char lc2msk_to_irqnr[256];
static char lc3msk_to_irqnr[256];
-extern asmlinkage void indyIRQ(void);
extern int ip22_eisa_init(void);
static void enable_local0_irq(unsigned int irq)
@@ -224,7 +223,7 @@ static struct hw_interrupt_type ip22_local3_irq_type = {
.end = end_local3_irq,
};
-void indy_local0_irqdispatch(struct pt_regs *regs)
+static void indy_local0_irqdispatch(struct pt_regs *regs)
{
u8 mask = sgint->istat0 & sgint->imask0;
u8 mask2;
@@ -242,7 +241,7 @@ void indy_local0_irqdispatch(struct pt_regs *regs)
return;
}
-void indy_local1_irqdispatch(struct pt_regs *regs)
+static void indy_local1_irqdispatch(struct pt_regs *regs)
{
u8 mask = sgint->istat1 & sgint->imask1;
u8 mask2;
@@ -262,7 +261,7 @@ void indy_local1_irqdispatch(struct pt_regs *regs)
extern void ip22_be_interrupt(int irq, struct pt_regs *regs);
-void indy_buserror_irq(struct pt_regs *regs)
+static void indy_buserror_irq(struct pt_regs *regs)
{
int irq = SGI_BUSERR_IRQ;
@@ -307,6 +306,56 @@ static struct irqaction map1_cascade = {
#define SGI_INTERRUPTS SGINT_LOCAL3
#endif
+extern void indy_r4k_timer_interrupt(struct pt_regs *regs);
+extern void indy_8254timer_irq(struct pt_regs *regs);
+
+/*
+ * IRQs on the INDY look basically (barring software IRQs which we don't use
+ * at all) like:
+ *
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Local IRQ level zero
+ * 3 Local IRQ level one
+ * 4 8254 Timer zero
+ * 5 8254 Timer one
+ * 6 Bus Error
+ * 7 R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+ * Local IRQ zero
+ * Local IRQ one
+ * Bus Error
+ * 8254 Timer zero
+ * Lowest ---- 8254 Timer one
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause();
+
+ /*
+ * First we check for r4k counter/timer IRQ.
+ */
+ if (pending & CAUSEF_IP7)
+ indy_r4k_timer_interrupt(regs);
+ else if (pending & CAUSEF_IP2)
+ indy_local0_irqdispatch(regs);
+ else if (pending & CAUSEF_IP3)
+ indy_local1_irqdispatch(regs);
+ else if (pending & CAUSEF_IP6)
+ indy_buserror_irq(regs);
+ else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
+ indy_8254timer_irq(regs);
+}
+
extern void mips_cpu_irq_init(unsigned int irq_base);
void __init arch_init_irq(void)
@@ -369,8 +418,6 @@ void __init arch_init_irq(void)
sgint->cmeimask0 = 0;
sgint->cmeimask1 = 0;
- set_except_vector(0, indyIRQ);
-
/* init CPU irqs */
mips_cpu_irq_init(SGINT_CPU);
diff --git a/arch/mips/sgi-ip22/ip22-irq.S b/arch/mips/sgi-ip22/ip22-irq.S
deleted file mode 100644
index 6ccbd9e1d96..00000000000
--- a/arch/mips/sgi-ip22/ip22-irq.S
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * ip22-irq.S: Interrupt exception dispatch code for FullHouse and
- * Guiness.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- */
-
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-/* A lot of complication here is taken away because:
- *
- * 1) We handle one interrupt and return, sitting in a loop and moving across
- * all the pending IRQ bits in the cause register is _NOT_ the answer, the
- * common case is one pending IRQ so optimize in that direction.
- *
- * 2) We need not check against bits in the status register IRQ mask, that
- * would make this routine slow as hell.
- *
- * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
- * between like BSD spl() brain-damage.
- *
- * Furthermore, the IRQs on the INDY look basically (barring software IRQs
- * which we don't use at all) like:
- *
- * MIPS IRQ Source
- * -------- ------
- * 0 Software (ignored)
- * 1 Software (ignored)
- * 2 Local IRQ level zero
- * 3 Local IRQ level one
- * 4 8254 Timer zero
- * 5 8254 Timer one
- * 6 Bus Error
- * 7 R4k timer (what we use)
- *
- * We handle the IRQ according to _our_ priority which is:
- *
- * Highest ---- R4k Timer
- * Local IRQ zero
- * Local IRQ one
- * Bus Error
- * 8254 Timer zero
- * Lowest ---- 8254 Timer one
- *
- * then we just return, if multiple IRQs are pending then we will just take
- * another exception, big deal.
- */
-
- .text
- .set noreorder
- .set noat
- .align 5
- NESTED(indyIRQ, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
- mfc0 s0, CP0_CAUSE # get irq mask
-
- /* First we check for r4k counter/timer IRQ. */
- andi a0, s0, CAUSEF_IP7
- beq a0, zero, 1f
- andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
-
- /* Wheee, a timer interrupt. */
- jal indy_r4k_timer_interrupt
- move a0, sp # delay slot
- j ret_from_irq
- nop # delay slot
-
-1:
- beq a0, zero, 1f
- andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
-
- /* Wheee, local level zero interrupt. */
- jal indy_local0_irqdispatch
- move a0, sp # delay slot
-
- j ret_from_irq
- nop # delay slot
-
-1:
- beq a0, zero, 1f
- andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
-
- /* Wheee, local level one interrupt. */
- jal indy_local1_irqdispatch
- move a0, sp # delay slot
- j ret_from_irq
- nop # delay slot
-
-1:
- beq a0, zero, 1f
- andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) # delay slot
-
- /* Wheee, an asynchronous bus error... */
- jal indy_buserror_irq
- move a0, sp # delay slot
- j ret_from_irq
- nop # delay slot
-
-1:
- /* Here by mistake? It is possible, that by the time we take
- * the exception the IRQ pin goes low, so just leave if this
- * is the case.
- */
- beq a0, zero, 1f
- nop # delay slot
-
- /* Must be one of the 8254 timers... */
- jal indy_8254timer_irq
- move a0, sp # delay slot
-1:
- j ret_from_irq
- nop # delay slot
- END(indyIRQ)
diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile
index 4ba340780c3..686ba14e288 100644
--- a/arch/mips/sgi-ip27/Makefile
+++ b/arch/mips/sgi-ip27/Makefile
@@ -2,7 +2,7 @@
# Makefile for the IP27 specific kernel interface routines under Linux.
#
-obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \
+obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o \
ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o \
ip27-timer.o ip27-hubio.o ip27-xtalk.o
diff --git a/arch/mips/sgi-ip27/TODO b/arch/mips/sgi-ip27/TODO
index 32106131b0d..19f1512c8f2 100644
--- a/arch/mips/sgi-ip27/TODO
+++ b/arch/mips/sgi-ip27/TODO
@@ -9,10 +9,6 @@ ip27-init.c:find_lbaord_real. DONE
in irix?
6. Investigate why things do not work without the setup_test() call
being invoked on all nodes in ip27-memory.c.
-7. Too many CLIs in the locore handlers :
-For the low level handlers set up by set_except_vector(),
-__tlb_refill_debug_tramp, __xtlb_refill_debug_tramp and cacheerror,
-investigate whether the code should do CLI, STI or KMODE.
8. Too many do_page_faults invoked - investigate.
9. start_thread must turn off UX64 ... and define tlb_refill_debug.
10. Need a bad pmd table, bad pte table. __bad_pmd_table/__bad_pagetable
diff --git a/arch/mips/sgi-ip27/ip27-irq-glue.S b/arch/mips/sgi-ip27/ip27-irq-glue.S
deleted file mode 100644
index c304df715e0..00000000000
--- a/arch/mips/sgi-ip27/ip27-irq-glue.S
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999 Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
- .text
- .align 5
-NESTED(ip27_irq, PT_SIZE, sp)
- SAVE_ALL
- CLI
-
- mfc0 s0, CP0_CAUSE
- mfc0 t0, CP0_STATUS
- and s0, t0
- move a0, sp
- PTR_LA ra, ret_from_irq
-
- /* First check for RT interrupt. */
- andi t0, s0, CAUSEF_IP4
- bnez t0, ip4
- andi t0, s0, CAUSEF_IP2
- bnez t0, ip2
- andi t0, s0, CAUSEF_IP3
- bnez t0, ip3
- andi t0, s0, CAUSEF_IP5
- bnez t0, ip5
- andi t0, s0, CAUSEF_IP6
- bnez t0, ip6
- j ra
-
-ip2: j ip27_do_irq_mask0 # PI_INT_PEND_0 or CC_PEND_{A|B}
-ip3: j ip27_do_irq_mask1 # PI_INT_PEND_1
-ip4: j ip27_rt_timer_interrupt
-ip5: j ip27_prof_timer
-ip6: j ip27_hub_error
-
- END(ip27_irq)
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 2854ac4c9be..2e643d2f51c 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -130,7 +130,7 @@ static int ms1bit(unsigned long x)
* Kanoj 05.13.00
*/
-void ip27_do_irq_mask0(struct pt_regs *regs)
+static void ip27_do_irq_mask0(struct pt_regs *regs)
{
int irq, swlevel;
hubreg_t pend0, mask0;
@@ -171,7 +171,7 @@ void ip27_do_irq_mask0(struct pt_regs *regs)
LOCAL_HUB_L(PI_INT_PEND0);
}
-void ip27_do_irq_mask1(struct pt_regs *regs)
+static void ip27_do_irq_mask1(struct pt_regs *regs)
{
int irq, swlevel;
hubreg_t pend1, mask1;
@@ -196,12 +196,12 @@ void ip27_do_irq_mask1(struct pt_regs *regs)
LOCAL_HUB_L(PI_INT_PEND1);
}
-void ip27_prof_timer(struct pt_regs *regs)
+static void ip27_prof_timer(struct pt_regs *regs)
{
panic("CPU %d got a profiling interrupt", smp_processor_id());
}
-void ip27_hub_error(struct pt_regs *regs)
+static void ip27_hub_error(struct pt_regs *regs)
{
panic("CPU %d got a hub error interrupt", smp_processor_id());
}
@@ -421,9 +421,26 @@ int __devinit request_bridge_irq(struct bridge_controller *bc)
return irq;
}
+extern void ip27_rt_timer_interrupt(struct pt_regs *regs);
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned long pending = read_c0_cause() & read_c0_status();
+
+ if (pending & CAUSEF_IP4)
+ ip27_rt_timer_interrupt(regs);
+ else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */
+ ip27_do_irq_mask0(regs);
+ else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */
+ ip27_do_irq_mask1(regs);
+ else if (pending & CAUSEF_IP5)
+ ip27_prof_timer(regs);
+ else if (pending & CAUSEF_IP6)
+ ip27_hub_error(regs);
+}
+
void __init arch_init_irq(void)
{
- set_except_vector(0, ip27_irq);
}
void install_ipi(void)
diff --git a/arch/mips/sgi-ip32/Makefile b/arch/mips/sgi-ip32/Makefile
index 470898f4afe..530bf848c3d 100644
--- a/arch/mips/sgi-ip32/Makefile
+++ b/arch/mips/sgi-ip32/Makefile
@@ -3,7 +3,7 @@
# under Linux.
#
-obj-y += ip32-berr.o ip32-irq.o ip32-irq-glue.o ip32-setup.o ip32-reset.o \
+obj-y += ip32-berr.o ip32-irq.o ip32-setup.o ip32-reset.o \
crime.o ip32-memory.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/sgi-ip32/ip32-irq-glue.S b/arch/mips/sgi-ip32/ip32-irq-glue.S
deleted file mode 100644
index 200924e1c4f..00000000000
--- a/arch/mips/sgi-ip32/ip32-irq-glue.S
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Low level interrupt handler for the SGI O2 aka IP32 aka Moosehead
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000 Harald Koerfgen
- * Copyright (C) 2001 Keith M Wesolowski
- */
-#include <asm/asm.h>
-#include <asm/regdef.h>
-#include <asm/mipsregs.h>
-#include <asm/stackframe.h>
-#include <asm/addrspace.h>
-
- .text
- .set noreorder
- .set noat
- .align 5
- NESTED(ip32_handle_int, PT_SIZE, ra)
- .set noat
- SAVE_ALL
- CLI # TEST: interrupts should be off
- .set at
- .set noreorder
-
- mfc0 s0,CP0_CAUSE
-
- andi t1, s0, IE_IRQ0
- bnez t1, handle_irq0
- andi t1, s0, IE_IRQ1
- bnez t1, handle_irq1
- andi t1, s0, IE_IRQ2
- bnez t1, handle_irq2
- andi t1, s0, IE_IRQ3
- bnez t1, handle_irq3
- andi t1, s0, IE_IRQ4
- bnez t1, handle_irq4
- andi t1, s0, IE_IRQ5
- bnez t1, handle_irq5
- nop
-
- /* Either someone has triggered the "software interrupts"
- * or we lost an interrupt somehow. Ignore it.
- */
- j ret_from_irq
- nop
-
-handle_irq0:
- jal ip32_irq0
- move a0, sp
- j ret_from_irq
- nop
-
-handle_irq1:
- jal ip32_irq1
- move a0, sp
- j ret_from_irq
- nop
-
-handle_irq2:
- jal ip32_irq2
- move a0, sp
- j ret_from_irq
- nop
-
-handle_irq3:
- jal ip32_irq3
- move a0, sp
- j ret_from_irq
- nop
-
-handle_irq4:
- jal ip32_irq4
- move a0, sp
- j ret_from_irq
- nop
-
-handle_irq5:
- jal ip32_irq5
- move a0, sp
- j ret_from_irq
- nop
-
- END(ip32_handle_int)
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
index 2eb22d692ed..22a6df94b4a 100644
--- a/arch/mips/sgi-ip32/ip32-irq.c
+++ b/arch/mips/sgi-ip32/ip32-irq.c
@@ -130,8 +130,6 @@ struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT,
struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT,
CPU_MASK_NONE, "CRIME CPU error", NULL, NULL };
-extern void ip32_handle_int(void);
-
/*
* For interrupts wired from a single device to the CPU. Only the clock
* uses this it seems, which is IRQ 0 and IP7.
@@ -503,7 +501,7 @@ static void ip32_unknown_interrupt(struct pt_regs *regs)
/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
/* change this to loop over all edge-triggered irqs, exception masked out ones */
-void ip32_irq0(struct pt_regs *regs)
+static void ip32_irq0(struct pt_regs *regs)
{
uint64_t crime_int;
int irq = 0;
@@ -520,31 +518,49 @@ void ip32_irq0(struct pt_regs *regs)
do_IRQ(irq, regs);
}
-void ip32_irq1(struct pt_regs *regs)
+static void ip32_irq1(struct pt_regs *regs)
{
ip32_unknown_interrupt(regs);
}
-void ip32_irq2(struct pt_regs *regs)
+static void ip32_irq2(struct pt_regs *regs)
{
ip32_unknown_interrupt(regs);
}
-void ip32_irq3(struct pt_regs *regs)
+static void ip32_irq3(struct pt_regs *regs)
{
ip32_unknown_interrupt(regs);
}
-void ip32_irq4(struct pt_regs *regs)
+static void ip32_irq4(struct pt_regs *regs)
{
ip32_unknown_interrupt(regs);
}
-void ip32_irq5(struct pt_regs *regs)
+static void ip32_irq5(struct pt_regs *regs)
{
ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs);
}
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause();
+
+ if (likely(pending & IE_IRQ0))
+ ip32_irq0(regs);
+ else if (unlikely(pending & IE_IRQ1))
+ ip32_irq1(regs);
+ else if (unlikely(pending & IE_IRQ2))
+ ip32_irq2(regs);
+ else if (unlikely(pending & IE_IRQ3))
+ ip32_irq3(regs);
+ else if (unlikely(pending & IE_IRQ4))
+ ip32_irq4(regs);
+ else if (likely(pending & IE_IRQ5))
+ ip32_irq5(regs);
+}
+
void __init arch_init_irq(void)
{
unsigned int irq;
@@ -556,7 +572,6 @@ void __init arch_init_irq(void)
crime->soft_int = 0;
mace->perif.ctrl.istat = 0;
mace->perif.ctrl.imask = 0;
- set_except_vector(0, ip32_handle_int);
for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
hw_irq_controller *controller;
diff --git a/arch/mips/sibyte/bcm1480/Makefile b/arch/mips/sibyte/bcm1480/Makefile
index 538d5a51ae9..7b36ff3873b 100644
--- a/arch/mips/sibyte/bcm1480/Makefile
+++ b/arch/mips/sibyte/bcm1480/Makefile
@@ -1,4 +1,4 @@
-obj-y := setup.o irq.o irq_handler.o time.o
+obj-y := setup.o irq.o time.o
obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index 9cf7d713b13..e61760b14d9 100644
--- a/arch/mips/sibyte/bcm1480/irq.c
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -187,9 +187,6 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask)
#endif
-/* Defined in arch/mips/sibyte/bcm1480/irq_handler.S */
-extern void bcm1480_irq_handler(void);
-
/*****************************************************************************/
static unsigned int startup_bcm1480_irq(unsigned int irq)
@@ -422,7 +419,6 @@ void __init arch_init_irq(void)
#endif
/* Enable necessary IPs, disable the rest */
change_c0_status(ST0_IM, imask);
- set_except_vector(0, bcm1480_irq_handler);
#ifdef CONFIG_KGDB
if (kgdb_flag) {
@@ -473,3 +469,76 @@ void bcm1480_kgdb_interrupt(struct pt_regs *regs)
}
#endif /* CONFIG_KGDB */
+
+static inline int dclz(unsigned long long x)
+{
+ int lz;
+
+ __asm__ (
+ " .set push \n"
+ " .set mips64 \n"
+ " dclz %0, %1 \n"
+ " .set pop \n"
+ : "=r" (lz)
+ : "r" (x));
+
+ return lz;
+}
+
+extern void bcm1480_timer_interrupt(struct pt_regs *regs);
+extern void bcm1480_mailbox_interrupt(struct pt_regs *regs);
+extern void bcm1480_kgdb_interrupt(struct pt_regs *regs);
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending;
+
+#ifdef CONFIG_SIBYTE_BCM1480_PROF
+ /* Set compare to count to silence count/compare timer interrupts */
+ write_c0_compare(read_c0_count());
+#endif
+
+ pending = read_c0_cause();
+
+#ifdef CONFIG_SIBYTE_BCM1480_PROF
+ if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */
+ sbprof_cpu_intr(exception_epc(regs));
+#endif
+
+ if (pending & CAUSEF_IP4)
+ bcm1480_timer_interrupt(regs);
+
+#ifdef CONFIG_SMP
+ if (pending & CAUSEF_IP3)
+ bcm1480_mailbox_interrupt(regs);
+#endif
+
+#ifdef CONFIG_KGDB
+ if (pending & CAUSEF_IP6)
+ bcm1480_kgdb_interrupt(regs); /* KGDB (uart 1) */
+#endif
+
+ if (pending & CAUSEF_IP2) {
+ unsigned long long mask_h, mask_l;
+ unsigned long base;
+
+ /*
+ * Default...we've hit an IP[2] interrupt, which means we've
+ * got to check the 1480 interrupt registers to figure out what
+ * to do. Need to detect which CPU we're on, now that
+ * smp_affinity is supported.
+ */
+ base = A_BCM1480_IMR_MAPPER(smp_processor_id());
+ mask_h = __raw_readq(
+ IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
+ mask_l = __raw_readq(
+ IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
+
+ if (!mask_h) {
+ if (mask_h ^ 1)
+ do_IRQ(63 - dclz(mask_h), regs);
+ else
+ do_IRQ(127 - dclz(mask_l), regs);
+ }
+ }
+}
diff --git a/arch/mips/sibyte/bcm1480/irq_handler.S b/arch/mips/sibyte/bcm1480/irq_handler.S
deleted file mode 100644
index 408db88d050..00000000000
--- a/arch/mips/sibyte/bcm1480/irq_handler.S
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * bcm1480_irq_handler() is the routine that is actually called when an
- * interrupt occurs. It is installed as the exception vector handler in
- * init_IRQ() in arch/mips/sibyte/bcm1480/irq.c
- *
- * In the handle we figure out which interrupts need handling, and use that
- * to call the dispatcher, which will take care of actually calling
- * registered handlers
- *
- * Note that we take care of all raised interrupts in one go at the handler.
- * This is more BSDish than the Indy code, and also, IMHO, more sane.
- */
-#include <linux/config.h>
-
-#include <asm/addrspace.h>
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include <asm/sibyte/sb1250_defs.h>
-#include <asm/sibyte/bcm1480_regs.h>
-#include <asm/sibyte/bcm1480_int.h>
-
-/*
- * What a pain. We have to be really careful saving the upper 32 bits of any
- * register across function calls if we don't want them trashed--since were
- * running in -o32, the calling routing never saves the full 64 bits of a
- * register across a function call. Being the interrupt handler, we're
- * guaranteed that interrupts are disabled during this code so we don't have
- * to worry about random interrupts blasting the high 32 bits.
- */
-
- .text
- .set push
- .set noreorder
- .set noat
- .set mips64
- #.set mips4
- .align 5
- NESTED(bcm1480_irq_handler, PT_SIZE, sp)
- SAVE_ALL
- CLI
-
-#ifdef CONFIG_SIBYTE_BCM1480_PROF
- /* Set compare to count to silence count/compare timer interrupts */
- mfc0 t1, CP0_COUNT
- mtc0 t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */
-#endif
- /* Read cause */
- mfc0 s0, CP0_CAUSE
-
-#ifdef CONFIG_SIBYTE_BCM1480_PROF
- /* Cpu performance counter interrupt is routed to IP[7] */
- andi t1, s0, CAUSEF_IP7
- beqz t1, 0f
- srl t1, s0, (CAUSEB_BD-2) /* Shift BD bit to bit 2 */
- and t1, t1, 0x4 /* mask to get just BD bit */
-#ifdef CONFIG_MIPS64
- dmfc0 a0, CP0_EPC
- daddu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
-#else
- mfc0 a0, CP0_EPC
- addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
-#endif
- jal sbprof_cpu_intr
- nop
- j ret_from_irq
- nop
-0:
-#endif
-
- /* Timer interrupt is routed to IP[4] */
- andi t1, s0, CAUSEF_IP4
- beqz t1, 1f
- nop
- jal bcm1480_timer_interrupt
- move a0, sp /* Pass the registers along */
- j ret_from_irq
- nop /* delay slot */
-1:
-
-#ifdef CONFIG_SMP
- /* Mailbox interrupt is routed to IP[3] */
- andi t1, s0, CAUSEF_IP3
- beqz t1, 2f
- nop
- jal bcm1480_mailbox_interrupt
- move a0, sp
- j ret_from_irq
- nop /* delay slot */
-2:
-#endif
-
-#ifdef CONFIG_KGDB
- /* KGDB (uart 1) interrupt is routed to IP[6] */
- andi t1, s0, CAUSEF_IP6
- beqz t1, 3f
- nop /* delay slot */
- jal bcm1480_kgdb_interrupt
- move a0, sp
- j ret_from_irq
- nop /* delay slot */
-3:
-#endif
-
- and t1, s0, CAUSEF_IP2
- beqz t1, 9f
- nop
-
- /*
- * Default...we've hit an IP[2] interrupt, which means we've got
- * to check the 1480 interrupt registers to figure out what to do
- * Need to detect which CPU we're on, now that smp_affinity is
- * supported.
- */
- PTR_LA v0, CKSEG1 + A_BCM1480_IMR_CPU0_BASE
-#ifdef CONFIG_SMP
- lw t1, TI_CPU($28)
- sll t1, t1, BCM1480_IMR_REGISTER_SPACING_SHIFT
- addu v0, v0, t1
-#endif
-
- /* Read IP[2] status (get both high and low halves of status) */
- ld s0, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H(v0)
- ld s1, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L(v0)
-
- move s2, zero /* intr number */
- li s3, 64
-
- beqz s0, 9f /* No interrupts. Return. */
- move a1, sp
-
- xori s4, s0, 1 /* if s0 (_H) == 1, it's a low intr, so... */
- movz s2, s3, s4 /* start the intr number at 64, and */
- movz s0, s1, s4 /* look at the low status value. */
-
- dclz s1, s0 /* Find the next interrupt. */
- dsubu a0, zero, s1
- daddiu a0, a0, 63
- jal do_IRQ
- daddu a0, a0, s2
-
-9: j ret_from_irq
- nop
-
- .set pop
- END(bcm1480_irq_handler)
diff --git a/arch/mips/sibyte/sb1250/Makefile b/arch/mips/sibyte/sb1250/Makefile
index a8af8469758..a2fdbd62f8a 100644
--- a/arch/mips/sibyte/sb1250/Makefile
+++ b/arch/mips/sibyte/sb1250/Makefile
@@ -1,4 +1,4 @@
-obj-y := setup.o irq.o irq_handler.o time.o
+obj-y := setup.o irq.o time.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index 589537bfcc3..0f6e54db488 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -163,10 +163,6 @@ static void sb1250_set_affinity(unsigned int irq, cpumask_t mask)
}
#endif
-
-/* Defined in arch/mips/sibyte/sb1250/irq_handler.S */
-extern void sb1250_irq_handler(void);
-
/*****************************************************************************/
static unsigned int startup_sb1250_irq(unsigned int irq)
@@ -379,7 +375,6 @@ void __init arch_init_irq(void)
#endif
/* Enable necessary IPs, disable the rest */
change_c0_status(ST0_IM, imask);
- set_except_vector(0, sb1250_irq_handler);
#ifdef CONFIG_KGDB
if (kgdb_flag) {
@@ -409,7 +404,7 @@ void __init arch_init_irq(void)
#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
-void sb1250_kgdb_interrupt(struct pt_regs *regs)
+static void sb1250_kgdb_interrupt(struct pt_regs *regs)
{
/*
* Clear break-change status (allow some time for the remote
@@ -424,3 +419,74 @@ void sb1250_kgdb_interrupt(struct pt_regs *regs)
}
#endif /* CONFIG_KGDB */
+
+static inline int dclz(unsigned long long x)
+{
+ int lz;
+
+ __asm__ (
+ " .set push \n"
+ " .set mips64 \n"
+ " dclz %0, %1 \n"
+ " .set pop \n"
+ : "=r" (lz)
+ : "r" (x));
+
+ return lz;
+}
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending;
+
+#ifdef CONFIG_SIBYTE_SB1250_PROF
+ /* Set compare to count to silence count/compare timer interrupts */
+ write_c0_count(read_c0_count());
+#endif
+
+ /*
+ * What a pain. We have to be really careful saving the upper 32 bits
+ * of any * register across function calls if we don't want them
+ * trashed--since were running in -o32, the calling routing never saves
+ * the full 64 bits of a register across a function call. Being the
+ * interrupt handler, we're guaranteed that interrupts are disabled
+ * during this code so we don't have to worry about random interrupts
+ * blasting the high 32 bits.
+ */
+
+ pending = read_c0_cause();
+
+#ifdef CONFIG_SIBYTE_SB1250_PROF
+ if (pending & CAUSEF_IP7) { /* Cpu performance counter interrupt */
+ sbprof_cpu_intr(exception_epc(regs));
+ }
+#endif
+
+ if (pending & CAUSEF_IP4)
+ sb1250_timer_interrupt(regs);
+
+#ifdef CONFIG_SMP
+ if (pending & CAUSEF_IP3)
+ sb1250_mailbox_interrupt(regs);
+#endif
+
+#ifdef CONFIG_KGDB
+ if (pending & CAUSEF_IP6) /* KGDB (uart 1) */
+ sb1250_kgdb_interrupt(regs);
+#endif
+
+ if (pending & CAUSEF_IP2) {
+ unsigned long long mask;
+
+ /*
+ * Default...we've hit an IP[2] interrupt, which means we've
+ * got to check the 1250 interrupt registers to figure out what
+ * to do. Need to detect which CPU we're on, now that
+ ~ smp_affinity is supported.
+ */
+ mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
+ R_IMR_INTERRUPT_STATUS_BASE)));
+ if (mask)
+ do_IRQ(63 - dclz(mask), regs);
+ }
+}
diff --git a/arch/mips/sibyte/sb1250/irq_handler.S b/arch/mips/sibyte/sb1250/irq_handler.S
deleted file mode 100644
index 60edc8fb302..00000000000
--- a/arch/mips/sibyte/sb1250/irq_handler.S
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * sb1250_handle_int() is the routine that is actually called when an interrupt
- * occurs. It is installed as the exception vector handler in arch_init_irq()
- * in arch/mips/sibyte/sb1250/irq.c
- *
- * In the handle we figure out which interrupts need handling, and use that to
- * call the dispatcher, which will take care of actually calling registered
- * handlers
- *
- * Note that we take care of all raised interrupts in one go at the handler.
- * This is more BSDish than the Indy code, and also, IMHO, more sane.
- */
-#include <linux/config.h>
-
-#include <asm/addrspace.h>
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include <asm/sibyte/sb1250_defs.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_int.h>
-
-/*
- * What a pain. We have to be really careful saving the upper 32 bits of any
- * register across function calls if we don't want them trashed--since were
- * running in -o32, the calling routing never saves the full 64 bits of a
- * register across a function call. Being the interrupt handler, we're
- * guaranteed that interrupts are disabled during this code so we don't have
- * to worry about random interrupts blasting the high 32 bits.
- */
-
- .text
- .set push
- .set noreorder
- .set noat
- .set mips64
- .align 5
- NESTED(sb1250_irq_handler, PT_SIZE, sp)
- SAVE_ALL
- CLI
-
-#ifdef CONFIG_SIBYTE_SB1250_PROF
- /* Set compare to count to silence count/compare timer interrupts */
- mfc0 t1, CP0_COUNT
- mtc0 t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */
-#endif
- /* Read cause */
- mfc0 s0, CP0_CAUSE
-
-#ifdef CONFIG_SIBYTE_SB1250_PROF
- /* Cpu performance counter interrupt is routed to IP[7] */
- andi t1, s0, CAUSEF_IP7
- beqz t1, 0f
- srl t1, s0, (CAUSEB_BD-2) /* Shift BD bit to bit 2 */
- and t1, t1, 0x4 /* mask to get just BD bit */
- mfc0 a0, CP0_EPC
- jal sbprof_cpu_intr
- addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
- j ret_from_irq
- nop
-0:
-#endif
-
- /* Timer interrupt is routed to IP[4] */
- andi t1, s0, CAUSEF_IP4
- beqz t1, 1f
- nop
- jal sb1250_timer_interrupt
- move a0, sp /* Pass the registers along */
- j ret_from_irq
- nop # delay slot
-1:
-
-#ifdef CONFIG_SMP
- /* Mailbox interrupt is routed to IP[3] */
- andi t1, s0, CAUSEF_IP3
- beqz t1, 2f
- nop
- jal sb1250_mailbox_interrupt
- move a0, sp
- j ret_from_irq
- nop # delay slot
-2:
-#endif
-
-#ifdef CONFIG_KGDB
- /* KGDB (uart 1) interrupt is routed to IP[6] */
- andi t1, s0, CAUSEF_IP6
- beqz t1, 1f
- nop # delay slot
- jal sb1250_kgdb_interrupt
- move a0, sp
- j ret_from_irq
- nop # delay slot
-1:
-#endif
-
- and t1, s0, CAUSEF_IP2
- beqz t1, 4f
- nop
-
- /*
- * Default...we've hit an IP[2] interrupt, which means we've got to
- * check the 1250 interrupt registers to figure out what to do
- * Need to detect which CPU we're on, now that smp_affinity is supported.
- */
- PTR_LA v0, CKSEG1 + A_IMR_CPU0_BASE
-#ifdef CONFIG_SMP
- lw t1, TI_CPU($28)
- sll t1, IMR_REGISTER_SPACING_SHIFT
- addu v0, t1
-#endif
- ld s0, R_IMR_INTERRUPT_STATUS_BASE(v0) /* read IP[2] status */
-
- beqz s0, 4f /* No interrupts. Return */
- move a1, sp
-
-3: dclz s1, s0 /* Find the next interrupt */
- dsubu a0, zero, s1
- daddiu a0, a0, 63
- jal do_IRQ
- nop
-
-4: j ret_from_irq
- nop
-
- .set pop
- END(sb1250_irq_handler)
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
index 1e5676e4be8..9c7eaa5fb21 100644
--- a/arch/mips/sni/Makefile
+++ b/arch/mips/sni/Makefile
@@ -2,6 +2,6 @@
# Makefile for the SNI specific part of the kernel
#
-obj-y += int-handler.o irq.o pcimt_scache.o reset.o setup.o
+obj-y += irq.o pcimt_scache.o reset.o setup.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/sni/int-handler.S b/arch/mips/sni/int-handler.S
deleted file mode 100644
index 2cdc09f55f1..00000000000
--- a/arch/mips/sni/int-handler.S
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * SNI RM200 PCI specific interrupt handler code.
- *
- * Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000, 01 by Ralf Baechle
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/sni.h>
-#include <asm/stackframe.h>
-
-/*
- * The PCI ASIC has the nasty property that it may delay writes if it is busy.
- * As a consequence from writes that have not graduated when we exit from the
- * interrupt handler we might catch a spurious interrupt. To avoid this we
- * force the PCI ASIC to graduate all writes by executing a read from the
- * PCI bus.
- */
- .set noreorder
- .set noat
- .align 5
- NESTED(sni_rm200_pci_handle_int, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
-
- /* Blinken light ... */
- lb t0, led_cache
- addiu t0, 1
- sb t0, led_cache
- sb t0, PCIMT_CSLED # write only register
- .data
-led_cache: .byte 0
- .text
-
- mfc0 t0, CP0_STATUS
- mfc0 t1, CP0_CAUSE
- and t0, t1
-
- andi t1, t0, 0x0800 # hardware interrupt 1
- bnez t1, _hwint1
- andi t1, t0, 0x4000 # hardware interrupt 4
- bnez t1, _hwint4
- andi t1, t0, 0x2000 # hardware interrupt 3
- bnez t1, _hwint3
- andi t1, t0, 0x1000 # hardware interrupt 2
- bnez t1, _hwint2
- andi t1, t0, 0x8000 # hardware interrupt 5
- bnez t1, _hwint5
- andi t1, t0, 0x0400 # hardware interrupt 0
- bnez t1, _hwint0
- nop
-
- j restore_all # spurious interrupt
- nop
-
- ##############################################################################
-
-/* hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
- button interrupts. */
-_hwint0: jal pciasic_hwint0
- move a0, sp
- j ret_from_irq
- nop
-
-/*
- * hwint 1 deals with EISA and SCSI interrupts
- */
-_hwint1: jal pciasic_hwint1
- move a0, sp
- j ret_from_irq
- nop
-
-
-/*
- * This interrupt was used for the com1 console on the first prototypes;
- * it's unsed otherwise
- */
-_hwint2: jal pciasic_hwint2
- move a0, sp
- j ret_from_irq
- nop
-
-/*
- * hwint 3 are the PCI interrupts A - D
- */
-_hwint3: jal pciasic_hwint3
- move a0, sp
- j ret_from_irq
- nop
-
-/*
- * hwint 4 is used for only the onboard PCnet 32.
- */
-_hwint4: jal pciasic_hwint4
- move a0, sp
- j ret_from_irq
- nop
-
-/* hwint5 is the r4k count / compare interrupt */
-_hwint5: jal pciasic_hwint5
- move a0, sp
- j ret_from_irq
- nop
-
- END(sni_rm200_pci_handle_int)
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index 952038aa4b9..7365b4853dd 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -19,8 +19,6 @@
DEFINE_SPINLOCK(pciasic_lock);
-extern asmlinkage void sni_rm200_pci_handle_int(void);
-
static void enable_pciasic_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
@@ -71,20 +69,20 @@ static struct hw_interrupt_type pciasic_irq_type = {
* hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
* button interrupts. Later ...
*/
-void pciasic_hwint0(struct pt_regs *regs)
+static void pciasic_hwint0(struct pt_regs *regs)
{
panic("Received int0 but no handler yet ...");
}
/* This interrupt was used for the com1 console on the first prototypes. */
-void pciasic_hwint2(struct pt_regs *regs)
+static void pciasic_hwint2(struct pt_regs *regs)
{
/* I think this shouldn't happen on production machines. */
panic("hwint2 and no handler yet");
}
/* hwint5 is the r4k count / compare interrupt */
-void pciasic_hwint5(struct pt_regs *regs)
+static void pciasic_hwint5(struct pt_regs *regs)
{
panic("hwint5 and no handler yet");
}
@@ -105,7 +103,7 @@ static unsigned int ls1bit8(unsigned int x)
*
* The EISA_INT bit in CSITPEND is high active, all others are low active.
*/
-void pciasic_hwint1(struct pt_regs *regs)
+static void pciasic_hwint1(struct pt_regs *regs)
{
u8 pend = *(volatile char *)PCIMT_CSITPEND;
unsigned long flags;
@@ -135,7 +133,7 @@ void pciasic_hwint1(struct pt_regs *regs)
/*
* hwint 3 should deal with the PCI A - D interrupts,
*/
-void pciasic_hwint3(struct pt_regs *regs)
+static void pciasic_hwint3(struct pt_regs *regs)
{
u8 pend = *(volatile char *)PCIMT_CSITPEND;
int irq;
@@ -150,13 +148,34 @@ void pciasic_hwint3(struct pt_regs *regs)
/*
* hwint 4 is used for only the onboard PCnet 32.
*/
-void pciasic_hwint4(struct pt_regs *regs)
+static void pciasic_hwint4(struct pt_regs *regs)
{
clear_c0_status(IE_IRQ4);
do_IRQ(PCIMT_IRQ_ETHERNET, regs);
set_c0_status(IE_IRQ4);
}
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause();
+ static unsigned char led_cache;
+
+ *(volatile unsigned char *) PCIMT_CSLED = ++led_cache;
+
+ if (pending & 0x0800)
+ pciasic_hwint1(regs);
+ else if (pending & 0x4000)
+ pciasic_hwint4(regs);
+ else if (pending & 0x2000)
+ pciasic_hwint3(regs);
+ else if (pending & 0x1000)
+ pciasic_hwint2(regs);
+ else if (pending & 0x8000)
+ pciasic_hwint5(regs);
+ else if (pending & 0x0400)
+ pciasic_hwint0(regs);
+}
+
void __init init_pciasic(void)
{
unsigned long flags;
@@ -176,8 +195,6 @@ void __init arch_init_irq(void)
{
int i;
- set_except_vector(0, sni_rm200_pci_handle_int);
-
init_i8259_irqs(); /* Integrated i8259 */
init_pciasic();
diff --git a/arch/mips/tx4927/common/Makefile b/arch/mips/tx4927/common/Makefile
index 8fa126b296e..9cb9535ebac 100644
--- a/arch/mips/tx4927/common/Makefile
+++ b/arch/mips/tx4927/common/Makefile
@@ -6,7 +6,7 @@
# unless it's something special (ie not a .c file).
#
-obj-y += tx4927_prom.o tx4927_setup.o tx4927_irq.o tx4927_irq_handler.o
+obj-y += tx4927_prom.o tx4927_setup.o tx4927_irq.o
obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o
obj-$(CONFIG_KGDB) += tx4927_dbgio.o
diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c
index 5ab2e2b7601..8ca68015cf4 100644
--- a/arch/mips/tx4927/common/tx4927_irq.c
+++ b/arch/mips/tx4927/common/tx4927_irq.c
@@ -525,8 +525,6 @@ static void tx4927_irq_pic_end(unsigned int irq)
*/
void __init tx4927_irq_init(void)
{
- extern asmlinkage void tx4927_irq_handler(void);
-
TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "-\n");
TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_cp0_init()\n");
@@ -535,16 +533,12 @@ void __init tx4927_irq_init(void)
TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_pic_init()\n");
tx4927_irq_pic_init();
- TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT,
- "=Calling set_except_vector(tx4927_irq_handler)\n");
- set_except_vector(0, tx4927_irq_handler);
-
TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "+\n");
return;
}
-int tx4927_irq_nested(void)
+static int tx4927_irq_nested(void)
{
int sw_irq = 0;
u32 level2;
@@ -582,3 +576,25 @@ int tx4927_irq_nested(void)
return (sw_irq);
}
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & STATUSF_IP7) /* cpu timer */
+ do_IRQ(TX4927_IRQ_CPU_TIMER, regs);
+ else if (pending & STATUSF_IP2) { /* tx4927 pic */
+ unsigned int irq = tx4927_irq_nested();
+
+ if (unlikely(irq == 0)) {
+ spurious_interrupt(regs);
+ return;
+ }
+ do_IRQ(irq, regs);
+ } else if (pending & STATUSF_IP0) /* user line 0 */
+ do_IRQ(TX4927_IRQ_USER0, regs);
+ else if (pending & STATUSF_IP1) /* user line 1 */
+ do_IRQ(TX4927_IRQ_USER1, regs);
+ else
+ spurious_interrupt(regs);
+}
diff --git a/arch/mips/tx4927/common/tx4927_irq_handler.S b/arch/mips/tx4927/common/tx4927_irq_handler.S
deleted file mode 100644
index dd3ceda9d71..00000000000
--- a/arch/mips/tx4927/common/tx4927_irq_handler.S
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * linux/arch/mips/tx4927/common/tx4927_irq_handler.S
- *
- * Primary interrupt handler for tx4927 based systems
- *
- * Author: MontaVista Software, Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- * source@mvista.com
- *
- * Copyright 2001-2002 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include <asm/tx4927/tx4927.h>
-
- .align 5
- NESTED(tx4927_irq_handler, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
-
- mfc0 t0, CP0_CAUSE
- mfc0 t1, CP0_STATUS
- and t0, t1
-
- andi t1, t0, STATUSF_IP7 /* cpu timer */
- bnez t1, ll_ip7
-
- /* IP6..IP3 multiplexed -- do not use */
-
- andi t1, t0, STATUSF_IP2 /* tx4927 pic */
- bnez t1, ll_ip2
-
- andi t1, t0, STATUSF_IP0 /* user line 0 */
- bnez t1, ll_ip0
-
- andi t1, t0, STATUSF_IP1 /* user line 1 */
- bnez t1, ll_ip1
-
- .set reorder
-
- /* wrong alarm or masked ... */
- j spurious_interrupt
- nop
- END(tx4927_irq_handler)
-
- .align 5
-
-
-ll_ip7:
- li a0, TX4927_IRQ_CPU_TIMER
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_ip2:
- jal tx4927_irq_nested
- nop
- beqz v0, goto_spurious_interrupt
- nop
- move a0, v0
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-goto_spurious_interrupt:
- j spurious_interrupt
- nop
-
-ll_ip1:
- li a0, TX4927_IRQ_USER1
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_ip0:
- li a0, TX4927_IRQ_USER0
- move a1, sp
- jal do_IRQ
- j ret_from_irq
diff --git a/arch/mips/tx4938/common/Makefile b/arch/mips/tx4938/common/Makefile
index 74c95c5bcdb..2033ae77f63 100644
--- a/arch/mips/tx4938/common/Makefile
+++ b/arch/mips/tx4938/common/Makefile
@@ -6,6 +6,6 @@
# unless it's something special (ie not a .c file).
#
-obj-y += prom.o setup.o irq.o irq_handler.o rtc_rx5c348.o
+obj-y += prom.o setup.o irq.o rtc_rx5c348.o
obj-$(CONFIG_KGDB) += dbgio.o
diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c
index 4f90d7faf63..873805178d8 100644
--- a/arch/mips/tx4938/common/irq.c
+++ b/arch/mips/tx4938/common/irq.c
@@ -392,11 +392,8 @@ tx4938_irq_pic_end(unsigned int irq)
void __init
tx4938_irq_init(void)
{
- extern asmlinkage void tx4938_irq_handler(void);
-
tx4938_irq_cp0_init();
tx4938_irq_pic_init();
- set_except_vector(0, tx4938_irq_handler);
return;
}
@@ -422,3 +419,21 @@ tx4938_irq_nested(void)
wbflush();
return (sw_irq);
}
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status();
+
+ if (pending & STATUSF_IP7)
+ do_IRQ(TX4938_IRQ_CPU_TIMER, regs);
+ else if (pending & STATUSF_IP2) {
+ int irq = tx4938_irq_nested();
+ if (irq)
+ do_IRQ(irq, regs);
+ else
+ spurious_interrupt(regs);
+ } else if (pending & STATUSF_IP1)
+ do_IRQ(TX4938_IRQ_USER1, regs);
+ else if (pending & STATUSF_IP0)
+ do_IRQ(TX4938_IRQ_USER0, regs);
+}
diff --git a/arch/mips/tx4938/common/irq_handler.S b/arch/mips/tx4938/common/irq_handler.S
deleted file mode 100644
index 1b2f72bac42..00000000000
--- a/arch/mips/tx4938/common/irq_handler.S
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * linux/arch/mips/tx4938/common/handler.S
- *
- * Primary interrupt handler for tx4938 based systems
- * Copyright (C) 2000-2001 Toshiba Corporation
- *
- * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is
- * licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
- */
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include <asm/tx4938/rbtx4938.h>
-
-
- .align 5
- NESTED(tx4938_irq_handler, PT_SIZE, sp)
- SAVE_ALL
- CLI
- .set at
-
- mfc0 t0, CP0_CAUSE
- mfc0 t1, CP0_STATUS
- and t0, t1
-
- andi t1, t0, STATUSF_IP7 /* cpu timer */
- bnez t1, ll_ip7
-
- /* IP6..IP3 multiplexed -- do not use */
-
- andi t1, t0, STATUSF_IP2 /* tx4938 pic */
- bnez t1, ll_ip2
-
- andi t1, t0, STATUSF_IP1 /* user line 1 */
- bnez t1, ll_ip1
-
- andi t1, t0, STATUSF_IP0 /* user line 0 */
- bnez t1, ll_ip0
-
- .set reorder
-
- nop
- END(tx4938_irq_handler)
-
- .align 5
-
-
-ll_ip7:
- li a0, TX4938_IRQ_CPU_TIMER
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-
-ll_ip2:
- jal tx4938_irq_nested
- nop
- beqz v0, goto_spurious_interrupt
- nop
- move a0, v0
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-goto_spurious_interrupt:
- j ret_from_irq
-
-ll_ip1:
- li a0, TX4938_IRQ_USER1
- move a1, sp
- jal do_IRQ
- j ret_from_irq
-
-ll_ip0:
- li a0, TX4938_IRQ_USER0
- move a1, sp
- jal do_IRQ
- j ret_from_irq
diff --git a/arch/mips/vr41xx/Kconfig b/arch/mips/vr41xx/Kconfig
index a7add16c9aa..055a2cdfc84 100644
--- a/arch/mips/vr41xx/Kconfig
+++ b/arch/mips/vr41xx/Kconfig
@@ -4,6 +4,8 @@ config CASIO_E55
select DMA_NONCOHERENT
select IRQ_CPU
select ISA
+ select SYS_HAS_CPU_VR41XX
+ select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
config IBM_WORKPAD
@@ -12,6 +14,8 @@ config IBM_WORKPAD
select DMA_NONCOHERENT
select IRQ_CPU
select ISA
+ select SYS_HAS_CPU_VR41XX
+ select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
config NEC_CMBVR4133
@@ -21,6 +25,9 @@ config NEC_CMBVR4133
select DMA_NONCOHERENT
select IRQ_CPU
select HW_HAS_PCI
+ select SYS_HAS_CPU_VR41XX
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
config ROCKHOPPER
bool "Support for Rockhopper baseboard"
@@ -34,6 +41,8 @@ config TANBAC_TB022X
select DMA_NONCOHERENT
select HW_HAS_PCI
select IRQ_CPU
+ select SYS_HAS_CPU_VR41XX
+ select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
help
The TANBAC VR4131 multichip module(TB0225) and
@@ -65,6 +74,8 @@ config VICTOR_MPC30X
select DMA_NONCOHERENT
select HW_HAS_PCI
select IRQ_CPU
+ select SYS_HAS_CPU_VR41XX
+ select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
config ZAO_CAPCELLA
@@ -73,6 +84,8 @@ config ZAO_CAPCELLA
select DMA_NONCOHERENT
select HW_HAS_PCI
select IRQ_CPU
+ select SYS_HAS_CPU_VR41XX
+ select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
config PCI_VR41XX
diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile
index 9096302a7ec..aa373974c80 100644
--- a/arch/mips/vr41xx/common/Makefile
+++ b/arch/mips/vr41xx/common/Makefile
@@ -2,7 +2,7 @@
# Makefile for common code of the NEC VR4100 series.
#
-obj-y += bcu.o cmu.o icu.o init.o int-handler.o irq.o pmu.o type.o
+obj-y += bcu.o cmu.o icu.o init.o irq.o pmu.o type.o
obj-$(CONFIG_VRC4173) += vrc4173.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/vr41xx/common/int-handler.S b/arch/mips/vr41xx/common/int-handler.S
deleted file mode 100644
index 2b6043f16d0..00000000000
--- a/arch/mips/vr41xx/common/int-handler.S
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * FILE NAME
- * arch/mips/vr41xx/common/int-handler.S
- *
- * BRIEF MODULE DESCRIPTION
- * Interrupt dispatcher for the NEC VR4100 series.
- *
- * Author: Yoichi Yuasa
- * yyuasa@mvista.com or source@mvista.com
- *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/*
- * Changes:
- * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
- * - New creation, NEC VR4100 series are supported.
- *
- * Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
- * - Coped with INTASSIGN of NEC VR4133.
- */
-#include <asm/asm.h>
-#include <asm/regdef.h>
-#include <asm/mipsregs.h>
-#include <asm/stackframe.h>
-
- .text
- .set noreorder
-
- .align 5
- NESTED(vr41xx_handle_interrupt, PT_SIZE, ra)
- .set noat
- SAVE_ALL
- CLI
- .set at
- .set noreorder
-
- /*
- * Get the pending interrupts
- */
- mfc0 t0, CP0_CAUSE
- mfc0 t1, CP0_STATUS
- andi t0, 0xff00
- and t0, t0, t1
-
- andi t1, t0, CAUSEF_IP7 # MIPS timer interrupt
- bnez t1, handle_irq
- li a0, 7
-
- andi t1, t0, 0x7800 # check for Int1-4
- beqz t1, 1f
-
- andi t1, t0, CAUSEF_IP3 # check for Int1
- bnez t1, handle_int
- li a0, 3
-
- andi t1, t0, CAUSEF_IP4 # check for Int2
- bnez t1, handle_int
- li a0, 4
-
- andi t1, t0, CAUSEF_IP5 # check for Int3
- bnez t1, handle_int
- li a0, 5
-
- andi t1, t0, CAUSEF_IP6 # check for Int4
- bnez t1, handle_int
- li a0, 6
-
-1:
- andi t1, t0, CAUSEF_IP2 # check for Int0
- bnez t1, handle_int
- li a0, 2
-
- andi t1, t0, CAUSEF_IP0 # check for IP0
- bnez t1, handle_irq
- li a0, 0
-
- andi t1, t0, CAUSEF_IP1 # check for IP1
- bnez t1, handle_irq
- li a0, 1
-
- j spurious_interrupt
- nop
-
-handle_int:
- jal irq_dispatch
- move a1, sp
- j ret_from_irq
- nop
-
-handle_irq:
- jal do_IRQ
- move a1, sp
- j ret_from_irq
- END(vr41xx_handle_interrupt)
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
index 61aa264275f..86796bb63c3 100644
--- a/arch/mips/vr41xx/common/irq.c
+++ b/arch/mips/vr41xx/common/irq.c
@@ -59,7 +59,7 @@ int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *)
EXPORT_SYMBOL_GPL(cascade_irq);
-asmlinkage void irq_dispatch(unsigned int irq, struct pt_regs *regs)
+static void irq_dispatch(unsigned int irq, struct pt_regs *regs)
{
irq_cascade_t *cascade;
irq_desc_t *desc;
@@ -84,11 +84,32 @@ asmlinkage void irq_dispatch(unsigned int irq, struct pt_regs *regs)
do_IRQ(irq, regs);
}
-extern asmlinkage void vr41xx_handle_interrupt(void);
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+ if (pending & CAUSEF_IP7)
+ do_IRQ(7, regs);
+ else if (pending & 0x7800) {
+ if (pending & CAUSEF_IP3)
+ irq_dispatch(3, regs);
+ else if (pending & CAUSEF_IP4)
+ irq_dispatch(4, regs);
+ else if (pending & CAUSEF_IP5)
+ irq_dispatch(5, regs);
+ else if (pending & CAUSEF_IP6)
+ irq_dispatch(6, regs);
+ } else if (pending & CAUSEF_IP2)
+ irq_dispatch(2, regs);
+ else if (pending & CAUSEF_IP0)
+ do_IRQ(0, regs);
+ else if (pending & CAUSEF_IP1)
+ do_IRQ(1, regs);
+ else
+ spurious_interrupt(regs);
+}
void __init arch_init_irq(void)
{
mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
-
- set_except_vector(0, vr41xx_handle_interrupt);
}