aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-04-18 22:49:42 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-04-18 22:49:42 -0400
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 7aec60d40420..87f0b79c6b15 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -816,6 +816,10 @@ config GENERIC_CALIBRATE_DELAY
816 bool 816 bool
817 default y 817 default y
818 818
819config SCHED_NO_NO_OMIT_FRAME_POINTER
820 bool
821 default y
822
819# 823#
820# Select some configuration options automatically based on user selections. 824# Select some configuration options automatically based on user selections.
821# 825#
@@ -1443,6 +1447,10 @@ choice
1443 prompt "MIPS MT options" 1447 prompt "MIPS MT options"
1444 depends on MIPS_MT 1448 depends on MIPS_MT
1445 1449
1450config MIPS_MT_SMTC
1451 bool "SMTC: Use all TCs on all VPEs for SMP"
1452 select SMP
1453
1446config MIPS_MT_SMP 1454config MIPS_MT_SMP
1447 bool "Use 1 TC on each available VPE for SMP" 1455 bool "Use 1 TC on each available VPE for SMP"
1448 select SMP 1456 select SMP
@@ -1456,6 +1464,11 @@ config MIPS_VPE_LOADER
1456 1464
1457endchoice 1465endchoice
1458 1466
1467config MIPS_MT_FPAFF
1468 bool "Dynamic FPU affinity for FP-intensive threads"
1469 depends on MIPS_MT
1470 default y
1471
1459config MIPS_VPE_LOADER_TOM 1472config MIPS_VPE_LOADER_TOM
1460 bool "Load VPE program into memory hidden from linux" 1473 bool "Load VPE program into memory hidden from linux"
1461 depends on MIPS_VPE_LOADER 1474 depends on MIPS_VPE_LOADER
@@ -1472,6 +1485,16 @@ config MIPS_VPE_APSP_API
1472 depends on MIPS_VPE_LOADER 1485 depends on MIPS_VPE_LOADER
1473 help 1486 help
1474 1487
1488config MIPS_APSP_KSPD
1489 bool "Enable KSPD"
1490 depends on MIPS_VPE_APSP_API
1491 default y
1492 help
1493 KSPD is a kernel daemon that accepts syscall requests from the SP
1494 side, actions them and returns the results. It also handles the
1495 "exit" syscall notifying other kernel modules the SP program is
1496 exiting. You probably want to say yes here.
1497
1475config SB1_PASS_1_WORKAROUNDS 1498config SB1_PASS_1_WORKAROUNDS
1476 bool 1499 bool
1477 depends on CPU_SB1_PASS_1 1500 depends on CPU_SB1_PASS_1
@@ -1599,7 +1622,7 @@ source "mm/Kconfig"
1599 1622
1600config SMP 1623config SMP
1601 bool "Multi-Processing support" 1624 bool "Multi-Processing support"
1602 depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250 || QEMU) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP 1625 depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250 || QEMU) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP || MIPS_MT_SMTC
1603 ---help--- 1626 ---help---
1604 This enables support for systems with more than one CPU. If you have 1627 This enables support for systems with more than one CPU. If you have
1605 a system with only one CPU, like most personal computers, say N. If 1628 a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 9a69e0f0ab76..69b9c1b8fafc 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -105,18 +105,18 @@ cflags-$(CONFIG_CPU_R4300) += -march=r4300 -Wa,--trap
105cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap 105cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap
106cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap 106cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap
107cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap 107cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
108cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips2 -mtune=r4600) \ 108cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
109 -Wa,-mips32 -Wa,--trap 109 -Wa,-mips32 -Wa,--trap
110cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips2 -mtune=r4600) \ 110cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
111 -Wa,-mips32r2 -Wa,--trap 111 -Wa,-mips32r2 -Wa,--trap
112cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips2 -mtune=r4600) \ 112cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
113 -Wa,-mips64 -Wa,--trap 113 -Wa,-mips64 -Wa,--trap
114cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips2 -mtune=r4600 ) \ 114cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
115 -Wa,-mips64r2 -Wa,--trap 115 -Wa,-mips64r2 -Wa,--trap
116cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap 116cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap
117cflags-$(CONFIG_CPU_R5432) += $(call cc-options,-march=r5400,-march=r5000) \ 117cflags-$(CONFIG_CPU_R5432) += $(call cc-option,-march=r5400,-march=r5000) \
118 -Wa,--trap 118 -Wa,--trap
119cflags-$(CONFIG_CPU_NEVADA) += $(call cc-options,-march=rm5200,-march=r5000) \ 119cflags-$(CONFIG_CPU_NEVADA) += $(call cc-option,-march=rm5200,-march=r5000) \
120 -Wa,--trap 120 -Wa,--trap
121cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=r5000) \ 121cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=r5000) \
122 -Wa,--trap 122 -Wa,--trap
diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile
index a1edfd1f643c..bf682f50b859 100644
--- a/arch/mips/au1000/common/Makefile
+++ b/arch/mips/au1000/common/Makefile
@@ -6,7 +6,7 @@
6# Makefile for the Alchemy Au1000 CPU, generic files. 6# Makefile for the Alchemy Au1000 CPU, generic files.
7# 7#
8 8
9obj-y += prom.o int-handler.o irq.o puts.o time.o reset.o \ 9obj-y += prom.o irq.o puts.o time.o reset.o \
10 au1xxx_irqmap.o clocks.o platform.o power.o setup.o \ 10 au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
11 sleeper.o cputable.o dma.o dbdma.o gpio.o 11 sleeper.o cputable.o dma.o dbdma.o gpio.o
12 12
diff --git a/arch/mips/au1000/common/int-handler.S b/arch/mips/au1000/common/int-handler.S
deleted file mode 100644
index 1c4ca883321e..000000000000
--- a/arch/mips/au1000/common/int-handler.S
+++ /dev/null
@@ -1,68 +0,0 @@
1/*
2 * Copyright 2001 MontaVista Software Inc.
3 * Author: ppopov@mvista.com
4 *
5 * Interrupt dispatcher for Au1000 boards.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12#include <asm/asm.h>
13#include <asm/mipsregs.h>
14#include <asm/addrspace.h>
15#include <asm/regdef.h>
16#include <asm/stackframe.h>
17
18 .text
19 .set macro
20 .set noat
21 .align 5
22
23NESTED(au1000_IRQ, PT_SIZE, sp)
24 SAVE_ALL
25 CLI # Important: mark KERNEL mode !
26
27 mfc0 t0,CP0_CAUSE # get pending interrupts
28 mfc0 t1,CP0_STATUS # get enabled interrupts
29 and t0,t1 # isolate allowed ones
30
31 andi t0,0xff00 # isolate pending bits
32 beqz t0, 3f # spurious interrupt
33
34 andi a0, t0, CAUSEF_IP7
35 beq a0, zero, 1f
36 move a0, sp
37 jal mips_timer_interrupt
38 j ret_from_irq
39
401:
41 andi a0, t0, CAUSEF_IP2 # Interrupt Controller 0, Request 0
42 beq a0, zero, 2f
43 move a0,sp
44 jal intc0_req0_irqdispatch
45 j ret_from_irq
462:
47 andi a0, t0, CAUSEF_IP3 # Interrupt Controller 0, Request 1
48 beq a0, zero, 3f
49 move a0,sp
50 jal intc0_req1_irqdispatch
51 j ret_from_irq
523:
53 andi a0, t0, CAUSEF_IP4 # Interrupt Controller 1, Request 0
54 beq a0, zero, 4f
55 move a0,sp
56 jal intc1_req0_irqdispatch
57 j ret_from_irq
584:
59 andi a0, t0, CAUSEF_IP5 # Interrupt Controller 1, Request 1
60 beq a0, zero, 5f
61 move a0, sp
62 jal intc1_req1_irqdispatch
63 j ret_from_irq
64
655:
66 move a0, sp
67 j spurious_interrupt
68END(au1000_IRQ)
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index 1339a0979f66..da61de776154 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -66,7 +66,6 @@
66#define EXT_INTC1_REQ1 5 /* IP 5 */ 66#define EXT_INTC1_REQ1 5 /* IP 5 */
67#define MIPS_TIMER_IP 7 /* IP 7 */ 67#define MIPS_TIMER_IP 7 /* IP 7 */
68 68
69extern asmlinkage void au1000_IRQ(void);
70extern void set_debug_traps(void); 69extern void set_debug_traps(void);
71extern irq_cpustat_t irq_stat [NR_CPUS]; 70extern irq_cpustat_t irq_stat [NR_CPUS];
72 71
@@ -446,7 +445,6 @@ void __init arch_init_irq(void)
446 extern int au1xxx_ic0_nr_irqs; 445 extern int au1xxx_ic0_nr_irqs;
447 446
448 cp0_status = read_c0_status(); 447 cp0_status = read_c0_status();
449 set_except_vector(0, au1000_IRQ);
450 448
451 /* Initialize interrupt controllers to a safe state. 449 /* Initialize interrupt controllers to a safe state.
452 */ 450 */
@@ -661,3 +659,21 @@ restore_au1xxx_intctl(void)
661 au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync(); 659 au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync();
662} 660}
663#endif /* CONFIG_PM */ 661#endif /* CONFIG_PM */
662
663asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
664{
665 unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
666
667 if (pending & CAUSEF_IP7)
668 mips_timer_interrupt(regs);
669 else if (pending & CAUSEF_IP2)
670 intc0_req0_irqdispatch(regs);
671 else if (pending & CAUSEF_IP3)
672 intc0_req1_irqdispatch(regs);
673 else if (pending & CAUSEF_IP4)
674 intc1_req0_irqdispatch(regs);
675 else if (pending & CAUSEF_IP5)
676 intc1_req1_irqdispatch(regs);
677 else
678 spurious_interrupt(regs);
679}
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
index 720e757b2b64..225ac8f34ccd 100644
--- a/arch/mips/cobalt/Makefile
+++ b/arch/mips/cobalt/Makefile
@@ -2,7 +2,7 @@
2# Makefile for the Cobalt micro systems family specific parts of the kernel 2# Makefile for the Cobalt micro systems family specific parts of the kernel
3# 3#
4 4
5obj-y := irq.o int-handler.o reset.o setup.o 5obj-y := irq.o reset.o setup.o
6 6
7obj-$(CONFIG_EARLY_PRINTK) += console.o 7obj-$(CONFIG_EARLY_PRINTK) += console.o
8 8
diff --git a/arch/mips/cobalt/int-handler.S b/arch/mips/cobalt/int-handler.S
deleted file mode 100644
index e75d5e3ca868..000000000000
--- a/arch/mips/cobalt/int-handler.S
+++ /dev/null
@@ -1,25 +0,0 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
7 * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
8 */
9#include <asm/asm.h>
10#include <asm/mipsregs.h>
11#include <asm/mach-cobalt/cobalt.h>
12#include <asm/regdef.h>
13#include <asm/stackframe.h>
14
15 .text
16 .align 5
17 NESTED(cobalt_handle_int, PT_SIZE, sp)
18 SAVE_ALL
19 CLI
20
21 PTR_LA ra, ret_from_irq
22 move a0, sp
23 j cobalt_irq
24
25 END(cobalt_handle_int)
diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c
index f9a108820d6e..0b75f4fb7195 100644
--- a/arch/mips/cobalt/irq.c
+++ b/arch/mips/cobalt/irq.c
@@ -20,8 +20,6 @@
20 20
21#include <asm/mach-cobalt/cobalt.h> 21#include <asm/mach-cobalt/cobalt.h>
22 22
23extern void cobalt_handle_int(void);
24
25/* 23/*
26 * We have two types of interrupts that we handle, ones that come in through 24 * We have two types of interrupts that we handle, ones that come in through
27 * the CPU interrupt lines, and ones that come in on the via chip. The CPU 25 * 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)
79 do_IRQ(irq, regs); 77 do_IRQ(irq, regs);
80} 78}
81 79
82asmlinkage void cobalt_irq(struct pt_regs *regs) 80asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
83{ 81{
84 unsigned pending; 82 unsigned pending;
85 83
@@ -122,8 +120,6 @@ void __init arch_init_irq(void)
122 */ 120 */
123 GALILEO_OUTL(0, GT_INTRMASK_OFS); 121 GALILEO_OUTL(0, GT_INTRMASK_OFS);
124 122
125 set_except_vector(0, cobalt_handle_int);
126
127 init_i8259_irqs(); /* 0 ... 15 */ 123 init_i8259_irqs(); /* 0 ... 15 */
128 mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */ 124 mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */
129 125
diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig
new file mode 100644
index 000000000000..8a1e3ace0b2c
--- /dev/null
+++ b/arch/mips/configs/tb0287_defconfig
@@ -0,0 +1,1096 @@
1#
2# Automatically generated make config: don't edit
3# Linux kernel version: 2.6.16
4# Wed Mar 22 11:07:34 2006
5#
6CONFIG_MIPS=y
7
8#
9# Machine selection
10#
11# CONFIG_MIPS_MTX1 is not set
12# CONFIG_MIPS_BOSPORUS is not set
13# CONFIG_MIPS_PB1000 is not set
14# CONFIG_MIPS_PB1100 is not set
15# CONFIG_MIPS_PB1500 is not set
16# CONFIG_MIPS_PB1550 is not set
17# CONFIG_MIPS_PB1200 is not set
18# CONFIG_MIPS_DB1000 is not set
19# CONFIG_MIPS_DB1100 is not set
20# CONFIG_MIPS_DB1500 is not set
21# CONFIG_MIPS_DB1550 is not set
22# CONFIG_MIPS_DB1200 is not set
23# CONFIG_MIPS_MIRAGE is not set
24# CONFIG_MIPS_COBALT is not set
25# CONFIG_MACH_DECSTATION is not set
26# CONFIG_MIPS_EV64120 is not set
27# CONFIG_MIPS_EV96100 is not set
28# CONFIG_MIPS_IVR is not set
29# CONFIG_MIPS_ITE8172 is not set
30# CONFIG_MACH_JAZZ is not set
31# CONFIG_LASAT is not set
32# CONFIG_MIPS_ATLAS is not set
33# CONFIG_MIPS_MALTA is not set
34# CONFIG_MIPS_SEAD is not set
35# CONFIG_MIPS_SIM is not set
36# CONFIG_MOMENCO_JAGUAR_ATX is not set
37# CONFIG_MOMENCO_OCELOT is not set
38# CONFIG_MOMENCO_OCELOT_3 is not set
39# CONFIG_MOMENCO_OCELOT_C is not set
40# CONFIG_MOMENCO_OCELOT_G is not set
41# CONFIG_MIPS_XXS1500 is not set
42# CONFIG_PNX8550_V2PCI is not set
43# CONFIG_PNX8550_JBS is not set
44# CONFIG_DDB5074 is not set
45# CONFIG_DDB5476 is not set
46# CONFIG_DDB5477 is not set
47CONFIG_MACH_VR41XX=y
48# CONFIG_PMC_YOSEMITE is not set
49# CONFIG_QEMU is not set
50# CONFIG_SGI_IP22 is not set
51# CONFIG_SGI_IP27 is not set
52# CONFIG_SGI_IP32 is not set
53# CONFIG_SIBYTE_BIGSUR is not set
54# CONFIG_SIBYTE_SWARM is not set
55# CONFIG_SIBYTE_SENTOSA is not set
56# CONFIG_SIBYTE_RHONE is not set
57# CONFIG_SIBYTE_CARMEL is not set
58# CONFIG_SIBYTE_PTSWARM is not set
59# CONFIG_SIBYTE_LITTLESUR is not set
60# CONFIG_SIBYTE_CRHINE is not set
61# CONFIG_SIBYTE_CRHONE is not set
62# CONFIG_SNI_RM200_PCI is not set
63# CONFIG_TOSHIBA_JMR3927 is not set
64# CONFIG_TOSHIBA_RBTX4927 is not set
65# CONFIG_TOSHIBA_RBTX4938 is not set
66# CONFIG_CASIO_E55 is not set
67# CONFIG_IBM_WORKPAD is not set
68# CONFIG_NEC_CMBVR4133 is not set
69CONFIG_TANBAC_TB022X=y
70# CONFIG_TANBAC_TB0226 is not set
71CONFIG_TANBAC_TB0287=y
72# CONFIG_VICTOR_MPC30X is not set
73# CONFIG_ZAO_CAPCELLA is not set
74CONFIG_PCI_VR41XX=y
75# CONFIG_VRC4173 is not set
76CONFIG_RWSEM_GENERIC_SPINLOCK=y
77CONFIG_GENERIC_CALIBRATE_DELAY=y
78CONFIG_DMA_NONCOHERENT=y
79CONFIG_DMA_NEED_PCI_MAP_STATE=y
80# CONFIG_CPU_BIG_ENDIAN is not set
81CONFIG_CPU_LITTLE_ENDIAN=y
82CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
83CONFIG_IRQ_CPU=y
84CONFIG_MIPS_L1_CACHE_SHIFT=5
85
86#
87# CPU selection
88#
89# CONFIG_CPU_MIPS32_R1 is not set
90# CONFIG_CPU_MIPS32_R2 is not set
91# CONFIG_CPU_MIPS64_R1 is not set
92# CONFIG_CPU_MIPS64_R2 is not set
93# CONFIG_CPU_R3000 is not set
94# CONFIG_CPU_TX39XX is not set
95CONFIG_CPU_VR41XX=y
96# CONFIG_CPU_R4300 is not set
97# CONFIG_CPU_R4X00 is not set
98# CONFIG_CPU_TX49XX is not set
99# CONFIG_CPU_R5000 is not set
100# CONFIG_CPU_R5432 is not set
101# CONFIG_CPU_R6000 is not set
102# CONFIG_CPU_NEVADA is not set
103# CONFIG_CPU_R8000 is not set
104# CONFIG_CPU_R10000 is not set
105# CONFIG_CPU_RM7000 is not set
106# CONFIG_CPU_RM9000 is not set
107# CONFIG_CPU_SB1 is not set
108CONFIG_SYS_HAS_CPU_VR41XX=y
109CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
110CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
111CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
112CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
113
114#
115# Kernel type
116#
117CONFIG_32BIT=y
118# CONFIG_64BIT is not set
119CONFIG_PAGE_SIZE_4KB=y
120# CONFIG_PAGE_SIZE_8KB is not set
121# CONFIG_PAGE_SIZE_16KB is not set
122# CONFIG_PAGE_SIZE_64KB is not set
123# CONFIG_MIPS_MT is not set
124# CONFIG_CPU_ADVANCED is not set
125CONFIG_CPU_HAS_SYNC=y
126CONFIG_GENERIC_HARDIRQS=y
127CONFIG_GENERIC_IRQ_PROBE=y
128CONFIG_ARCH_FLATMEM_ENABLE=y
129CONFIG_SELECT_MEMORY_MODEL=y
130CONFIG_FLATMEM_MANUAL=y
131# CONFIG_DISCONTIGMEM_MANUAL is not set
132# CONFIG_SPARSEMEM_MANUAL is not set
133CONFIG_FLATMEM=y
134CONFIG_FLAT_NODE_MEM_MAP=y
135# CONFIG_SPARSEMEM_STATIC is not set
136CONFIG_SPLIT_PTLOCK_CPUS=4
137CONFIG_PREEMPT_NONE=y
138# CONFIG_PREEMPT_VOLUNTARY is not set
139# CONFIG_PREEMPT is not set
140
141#
142# Code maturity level options
143#
144CONFIG_EXPERIMENTAL=y
145CONFIG_BROKEN_ON_SMP=y
146CONFIG_INIT_ENV_ARG_LIMIT=32
147
148#
149# General setup
150#
151CONFIG_LOCALVERSION=""
152CONFIG_LOCALVERSION_AUTO=y
153CONFIG_SWAP=y
154CONFIG_SYSVIPC=y
155# CONFIG_POSIX_MQUEUE is not set
156# CONFIG_BSD_PROCESS_ACCT is not set
157CONFIG_SYSCTL=y
158# CONFIG_AUDIT is not set
159# CONFIG_IKCONFIG is not set
160CONFIG_INITRAMFS_SOURCE=""
161# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
162CONFIG_EMBEDDED=y
163CONFIG_KALLSYMS=y
164# CONFIG_KALLSYMS_EXTRA_PASS is not set
165# CONFIG_HOTPLUG is not set
166CONFIG_PRINTK=y
167CONFIG_BUG=y
168CONFIG_ELF_CORE=y
169CONFIG_BASE_FULL=y
170CONFIG_FUTEX=y
171CONFIG_EPOLL=y
172CONFIG_SHMEM=y
173CONFIG_CC_ALIGN_FUNCTIONS=0
174CONFIG_CC_ALIGN_LABELS=0
175CONFIG_CC_ALIGN_LOOPS=0
176CONFIG_CC_ALIGN_JUMPS=0
177CONFIG_SLAB=y
178# CONFIG_TINY_SHMEM is not set
179CONFIG_BASE_SMALL=0
180# CONFIG_SLOB is not set
181
182#
183# Loadable module support
184#
185CONFIG_MODULES=y
186CONFIG_MODULE_UNLOAD=y
187# CONFIG_MODULE_FORCE_UNLOAD is not set
188CONFIG_OBSOLETE_MODPARM=y
189CONFIG_MODVERSIONS=y
190CONFIG_MODULE_SRCVERSION_ALL=y
191CONFIG_KMOD=y
192
193#
194# Block layer
195#
196# CONFIG_LBD is not set
197
198#
199# IO Schedulers
200#
201CONFIG_IOSCHED_NOOP=y
202CONFIG_IOSCHED_AS=y
203CONFIG_IOSCHED_DEADLINE=y
204CONFIG_IOSCHED_CFQ=y
205CONFIG_DEFAULT_AS=y
206# CONFIG_DEFAULT_DEADLINE is not set
207# CONFIG_DEFAULT_CFQ is not set
208# CONFIG_DEFAULT_NOOP is not set
209CONFIG_DEFAULT_IOSCHED="anticipatory"
210
211#
212# Bus options (PCI, PCMCIA, EISA, ISA, TC)
213#
214CONFIG_HW_HAS_PCI=y
215CONFIG_PCI=y
216# CONFIG_PCI_LEGACY_PROC is not set
217CONFIG_MMU=y
218
219#
220# PCCARD (PCMCIA/CardBus) support
221#
222# CONFIG_PCCARD is not set
223
224#
225# PCI Hotplug Support
226#
227# CONFIG_HOTPLUG_PCI is not set
228
229#
230# Executable file formats
231#
232CONFIG_BINFMT_ELF=y
233# CONFIG_BINFMT_MISC is not set
234CONFIG_TRAD_SIGNALS=y
235
236#
237# Networking
238#
239CONFIG_NET=y
240
241#
242# Networking options
243#
244# CONFIG_NETDEBUG is not set
245CONFIG_PACKET=y
246# CONFIG_PACKET_MMAP is not set
247CONFIG_UNIX=y
248CONFIG_XFRM=y
249CONFIG_XFRM_USER=m
250# CONFIG_NET_KEY is not set
251CONFIG_INET=y
252CONFIG_IP_MULTICAST=y
253CONFIG_IP_ADVANCED_ROUTER=y
254CONFIG_ASK_IP_FIB_HASH=y
255# CONFIG_IP_FIB_TRIE is not set
256CONFIG_IP_FIB_HASH=y
257CONFIG_IP_MULTIPLE_TABLES=y
258CONFIG_IP_ROUTE_MULTIPATH=y
259# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
260CONFIG_IP_ROUTE_VERBOSE=y
261CONFIG_IP_PNP=y
262# CONFIG_IP_PNP_DHCP is not set
263CONFIG_IP_PNP_BOOTP=y
264# CONFIG_IP_PNP_RARP is not set
265CONFIG_NET_IPIP=m
266CONFIG_NET_IPGRE=m
267# CONFIG_NET_IPGRE_BROADCAST is not set
268# CONFIG_IP_MROUTE is not set
269# CONFIG_ARPD is not set
270CONFIG_SYN_COOKIES=y
271# CONFIG_INET_AH is not set
272# CONFIG_INET_ESP is not set
273# CONFIG_INET_IPCOMP is not set
274CONFIG_INET_TUNNEL=m
275CONFIG_INET_DIAG=y
276CONFIG_INET_TCP_DIAG=y
277CONFIG_TCP_CONG_ADVANCED=y
278
279#
280# TCP congestion control
281#
282CONFIG_TCP_CONG_BIC=y
283CONFIG_TCP_CONG_CUBIC=m
284CONFIG_TCP_CONG_WESTWOOD=m
285CONFIG_TCP_CONG_HTCP=m
286# CONFIG_TCP_CONG_HSTCP is not set
287# CONFIG_TCP_CONG_HYBLA is not set
288# CONFIG_TCP_CONG_VEGAS is not set
289# CONFIG_TCP_CONG_SCALABLE is not set
290# CONFIG_IPV6 is not set
291# CONFIG_NETFILTER is not set
292
293#
294# DCCP Configuration (EXPERIMENTAL)
295#
296# CONFIG_IP_DCCP is not set
297
298#
299# SCTP Configuration (EXPERIMENTAL)
300#
301# CONFIG_IP_SCTP is not set
302
303#
304# TIPC Configuration (EXPERIMENTAL)
305#
306# CONFIG_TIPC is not set
307# CONFIG_ATM is not set
308# CONFIG_BRIDGE is not set
309# CONFIG_VLAN_8021Q is not set
310# CONFIG_DECNET is not set
311# CONFIG_LLC2 is not set
312# CONFIG_IPX is not set
313# CONFIG_ATALK is not set
314# CONFIG_X25 is not set
315# CONFIG_LAPB is not set
316# CONFIG_NET_DIVERT is not set
317# CONFIG_ECONET is not set
318# CONFIG_WAN_ROUTER is not set
319
320#
321# QoS and/or fair queueing
322#
323# CONFIG_NET_SCHED is not set
324
325#
326# Network testing
327#
328# CONFIG_NET_PKTGEN is not set
329# CONFIG_HAMRADIO is not set
330# CONFIG_IRDA is not set
331# CONFIG_BT is not set
332# CONFIG_IEEE80211 is not set
333
334#
335# Device Drivers
336#
337
338#
339# Generic Driver Options
340#
341CONFIG_STANDALONE=y
342CONFIG_PREVENT_FIRMWARE_BUILD=y
343# CONFIG_FW_LOADER is not set
344
345#
346# Connector - unified userspace <-> kernelspace linker
347#
348# CONFIG_CONNECTOR is not set
349
350#
351# Memory Technology Devices (MTD)
352#
353# CONFIG_MTD is not set
354
355#
356# Parallel port support
357#
358# CONFIG_PARPORT is not set
359
360#
361# Plug and Play support
362#
363
364#
365# Block devices
366#
367# CONFIG_BLK_CPQ_DA is not set
368# CONFIG_BLK_CPQ_CISS_DA is not set
369# CONFIG_BLK_DEV_DAC960 is not set
370# CONFIG_BLK_DEV_UMEM is not set
371# CONFIG_BLK_DEV_COW_COMMON is not set
372CONFIG_BLK_DEV_LOOP=m
373# CONFIG_BLK_DEV_CRYPTOLOOP is not set
374CONFIG_BLK_DEV_NBD=m
375# CONFIG_BLK_DEV_SX8 is not set
376# CONFIG_BLK_DEV_UB is not set
377CONFIG_BLK_DEV_RAM=y
378CONFIG_BLK_DEV_RAM_COUNT=16
379CONFIG_BLK_DEV_RAM_SIZE=4096
380# CONFIG_BLK_DEV_INITRD is not set
381# CONFIG_CDROM_PKTCDVD is not set
382# CONFIG_ATA_OVER_ETH is not set
383
384#
385# ATA/ATAPI/MFM/RLL support
386#
387CONFIG_IDE=y
388CONFIG_BLK_DEV_IDE=y
389
390#
391# Please see Documentation/ide.txt for help/info on IDE drives
392#
393# CONFIG_BLK_DEV_IDE_SATA is not set
394CONFIG_BLK_DEV_IDEDISK=y
395# CONFIG_IDEDISK_MULTI_MODE is not set
396# CONFIG_BLK_DEV_IDECD is not set
397# CONFIG_BLK_DEV_IDETAPE is not set
398# CONFIG_BLK_DEV_IDEFLOPPY is not set
399# CONFIG_BLK_DEV_IDESCSI is not set
400# CONFIG_IDE_TASK_IOCTL is not set
401
402#
403# IDE chipset support/bugfixes
404#
405CONFIG_IDE_GENERIC=y
406CONFIG_BLK_DEV_IDEPCI=y
407# CONFIG_IDEPCI_SHARE_IRQ is not set
408# CONFIG_BLK_DEV_OFFBOARD is not set
409# CONFIG_BLK_DEV_GENERIC is not set
410# CONFIG_BLK_DEV_OPTI621 is not set
411CONFIG_BLK_DEV_IDEDMA_PCI=y
412# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
413# CONFIG_IDEDMA_PCI_AUTO is not set
414# CONFIG_BLK_DEV_AEC62XX is not set
415# CONFIG_BLK_DEV_ALI15X3 is not set
416# CONFIG_BLK_DEV_AMD74XX is not set
417# CONFIG_BLK_DEV_CMD64X is not set
418# CONFIG_BLK_DEV_TRIFLEX is not set
419# CONFIG_BLK_DEV_CY82C693 is not set
420# CONFIG_BLK_DEV_CS5520 is not set
421# CONFIG_BLK_DEV_CS5530 is not set
422# CONFIG_BLK_DEV_HPT34X is not set
423# CONFIG_BLK_DEV_HPT366 is not set
424# CONFIG_BLK_DEV_SC1200 is not set
425# CONFIG_BLK_DEV_PIIX is not set
426# CONFIG_BLK_DEV_IT821X is not set
427# CONFIG_BLK_DEV_NS87415 is not set
428# CONFIG_BLK_DEV_PDC202XX_OLD is not set
429# CONFIG_BLK_DEV_PDC202XX_NEW is not set
430# CONFIG_BLK_DEV_SVWKS is not set
431CONFIG_BLK_DEV_SIIMAGE=y
432# CONFIG_BLK_DEV_SLC90E66 is not set
433# CONFIG_BLK_DEV_TRM290 is not set
434# CONFIG_BLK_DEV_VIA82CXXX is not set
435# CONFIG_IDE_ARM is not set
436CONFIG_BLK_DEV_IDEDMA=y
437# CONFIG_IDEDMA_IVB is not set
438# CONFIG_IDEDMA_AUTO is not set
439# CONFIG_BLK_DEV_HD is not set
440
441#
442# SCSI device support
443#
444# CONFIG_RAID_ATTRS is not set
445CONFIG_SCSI=y
446CONFIG_SCSI_PROC_FS=y
447
448#
449# SCSI support type (disk, tape, CD-ROM)
450#
451CONFIG_BLK_DEV_SD=y
452# CONFIG_CHR_DEV_ST is not set
453# CONFIG_CHR_DEV_OSST is not set
454# CONFIG_BLK_DEV_SR is not set
455# CONFIG_CHR_DEV_SG is not set
456# CONFIG_CHR_DEV_SCH is not set
457
458#
459# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
460#
461# CONFIG_SCSI_MULTI_LUN is not set
462# CONFIG_SCSI_CONSTANTS is not set
463# CONFIG_SCSI_LOGGING is not set
464
465#
466# SCSI Transport Attributes
467#
468# CONFIG_SCSI_SPI_ATTRS is not set
469# CONFIG_SCSI_FC_ATTRS is not set
470# CONFIG_SCSI_ISCSI_ATTRS is not set
471# CONFIG_SCSI_SAS_ATTRS is not set
472
473#
474# SCSI low-level drivers
475#
476# CONFIG_ISCSI_TCP is not set
477# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
478# CONFIG_SCSI_3W_9XXX is not set
479# CONFIG_SCSI_ACARD is not set
480# CONFIG_SCSI_AACRAID is not set
481# CONFIG_SCSI_AIC7XXX is not set
482# CONFIG_SCSI_AIC7XXX_OLD is not set
483# CONFIG_SCSI_AIC79XX is not set
484# CONFIG_SCSI_DPT_I2O is not set
485# CONFIG_MEGARAID_NEWGEN is not set
486# CONFIG_MEGARAID_LEGACY is not set
487# CONFIG_MEGARAID_SAS is not set
488# CONFIG_SCSI_SATA is not set
489# CONFIG_SCSI_DMX3191D is not set
490# CONFIG_SCSI_FUTURE_DOMAIN is not set
491# CONFIG_SCSI_IPS is not set
492# CONFIG_SCSI_INITIO is not set
493# CONFIG_SCSI_INIA100 is not set
494# CONFIG_SCSI_SYM53C8XX_2 is not set
495# CONFIG_SCSI_IPR is not set
496# CONFIG_SCSI_QLOGIC_FC is not set
497# CONFIG_SCSI_QLOGIC_1280 is not set
498# CONFIG_SCSI_QLA_FC is not set
499# CONFIG_SCSI_LPFC is not set
500# CONFIG_SCSI_DC395x is not set
501# CONFIG_SCSI_DC390T is not set
502# CONFIG_SCSI_NSP32 is not set
503# CONFIG_SCSI_DEBUG is not set
504
505#
506# Multi-device support (RAID and LVM)
507#
508# CONFIG_MD is not set
509
510#
511# Fusion MPT device support
512#
513# CONFIG_FUSION is not set
514# CONFIG_FUSION_SPI is not set
515# CONFIG_FUSION_FC is not set
516# CONFIG_FUSION_SAS is not set
517
518#
519# IEEE 1394 (FireWire) support
520#
521CONFIG_IEEE1394=m
522
523#
524# Subsystem Options
525#
526# CONFIG_IEEE1394_VERBOSEDEBUG is not set
527# CONFIG_IEEE1394_OUI_DB is not set
528CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
529CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
530# CONFIG_IEEE1394_EXPORT_FULL_API is not set
531
532#
533# Device Drivers
534#
535
536#
537# Texas Instruments PCILynx requires I2C
538#
539CONFIG_IEEE1394_OHCI1394=m
540
541#
542# Protocol Drivers
543#
544CONFIG_IEEE1394_VIDEO1394=m
545CONFIG_IEEE1394_SBP2=m
546# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
547CONFIG_IEEE1394_ETH1394=m
548CONFIG_IEEE1394_DV1394=m
549CONFIG_IEEE1394_RAWIO=m
550
551#
552# I2O device support
553#
554# CONFIG_I2O is not set
555
556#
557# Network device support
558#
559CONFIG_NETDEVICES=y
560CONFIG_DUMMY=m
561# CONFIG_BONDING is not set
562# CONFIG_EQUALIZER is not set
563# CONFIG_TUN is not set
564
565#
566# ARCnet devices
567#
568# CONFIG_ARCNET is not set
569
570#
571# PHY device support
572#
573# CONFIG_PHYLIB is not set
574
575#
576# Ethernet (10 or 100Mbit)
577#
578CONFIG_NET_ETHERNET=y
579CONFIG_MII=y
580# CONFIG_HAPPYMEAL is not set
581# CONFIG_SUNGEM is not set
582# CONFIG_CASSINI is not set
583# CONFIG_NET_VENDOR_3COM is not set
584# CONFIG_DM9000 is not set
585
586#
587# Tulip family network device support
588#
589# CONFIG_NET_TULIP is not set
590# CONFIG_HP100 is not set
591# CONFIG_NET_PCI is not set
592
593#
594# Ethernet (1000 Mbit)
595#
596# CONFIG_ACENIC is not set
597# CONFIG_DL2K is not set
598# CONFIG_E1000 is not set
599# CONFIG_NS83820 is not set
600# CONFIG_HAMACHI is not set
601# CONFIG_YELLOWFIN is not set
602CONFIG_R8169=y
603# CONFIG_R8169_NAPI is not set
604# CONFIG_SIS190 is not set
605# CONFIG_SKGE is not set
606# CONFIG_SKY2 is not set
607# CONFIG_SK98LIN is not set
608# CONFIG_TIGON3 is not set
609# CONFIG_BNX2 is not set
610
611#
612# Ethernet (10000 Mbit)
613#
614# CONFIG_CHELSIO_T1 is not set
615# CONFIG_IXGB is not set
616# CONFIG_S2IO is not set
617
618#
619# Token Ring devices
620#
621# CONFIG_TR is not set
622
623#
624# Wireless LAN (non-hamradio)
625#
626# CONFIG_NET_RADIO is not set
627
628#
629# Wan interfaces
630#
631# CONFIG_WAN is not set
632# CONFIG_FDDI is not set
633# CONFIG_HIPPI is not set
634# CONFIG_PPP is not set
635# CONFIG_SLIP is not set
636# CONFIG_NET_FC is not set
637# CONFIG_SHAPER is not set
638# CONFIG_NETCONSOLE is not set
639# CONFIG_NETPOLL is not set
640# CONFIG_NET_POLL_CONTROLLER is not set
641
642#
643# ISDN subsystem
644#
645# CONFIG_ISDN is not set
646
647#
648# Telephony Support
649#
650# CONFIG_PHONE is not set
651
652#
653# Input device support
654#
655CONFIG_INPUT=y
656
657#
658# Userland interfaces
659#
660# CONFIG_INPUT_MOUSEDEV is not set
661# CONFIG_INPUT_JOYDEV is not set
662# CONFIG_INPUT_TSDEV is not set
663# CONFIG_INPUT_EVDEV is not set
664# CONFIG_INPUT_EVBUG is not set
665
666#
667# Input Device Drivers
668#
669# CONFIG_INPUT_KEYBOARD is not set
670# CONFIG_INPUT_MOUSE is not set
671# CONFIG_INPUT_JOYSTICK is not set
672# CONFIG_INPUT_TOUCHSCREEN is not set
673# CONFIG_INPUT_MISC is not set
674
675#
676# Hardware I/O ports
677#
678# CONFIG_SERIO is not set
679# CONFIG_GAMEPORT is not set
680
681#
682# Character devices
683#
684CONFIG_VT=y
685CONFIG_VT_CONSOLE=y
686CONFIG_HW_CONSOLE=y
687# CONFIG_SERIAL_NONSTANDARD is not set
688
689#
690# Serial drivers
691#
692# CONFIG_SERIAL_8250 is not set
693
694#
695# Non-8250 serial port support
696#
697CONFIG_SERIAL_CORE=y
698CONFIG_SERIAL_CORE_CONSOLE=y
699CONFIG_SERIAL_VR41XX=y
700CONFIG_SERIAL_VR41XX_CONSOLE=y
701# CONFIG_SERIAL_JSM is not set
702CONFIG_UNIX98_PTYS=y
703CONFIG_LEGACY_PTYS=y
704CONFIG_LEGACY_PTY_COUNT=256
705
706#
707# IPMI
708#
709# CONFIG_IPMI_HANDLER is not set
710
711#
712# Watchdog Cards
713#
714# CONFIG_WATCHDOG is not set
715# CONFIG_RTC is not set
716# CONFIG_GEN_RTC is not set
717# CONFIG_RTC_VR41XX is not set
718# CONFIG_DTLK is not set
719# CONFIG_R3964 is not set
720# CONFIG_APPLICOM is not set
721# CONFIG_TANBAC_TB0219 is not set
722
723#
724# Ftape, the floppy tape device driver
725#
726# CONFIG_DRM is not set
727CONFIG_GPIO_VR41XX=y
728# CONFIG_RAW_DRIVER is not set
729
730#
731# TPM devices
732#
733# CONFIG_TCG_TPM is not set
734# CONFIG_TELCLOCK is not set
735
736#
737# I2C support
738#
739# CONFIG_I2C is not set
740
741#
742# SPI support
743#
744# CONFIG_SPI is not set
745# CONFIG_SPI_MASTER is not set
746
747#
748# Dallas's 1-wire bus
749#
750# CONFIG_W1 is not set
751
752#
753# Hardware Monitoring support
754#
755# CONFIG_HWMON is not set
756# CONFIG_HWMON_VID is not set
757
758#
759# Misc devices
760#
761
762#
763# Multimedia Capabilities Port drivers
764#
765
766#
767# Multimedia devices
768#
769# CONFIG_VIDEO_DEV is not set
770
771#
772# Digital Video Broadcasting Devices
773#
774# CONFIG_DVB is not set
775
776#
777# Graphics support
778#
779# CONFIG_FB is not set
780
781#
782# Console display driver support
783#
784# CONFIG_VGA_CONSOLE is not set
785CONFIG_DUMMY_CONSOLE=y
786
787#
788# Sound
789#
790# CONFIG_SOUND is not set
791
792#
793# USB support
794#
795CONFIG_USB_ARCH_HAS_HCD=y
796CONFIG_USB_ARCH_HAS_OHCI=y
797CONFIG_USB=m
798# CONFIG_USB_DEBUG is not set
799
800#
801# Miscellaneous USB options
802#
803# CONFIG_USB_DEVICEFS is not set
804# CONFIG_USB_BANDWIDTH is not set
805# CONFIG_USB_DYNAMIC_MINORS is not set
806# CONFIG_USB_OTG is not set
807
808#
809# USB Host Controller Drivers
810#
811CONFIG_USB_EHCI_HCD=m
812# CONFIG_USB_EHCI_SPLIT_ISO is not set
813# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
814# CONFIG_USB_ISP116X_HCD is not set
815CONFIG_USB_OHCI_HCD=m
816# CONFIG_USB_OHCI_BIG_ENDIAN is not set
817CONFIG_USB_OHCI_LITTLE_ENDIAN=y
818# CONFIG_USB_UHCI_HCD is not set
819# CONFIG_USB_SL811_HCD is not set
820
821#
822# USB Device Class drivers
823#
824# CONFIG_USB_ACM is not set
825# CONFIG_USB_PRINTER is not set
826
827#
828# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
829#
830
831#
832# may also be needed; see USB_STORAGE Help for more information
833#
834CONFIG_USB_STORAGE=m
835# CONFIG_USB_STORAGE_DEBUG is not set
836# CONFIG_USB_STORAGE_DATAFAB is not set
837# CONFIG_USB_STORAGE_FREECOM is not set
838# CONFIG_USB_STORAGE_ISD200 is not set
839# CONFIG_USB_STORAGE_DPCM is not set
840# CONFIG_USB_STORAGE_USBAT is not set
841# CONFIG_USB_STORAGE_SDDR09 is not set
842# CONFIG_USB_STORAGE_SDDR55 is not set
843# CONFIG_USB_STORAGE_JUMPSHOT is not set
844# CONFIG_USB_STORAGE_ALAUDA is not set
845# CONFIG_USB_LIBUSUAL is not set
846
847#
848# USB Input Devices
849#
850CONFIG_USB_HID=m
851CONFIG_USB_HIDINPUT=y
852# CONFIG_USB_HIDINPUT_POWERBOOK is not set
853# CONFIG_HID_FF is not set
854# CONFIG_USB_HIDDEV is not set
855
856#
857# USB HID Boot Protocol drivers
858#
859# CONFIG_USB_KBD is not set
860# CONFIG_USB_MOUSE is not set
861# CONFIG_USB_AIPTEK is not set
862# CONFIG_USB_WACOM is not set
863# CONFIG_USB_ACECAD is not set
864# CONFIG_USB_KBTAB is not set
865# CONFIG_USB_POWERMATE is not set
866# CONFIG_USB_MTOUCH is not set
867# CONFIG_USB_ITMTOUCH is not set
868# CONFIG_USB_EGALAX is not set
869# CONFIG_USB_YEALINK is not set
870# CONFIG_USB_XPAD is not set
871# CONFIG_USB_ATI_REMOTE is not set
872# CONFIG_USB_ATI_REMOTE2 is not set
873# CONFIG_USB_KEYSPAN_REMOTE is not set
874# CONFIG_USB_APPLETOUCH is not set
875
876#
877# USB Imaging devices
878#
879# CONFIG_USB_MDC800 is not set
880# CONFIG_USB_MICROTEK is not set
881
882#
883# USB Multimedia devices
884#
885# CONFIG_USB_DABUSB is not set
886
887#
888# Video4Linux support is needed for USB Multimedia device support
889#
890
891#
892# USB Network Adapters
893#
894# CONFIG_USB_CATC is not set
895# CONFIG_USB_KAWETH is not set
896# CONFIG_USB_PEGASUS is not set
897# CONFIG_USB_RTL8150 is not set
898# CONFIG_USB_USBNET is not set
899CONFIG_USB_MON=y
900
901#
902# USB port drivers
903#
904
905#
906# USB Serial Converter support
907#
908# CONFIG_USB_SERIAL is not set
909
910#
911# USB Miscellaneous drivers
912#
913# CONFIG_USB_EMI62 is not set
914# CONFIG_USB_EMI26 is not set
915# CONFIG_USB_AUERSWALD is not set
916# CONFIG_USB_RIO500 is not set
917# CONFIG_USB_LEGOTOWER is not set
918# CONFIG_USB_LCD is not set
919# CONFIG_USB_LED is not set
920# CONFIG_USB_CYTHERM is not set
921# CONFIG_USB_PHIDGETKIT is not set
922# CONFIG_USB_PHIDGETSERVO is not set
923# CONFIG_USB_IDMOUSE is not set
924# CONFIG_USB_SISUSBVGA is not set
925# CONFIG_USB_LD is not set
926
927#
928# USB DSL modem support
929#
930
931#
932# USB Gadget Support
933#
934# CONFIG_USB_GADGET is not set
935
936#
937# MMC/SD Card support
938#
939# CONFIG_MMC is not set
940
941#
942# InfiniBand support
943#
944# CONFIG_INFINIBAND is not set
945
946#
947# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
948#
949
950#
951# File systems
952#
953CONFIG_EXT2_FS=y
954# CONFIG_EXT2_FS_XATTR is not set
955# CONFIG_EXT2_FS_XIP is not set
956CONFIG_EXT3_FS=y
957CONFIG_EXT3_FS_XATTR=y
958# CONFIG_EXT3_FS_POSIX_ACL is not set
959# CONFIG_EXT3_FS_SECURITY is not set
960CONFIG_JBD=y
961# CONFIG_JBD_DEBUG is not set
962CONFIG_FS_MBCACHE=y
963# CONFIG_REISERFS_FS is not set
964# CONFIG_JFS_FS is not set
965# CONFIG_FS_POSIX_ACL is not set
966CONFIG_XFS_FS=y
967CONFIG_XFS_QUOTA=y
968# CONFIG_XFS_SECURITY is not set
969CONFIG_XFS_POSIX_ACL=y
970# CONFIG_XFS_RT is not set
971# CONFIG_OCFS2_FS is not set
972# CONFIG_MINIX_FS is not set
973CONFIG_ROMFS_FS=m
974CONFIG_INOTIFY=y
975# CONFIG_QUOTA is not set
976CONFIG_QUOTACTL=y
977# CONFIG_DNOTIFY is not set
978# CONFIG_AUTOFS_FS is not set
979CONFIG_AUTOFS4_FS=y
980# CONFIG_FUSE_FS is not set
981
982#
983# CD-ROM/DVD Filesystems
984#
985# CONFIG_ISO9660_FS is not set
986# CONFIG_UDF_FS is not set
987
988#
989# DOS/FAT/NT Filesystems
990#
991# CONFIG_MSDOS_FS is not set
992# CONFIG_VFAT_FS is not set
993# CONFIG_NTFS_FS is not set
994
995#
996# Pseudo filesystems
997#
998CONFIG_PROC_FS=y
999CONFIG_PROC_KCORE=y
1000CONFIG_SYSFS=y
1001CONFIG_TMPFS=y
1002# CONFIG_HUGETLB_PAGE is not set
1003CONFIG_RAMFS=y
1004# CONFIG_RELAYFS_FS is not set
1005# CONFIG_CONFIGFS_FS is not set
1006
1007#
1008# Miscellaneous filesystems
1009#
1010# CONFIG_ADFS_FS is not set
1011# CONFIG_AFFS_FS is not set
1012# CONFIG_HFS_FS is not set
1013# CONFIG_HFSPLUS_FS is not set
1014# CONFIG_BEFS_FS is not set
1015# CONFIG_BFS_FS is not set
1016# CONFIG_EFS_FS is not set
1017CONFIG_CRAMFS=m
1018# CONFIG_VXFS_FS is not set
1019# CONFIG_HPFS_FS is not set
1020# CONFIG_QNX4FS_FS is not set
1021# CONFIG_SYSV_FS is not set
1022# CONFIG_UFS_FS is not set
1023
1024#
1025# Network File Systems
1026#
1027CONFIG_NFS_FS=y
1028CONFIG_NFS_V3=y
1029# CONFIG_NFS_V3_ACL is not set
1030# CONFIG_NFS_V4 is not set
1031# CONFIG_NFS_DIRECTIO is not set
1032# CONFIG_NFSD is not set
1033CONFIG_ROOT_NFS=y
1034CONFIG_LOCKD=y
1035CONFIG_LOCKD_V4=y
1036CONFIG_NFS_COMMON=y
1037CONFIG_SUNRPC=y
1038# CONFIG_RPCSEC_GSS_KRB5 is not set
1039# CONFIG_RPCSEC_GSS_SPKM3 is not set
1040# CONFIG_SMB_FS is not set
1041# CONFIG_CIFS is not set
1042# CONFIG_NCP_FS is not set
1043# CONFIG_CODA_FS is not set
1044# CONFIG_AFS_FS is not set
1045# CONFIG_9P_FS is not set
1046
1047#
1048# Partition Types
1049#
1050# CONFIG_PARTITION_ADVANCED is not set
1051CONFIG_MSDOS_PARTITION=y
1052
1053#
1054# Native Language Support
1055#
1056# CONFIG_NLS is not set
1057
1058#
1059# Profiling support
1060#
1061# CONFIG_PROFILING is not set
1062
1063#
1064# Kernel hacking
1065#
1066# CONFIG_PRINTK_TIME is not set
1067# CONFIG_MAGIC_SYSRQ is not set
1068# CONFIG_DEBUG_KERNEL is not set
1069CONFIG_LOG_BUF_SHIFT=14
1070CONFIG_CROSSCOMPILE=y
1071CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs"
1072
1073#
1074# Security options
1075#
1076CONFIG_KEYS=y
1077CONFIG_KEYS_DEBUG_PROC_KEYS=y
1078# CONFIG_SECURITY is not set
1079
1080#
1081# Cryptographic options
1082#
1083# CONFIG_CRYPTO is not set
1084
1085#
1086# Hardware crypto devices
1087#
1088
1089#
1090# Library routines
1091#
1092# CONFIG_CRC_CCITT is not set
1093# CONFIG_CRC16 is not set
1094CONFIG_CRC32=y
1095# CONFIG_LIBCRC32C is not set
1096CONFIG_ZLIB_INFLATE=m
diff --git a/arch/mips/ddb5xxx/ddb5074/Makefile b/arch/mips/ddb5xxx/ddb5074/Makefile
index 488206b8d94e..304c02107b46 100644
--- a/arch/mips/ddb5xxx/ddb5074/Makefile
+++ b/arch/mips/ddb5xxx/ddb5074/Makefile
@@ -3,6 +3,6 @@
3# under Linux. 3# under Linux.
4# 4#
5 5
6obj-y += setup.o irq.o int-handler.o nile4_pic.o 6obj-y += setup.o irq.o nile4_pic.o
7 7
8EXTRA_AFLAGS := $(CFLAGS) 8EXTRA_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 a78644150b37..000000000000
--- a/arch/mips/ddb5xxx/ddb5074/int-handler.S
+++ /dev/null
@@ -1,120 +0,0 @@
1/*
2 * arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
3 *
4 * Based on arch/mips/sgi/kernel/indyIRQ.S
5 *
6 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
7 *
8 * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
9 * Sony Software Development Center Europe (SDCE), Brussels
10 */
11#include <asm/asm.h>
12#include <asm/mipsregs.h>
13#include <asm/regdef.h>
14#include <asm/stackframe.h>
15
16/* A lot of complication here is taken away because:
17 *
18 * 1) We handle one interrupt and return, sitting in a loop and moving across
19 * all the pending IRQ bits in the cause register is _NOT_ the answer, the
20 * common case is one pending IRQ so optimize in that direction.
21 *
22 * 2) We need not check against bits in the status register IRQ mask, that
23 * would make this routine slow as hell.
24 *
25 * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
26 * between like BSD spl() brain-damage.
27 *
28 * Furthermore, the IRQs on the INDY look basically (barring software IRQs
29 * which we don't use at all) like:
30 *
31 * MIPS IRQ Source
32 * -------- ------
33 * 0 Software (ignored)
34 * 1 Software (ignored)
35 * 2 Local IRQ level zero
36 * 3 Local IRQ level one
37 * 4 8254 Timer zero
38 * 5 8254 Timer one
39 * 6 Bus Error
40 * 7 R4k timer (what we use)
41 *
42 * We handle the IRQ according to _our_ priority which is:
43 *
44 * Highest ---- R4k Timer
45 * Local IRQ zero
46 * Local IRQ one
47 * Bus Error
48 * 8254 Timer zero
49 * Lowest ---- 8254 Timer one
50 *
51 * then we just return, if multiple IRQs are pending then we will just take
52 * another exception, big deal.
53 */
54
55 .text
56 .set noreorder
57 .set noat
58 .align 5
59 NESTED(ddbIRQ, PT_SIZE, sp)
60 SAVE_ALL
61 CLI
62 .set at
63 mfc0 s0, CP0_CAUSE # get irq mask
64
65#if 1
66 mfc0 t2,CP0_STATUS # get enabled interrupts
67 and s0,t2 # isolate allowed ones
68#endif
69 /* First we check for r4k counter/timer IRQ. */
70 andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
71 beq a0, zero, 1f
72 andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
73
74 /* Wheee, local level zero interrupt. */
75 jal ddb_local0_irqdispatch
76 move a0, sp # delay slot
77
78 j ret_from_irq
79 nop # delay slot
80
811:
82 beq a0, zero, 1f
83 andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
84
85 /* Wheee, local level one interrupt. */
86 move a0, sp
87 jal ddb_local1_irqdispatch
88 nop
89
90 j ret_from_irq
91 nop
92
931:
94 beq a0, zero, 1f
95 nop
96
97 /* Wheee, an asynchronous bus error... */
98 move a0, sp
99 jal ddb_buserror_irq
100 nop
101
102 j ret_from_irq
103 nop
104
1051:
106 /* Here by mistake? This is possible, what can happen
107 * is that by the time we take the exception the IRQ
108 * pin goes low, so just leave if this is the case.
109 */
110 andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
111 beq a0, zero, 1f
112
113 /* Must be one of the 8254 timers... */
114 move a0, sp
115 jal ddb_8254timer_irq
116 nop
1171:
118 j ret_from_irq
119 nop
120 END(ddbIRQ)
diff --git a/arch/mips/ddb5xxx/ddb5074/irq.c b/arch/mips/ddb5xxx/ddb5074/irq.c
index 45088a1be414..60c087b7738c 100644
--- a/arch/mips/ddb5xxx/ddb5074/irq.c
+++ b/arch/mips/ddb5xxx/ddb5074/irq.c
@@ -21,8 +21,6 @@
21#include <asm/ddb5xxx/ddb5074.h> 21#include <asm/ddb5xxx/ddb5074.h>
22 22
23 23
24extern asmlinkage void ddbIRQ(void);
25
26static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; 24static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
27 25
28#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ 26#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */
@@ -90,7 +88,7 @@ static void m1543_irq_setup(void)
90 88
91} 89}
92 90
93void ddb_local0_irqdispatch(struct pt_regs *regs) 91static void ddb_local0_irqdispatch(struct pt_regs *regs)
94{ 92{
95 u32 mask; 93 u32 mask;
96 int nile4_irq; 94 int nile4_irq;
@@ -118,29 +116,41 @@ void ddb_local0_irqdispatch(struct pt_regs *regs)
118 } 116 }
119} 117}
120 118
121void ddb_local1_irqdispatch(void) 119static void ddb_local1_irqdispatch(void)
122{ 120{
123 printk("ddb_local1_irqdispatch called\n"); 121 printk("ddb_local1_irqdispatch called\n");
124} 122}
125 123
126void ddb_buserror_irq(void) 124static void ddb_buserror_irq(void)
127{ 125{
128 printk("ddb_buserror_irq called\n"); 126 printk("ddb_buserror_irq called\n");
129} 127}
130 128
131void ddb_8254timer_irq(void) 129static void ddb_8254timer_irq(void)
132{ 130{
133 printk("ddb_8254timer_irq called\n"); 131 printk("ddb_8254timer_irq called\n");
134} 132}
135 133
134asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
135{
136 unsigned int pending = read_c0_cause() & read_c0_status();
137
138 if (pending & CAUSEF_IP2)
139 ddb_local0_irqdispatch(regs);
140 else if (pending & CAUSEF_IP3)
141 ddb_local1_irqdispatch();
142 else if (pending & CAUSEF_IP6)
143 ddb_buserror_irq();
144 else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
145 ddb_8254timer_irq();
146}
147
136void __init arch_init_irq(void) 148void __init arch_init_irq(void)
137{ 149{
138 /* setup cascade interrupts */ 150 /* setup cascade interrupts */
139 setup_irq(NILE4_IRQ_BASE + NILE4_INT_INTE, &irq_cascade); 151 setup_irq(NILE4_IRQ_BASE + NILE4_INT_INTE, &irq_cascade);
140 setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade); 152 setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade);
141 153
142 set_except_vector(0, ddbIRQ);
143
144 nile4_irq_setup(NILE4_IRQ_BASE); 154 nile4_irq_setup(NILE4_IRQ_BASE);
145 m1543_irq_setup(); 155 m1543_irq_setup();
146 init_i8259_irqs(); 156 init_i8259_irqs();
diff --git a/arch/mips/ddb5xxx/ddb5476/Makefile b/arch/mips/ddb5xxx/ddb5476/Makefile
index 61eec363cb02..ab0312cb47b4 100644
--- a/arch/mips/ddb5xxx/ddb5476/Makefile
+++ b/arch/mips/ddb5xxx/ddb5476/Makefile
@@ -3,7 +3,7 @@
3# under Linux. 3# under Linux.
4# 4#
5 5
6obj-y += setup.o irq.o int-handler.o nile4_pic.o vrc5476_irq.o 6obj-y += setup.o irq.o nile4_pic.o vrc5476_irq.o
7obj-$(CONFIG_KGDB) += dbg_io.o 7obj-$(CONFIG_KGDB) += dbg_io.o
8 8
9EXTRA_AFLAGS := $(CFLAGS) 9EXTRA_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 12c292e189ba..000000000000
--- a/arch/mips/ddb5xxx/ddb5476/int-handler.S
+++ /dev/null
@@ -1,112 +0,0 @@
1/*
2 * Copyright 2001 MontaVista Software Inc.
3 * Author: jsun@mvista.com or jsun@junsun.net
4 *
5 * First-level interrupt dispatcher for ddb5476
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12#include <asm/asm.h>
13#include <asm/mipsregs.h>
14#include <asm/addrspace.h>
15#include <asm/regdef.h>
16#include <asm/stackframe.h>
17
18#include <asm/ddb5xxx/ddb5476.h>
19
20/*
21 * first level interrupt dispatcher for ocelot board -
22 * We check for the timer first, then check PCI ints A and D.
23 * Then check for serial IRQ and fall through.
24 */
25 .align 5
26 NESTED(ddb5476_handle_int, PT_SIZE, sp)
27 SAVE_ALL
28 CLI
29 .set at
30 .set noreorder
31 mfc0 t0, CP0_CAUSE
32 mfc0 t2, CP0_STATUS
33
34 and t0, t2
35
36 andi t1, t0, STATUSF_IP7 /* cpu timer */
37 bnez t1, ll_cpu_ip7
38 andi t1, t0, STATUSF_IP2 /* vrc5476 & i8259 */
39 bnez t1, ll_cpu_ip2
40 andi t1, t0, STATUSF_IP3
41 bnez t1, ll_cpu_ip3
42 andi t1, t0, STATUSF_IP4
43 bnez t1, ll_cpu_ip4
44 andi t1, t0, STATUSF_IP5
45 bnez t1, ll_cpu_ip5
46 andi t1, t0, STATUSF_IP6
47 bnez t1, ll_cpu_ip6
48 andi t1, t0, STATUSF_IP0 /* software int 0 */
49 bnez t1, ll_cpu_ip0
50 andi t1, t0, STATUSF_IP1 /* software int 1 */
51 bnez t1, ll_cpu_ip1
52 nop
53
54 .set reorder
55
56 /* wrong alarm or masked ... */
57 // j spurious_interrupt
58 move a0, sp
59 jal vrc5476_irq_dispatch
60 j ret_from_irq
61 nop
62
63 .align 5
64
65ll_cpu_ip0:
66 li a0, CPU_IRQ_BASE + 0
67 move a1, sp
68 jal do_IRQ
69 j ret_from_irq
70
71ll_cpu_ip1:
72 li a0, CPU_IRQ_BASE + 1
73 move a1, sp
74 jal do_IRQ
75 j ret_from_irq
76
77ll_cpu_ip2: /* jump to second-level dispatching */
78 move a0, sp
79 jal vrc5476_irq_dispatch
80 j ret_from_irq
81
82ll_cpu_ip3:
83 li a0, CPU_IRQ_BASE + 3
84 move a1, sp
85 jal do_IRQ
86 j ret_from_irq
87
88ll_cpu_ip4:
89 li a0, CPU_IRQ_BASE + 4
90 move a1, sp
91 jal do_IRQ
92 j ret_from_irq
93
94ll_cpu_ip5:
95 li a0, CPU_IRQ_BASE + 5
96 move a1, sp
97 jal do_IRQ
98 j ret_from_irq
99
100ll_cpu_ip6:
101 li a0, CPU_IRQ_BASE + 6
102 move a1, sp
103 jal do_IRQ
104 j ret_from_irq
105
106ll_cpu_ip7:
107 li a0, CPU_IRQ_BASE + 7
108 move a1, sp
109 jal do_IRQ
110 j ret_from_irq
111
112 END(ddb5476_handle_int)
diff --git a/arch/mips/ddb5xxx/ddb5476/irq.c b/arch/mips/ddb5xxx/ddb5476/irq.c
index 5388b5868c4a..7583a1f30711 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)
110static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; 110static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
111static struct irqaction irq_error = { no_action, 0, CPU_MASK_NONE, "error", NULL, NULL }; 111static struct irqaction irq_error = { no_action, 0, CPU_MASK_NONE, "error", NULL, NULL };
112 112
113extern asmlinkage void ddb5476_handle_int(void);
114extern int setup_irq(unsigned int irq, struct irqaction *irqaction); 113extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
115extern void mips_cpu_irq_init(u32 irq_base); 114extern void mips_cpu_irq_init(u32 irq_base);
116extern void vrc5476_irq_init(u32 irq_base); 115extern void vrc5476_irq_init(u32 irq_base);
117 116
117extern void vrc5476_irq_dispatch(struct pt_regs *regs);
118
119asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
120{
121 unsigned int pending = read_c0_cause() & read_c0_status();
122
123 if (pending & STATUSF_IP7)
124 do_IRQ(CPU_IRQ_BASE + 7, regs);
125 else if (pending & STATUSF_IP2)
126 vrc5476_irq_dispatch(regs);
127 else if (pending & STATUSF_IP3)
128 do_IRQ(CPU_IRQ_BASE + 3, regs);
129 else if (pending & STATUSF_IP4)
130 do_IRQ(CPU_IRQ_BASE + 4, regs);
131 else if (pending & STATUSF_IP5)
132 do_IRQ(CPU_IRQ_BASE + 5, regs);
133 else if (pending & STATUSF_IP6)
134 do_IRQ(CPU_IRQ_BASE + 6, regs);
135 else if (pending & STATUSF_IP0)
136 do_IRQ(CPU_IRQ_BASE, regs);
137 else if (pending & STATUSF_IP1)
138 do_IRQ(CPU_IRQ_BASE + 1, regs);
139
140 vrc5476_irq_dispatch(regs);
141}
142
118void __init arch_init_irq(void) 143void __init arch_init_irq(void)
119{ 144{
120 /* hardware initialization */ 145 /* hardware initialization */
@@ -137,7 +162,4 @@ void __init arch_init_irq(void)
137 setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_LBRT, &irq_error); 162 setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_LBRT, &irq_error);
138 setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCIS, &irq_error); 163 setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCIS, &irq_error);
139 setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCI, &irq_error); 164 setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCI, &irq_error);
140
141 /* setup the grandpa intr vector */
142 set_except_vector(0, ddb5476_handle_int);
143} 165}
diff --git a/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c b/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c
index f66fe5b58636..a3c5e7b18018 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)
77} 77}
78 78
79 79
80asmlinkage void 80void
81vrc5476_irq_dispatch(struct pt_regs *regs) 81vrc5476_irq_dispatch(struct pt_regs *regs)
82{ 82{
83 extern void spurious_interrupt(void);
84
85 u32 mask; 83 u32 mask;
86 int nile4_irq; 84 int nile4_irq;
87 85
@@ -107,5 +105,5 @@ vrc5476_irq_dispatch(struct pt_regs *regs)
107 return; 105 return;
108 } 106 }
109 } 107 }
110 spurious_interrupt(); 108 spurious_interrupt(regs);
111} 109}
diff --git a/arch/mips/ddb5xxx/ddb5477/Makefile b/arch/mips/ddb5xxx/ddb5477/Makefile
index b79b43c9f93b..ea68815ad17a 100644
--- a/arch/mips/ddb5xxx/ddb5477/Makefile
+++ b/arch/mips/ddb5xxx/ddb5477/Makefile
@@ -2,7 +2,7 @@
2# Makefile for NEC DDB-Vrc5477 board 2# Makefile for NEC DDB-Vrc5477 board
3# 3#
4 4
5obj-y += int-handler.o irq.o irq_5477.o setup.o lcd44780.o 5obj-y += irq.o irq_5477.o setup.o lcd44780.o
6 6
7obj-$(CONFIG_RUNTIME_DEBUG) += debug.o 7obj-$(CONFIG_RUNTIME_DEBUG) += debug.o
8obj-$(CONFIG_KGDB) += kgdb_io.o 8obj-$(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 a2502a14400e..000000000000
--- a/arch/mips/ddb5xxx/ddb5477/int-handler.S
+++ /dev/null
@@ -1,75 +0,0 @@
1/*
2 * Copyright 2001 MontaVista Software Inc.
3 * Author: jsun@mvista.com or jsun@junsun.net
4 *
5 * First-level interrupt dispatcher for ddb5477
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12#include <asm/asm.h>
13#include <asm/mipsregs.h>
14#include <asm/addrspace.h>
15#include <asm/regdef.h>
16#include <asm/stackframe.h>
17#include <asm/ddb5xxx/ddb5477.h>
18
19/*
20 * first level interrupt dispatcher for ocelot board -
21 * We check for the timer first, then check PCI ints A and D.
22 * Then check for serial IRQ and fall through.
23 */
24 .align 5
25 NESTED(ddb5477_handle_int, PT_SIZE, sp)
26 SAVE_ALL
27 CLI
28 .set at
29 .set noreorder
30 mfc0 t0, CP0_CAUSE
31 mfc0 t2, CP0_STATUS
32
33 and t0, t2
34
35 andi t1, t0, STATUSF_IP7 /* cpu timer */
36 bnez t1, ll_cputimer_irq
37 andi t1, t0, (STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 )
38 bnez t1, ll_vrc5477_irq
39 andi t1, t0, STATUSF_IP0 /* software int 0 */
40 bnez t1, ll_cpu_ip0
41 andi t1, t0, STATUSF_IP1 /* software int 1 */
42 bnez t1, ll_cpu_ip1
43 nop
44 .set reorder
45
46 /* wrong alarm or masked ... */
47 j spurious_interrupt
48 nop
49 END(ddb5477_handle_int)
50
51 .align 5
52
53ll_vrc5477_irq:
54 move a0, sp
55 jal vrc5477_irq_dispatch
56 j ret_from_irq
57
58ll_cputimer_irq:
59 li a0, CPU_IRQ_BASE + 7
60 move a1, sp
61 jal do_IRQ
62 j ret_from_irq
63
64
65ll_cpu_ip0:
66 li a0, CPU_IRQ_BASE + 0
67 move a1, sp
68 jal do_IRQ
69 j ret_from_irq
70
71ll_cpu_ip1:
72 li a0, CPU_IRQ_BASE + 1
73 move a1, sp
74 jal do_IRQ
75 j ret_from_irq
diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c
index 9ffe1a9142ca..de433cf9fb50 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)
75 75
76extern void vrc5477_irq_init(u32 base); 76extern void vrc5477_irq_init(u32 base);
77extern void mips_cpu_irq_init(u32 base); 77extern void mips_cpu_irq_init(u32 base);
78extern asmlinkage void ddb5477_handle_int(void);
79extern int setup_irq(unsigned int irq, struct irqaction *irqaction); 78extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
80static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; 79static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
81 80
@@ -135,9 +134,6 @@ void __init arch_init_irq(void)
135 /* setup cascade interrupts */ 134 /* setup cascade interrupts */
136 setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade); 135 setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade);
137 setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade); 136 setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);
138
139 /* hook up the first-level interrupt handler */
140 set_except_vector(0, ddb5477_handle_int);
141} 137}
142 138
143u8 i8259_interrupt_ack(void) 139u8 i8259_interrupt_ack(void)
@@ -159,7 +155,7 @@ u8 i8259_interrupt_ack(void)
159 * the first level int-handler will jump here if it is a vrc5477 irq 155 * the first level int-handler will jump here if it is a vrc5477 irq
160 */ 156 */
161#define NUM_5477_IRQS 32 157#define NUM_5477_IRQS 32
162asmlinkage void 158static void
163vrc5477_irq_dispatch(struct pt_regs *regs) 159vrc5477_irq_dispatch(struct pt_regs *regs)
164{ 160{
165 u32 intStatus; 161 u32 intStatus;
@@ -197,3 +193,21 @@ vrc5477_irq_dispatch(struct pt_regs *regs)
197 } 193 }
198 } 194 }
199} 195}
196
197#define VR5477INTS (STATUSF_IP2|STATUSF_IP3|STATUSF_IP4|STATUSF_IP5|STATUSF_IP6)
198
199asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
200{
201 unsigned int pending = read_c0_cause() & read_c0_status();
202
203 if (pending & STATUSF_IP7)
204 do_IRQ(CPU_IRQ_BASE + 7, regs);
205 else if (pending & VR5477INTS)
206 vrc5477_irq_dispatch(regs);
207 else if (pending & STATUSF_IP0)
208 do_IRQ(CPU_IRQ_BASE, regs);
209 else if (pending & STATUSF_IP1)
210 do_IRQ(CPU_IRQ_BASE + 1, regs);
211 else
212 spurious_interrupt(regs);
213}
diff --git a/arch/mips/dec/boot/decstation.c b/arch/mips/dec/boot/decstation.c
index 56fd4277555e..4db8bacaf22d 100644
--- a/arch/mips/dec/boot/decstation.c
+++ b/arch/mips/dec/boot/decstation.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * arch/mips/dec/decstation.c 2 * arch/mips/dec/decstation.c
3 */ 3 */
4#include <asm/sections.h>
4 5
5#define RELOC 6#define RELOC
6#define INITRD 7#define INITRD
@@ -24,7 +25,7 @@
24#define INITRD_START (*(unsigned long *) (PARAM+0x218)) 25#define INITRD_START (*(unsigned long *) (PARAM+0x218))
25#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) 26#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
26 27
27extern int _ftext, _end; /* begin and end of kernel image */ 28extern int _ftext; /* begin and end of kernel image */
28extern void kernel_entry(int, char **, unsigned long, int *); 29extern void kernel_entry(int, char **, unsigned long, int *);
29 30
30void * memcpy(void * dest, const void *src, unsigned int count) 31void * 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 41fa372007bf..e8ec93e33fe6 100644
--- a/arch/mips/dec/int-handler.S
+++ b/arch/mips/dec/int-handler.S
@@ -36,7 +36,7 @@
36 .text 36 .text
37 .set noreorder 37 .set noreorder
38/* 38/*
39 * decstation_handle_int: Interrupt handler for DECstations 39 * plat_irq_dispatch: Interrupt handler for DECstations
40 * 40 *
41 * We follow the model in the Indy interrupt code by David Miller, where he 41 * We follow the model in the Indy interrupt code by David Miller, where he
42 * says: a lot of complication here is taken away because: 42 * says: a lot of complication here is taken away because:
@@ -125,11 +125,7 @@
125 * just take another exception, big deal. 125 * just take another exception, big deal.
126 */ 126 */
127 .align 5 127 .align 5
128 NESTED(decstation_handle_int, PT_SIZE, ra) 128 NESTED(plat_irq_dispatch, PT_SIZE, ra)
129 .set noat
130 SAVE_ALL
131 CLI # TEST: interrupts should be off
132 .set at
133 .set noreorder 129 .set noreorder
134 130
135 /* 131 /*
@@ -282,9 +278,11 @@ fpu:
282#endif 278#endif
283 279
284spurious: 280spurious:
285 j spurious_interrupt 281 jal spurious_interrupt
286 nop 282 nop
287 END(decstation_handle_int) 283 j ret_from_irq
284 nop
285 END(plat_irq_dispatch)
288 286
289/* 287/*
290 * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl 288 * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index 7c1ca8f6330e..ad5d436d80c1 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -48,8 +48,6 @@ extern void dec_machine_halt(void);
48extern void dec_machine_power_off(void); 48extern void dec_machine_power_off(void);
49extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs); 49extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs);
50 50
51extern asmlinkage void decstation_handle_int(void);
52
53unsigned long dec_kn_slot_base, dec_kn_slot_size; 51unsigned long dec_kn_slot_base, dec_kn_slot_size;
54 52
55EXPORT_SYMBOL(dec_kn_slot_base); 53EXPORT_SYMBOL(dec_kn_slot_base);
@@ -744,7 +742,6 @@ void __init arch_init_irq(void)
744 panic("Don't know how to set this up!"); 742 panic("Don't know how to set this up!");
745 break; 743 break;
746 } 744 }
747 set_except_vector(0, decstation_handle_int);
748 745
749 /* Free the FPU interrupt if the exception is present. */ 746 /* Free the FPU interrupt if the exception is present. */
750 if (!cpu_has_nofpuex) { 747 if (!cpu_has_nofpuex) {
diff --git a/arch/mips/galileo-boards/ev96100/Makefile b/arch/mips/galileo-boards/ev96100/Makefile
index 58c02f9db69d..cd868ec78cbc 100644
--- a/arch/mips/galileo-boards/ev96100/Makefile
+++ b/arch/mips/galileo-boards/ev96100/Makefile
@@ -6,4 +6,4 @@
6# Makefile for the Galileo EV96100 board. 6# Makefile for the Galileo EV96100 board.
7# 7#
8 8
9obj-y += init.o irq.o puts.o reset.o time.o int-handler.o setup.o 9obj-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 ff4d10a38859..000000000000
--- a/arch/mips/galileo-boards/ev96100/int-handler.S
+++ /dev/null
@@ -1,33 +0,0 @@
1#include <asm/asm.h>
2#include <asm/mipsregs.h>
3#include <asm/regdef.h>
4#include <asm/stackframe.h>
5
6 .set noat
7 .align 5
8
9NESTED(ev96100IRQ, PT_SIZE, sp)
10 SAVE_ALL
11 CLI # Important: mark KERNEL mode !
12
13 mfc0 t0, CP0_CAUSE # get pending interrupts
14 mfc0 t1, CP0_STATUS # get enabled interrupts
15 and t0, t1 # isolate allowed ones
16
17 # FIX ME add R7000 extensions
18 andi t0,0xff00 # isolate pending bits
19 andi a0, t0, CAUSEF_IP7
20 beq a0, zero, 1f
21 move a0, sp
22 jal mips_timer_interrupt
23 j ret_from_irq
24
251: beqz t0, 3f # spurious interrupt
26
27 move a0, t0
28 move a1, sp
29 jal ev96100_cpu_irq
30 j ret_from_irq
31
323: j spurious_interrupt
33 END(ev96100IRQ)
diff --git a/arch/mips/galileo-boards/ev96100/irq.c b/arch/mips/galileo-boards/ev96100/irq.c
index 97bf094da4fe..ee5d6720f23b 100644
--- a/arch/mips/galileo-boards/ev96100/irq.c
+++ b/arch/mips/galileo-boards/ev96100/irq.c
@@ -40,8 +40,6 @@
40#include <linux/interrupt.h> 40#include <linux/interrupt.h>
41#include <asm/irq_cpu.h> 41#include <asm/irq_cpu.h>
42 42
43extern asmlinkage void ev96100IRQ(void);
44
45static inline unsigned int ffz8(unsigned int word) 43static inline unsigned int ffz8(unsigned int word)
46{ 44{
47 unsigned long k; 45 unsigned long k;
@@ -54,13 +52,26 @@ static inline unsigned int ffz8(unsigned int word)
54 return k; 52 return k;
55} 53}
56 54
57asmlinkage void ev96100_cpu_irq(unsigned int pendin) 55extern void mips_timer_interrupt(struct pt_regs *regs);
56
57asmlinkage void ev96100_cpu_irq(unsigned int pending, struct pt_regs *regs)
58{ 58{
59 do_IRQ(ffz8(pending >> 8), regs); 59 do_IRQ(ffz8(pending >> 8), regs);
60} 60}
61 61
62asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
63{
64 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
65
66 if (pending & CAUSEF_IP7)
67 mips_timer_interrupt(regs);
68 else if (pending)
69 ev96100_cpu_irq(pending, regs);
70 else
71 spurious_interrupt(regs);
72}
73
62void __init arch_init_irq(void) 74void __init arch_init_irq(void)
63{ 75{
64 set_except_vector(0, ev96100IRQ);
65 mips_cpu_irq_init(0); 76 mips_cpu_irq_init(0);
66} 77}
diff --git a/arch/mips/gt64120/ev64120/Makefile b/arch/mips/gt64120/ev64120/Makefile
index ebe91c57e173..b2c53a8f8718 100644
--- a/arch/mips/gt64120/ev64120/Makefile
+++ b/arch/mips/gt64120/ev64120/Makefile
@@ -6,6 +6,6 @@
6# Makefile for the Galileo EV64120 board. 6# Makefile for the Galileo EV64120 board.
7# 7#
8 8
9obj-y += int-handler.o irq.o promcon.o reset.o serialGT.o setup.o 9obj-y += irq.o promcon.o reset.o serialGT.o setup.o
10 10
11EXTRA_AFLAGS := $(CFLAGS) 11EXTRA_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 752435faf2de..000000000000
--- a/arch/mips/gt64120/ev64120/int-handler.S
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 * int-handler.S
3 *
4 * Based on the cobalt handler.
5 */
6#include <asm/asm.h>
7#include <asm/mipsregs.h>
8#include <asm/addrspace.h>
9#include <asm/regdef.h>
10#include <asm/stackframe.h>
11
12/*
13 * galileo_handle_int -
14 * We check for the timer first, then check PCI ints A and D.
15 * Then check for serial IRQ and fall through.
16 */
17 .align 5
18 .set reorder
19 .set noat
20 NESTED(galileo_handle_int, PT_SIZE, sp)
21 SAVE_ALL
22 CLI
23 .set at
24 mfc0 t0,CP0_CAUSE
25 mfc0 t2,CP0_STATUS
26
27 and t0,t2
28
29 andi t1,t0,STATUSF_IP4 /* int2 hardware line (timer) */
30 bnez t1,ll_gt64120_irq
31 andi t1,t0,STATUSF_IP2 /* int0 hardware line */
32 bnez t1,ll_pci_intA
33 andi t1,t0,STATUSF_IP5 /* int3 hardware line */
34 bnez t1,ll_pci_intD
35 andi t1,t0,STATUSF_IP6 /* int4 hardware line */
36 bnez t1,ll_serial_irq
37 andi t1,t0,STATUSF_IP7 /* compare int */
38 bnez t1,ll_compare_irq
39 nop
40
41 /* wrong alarm or masked ... */
42 j spurious_interrupt
43 nop
44 END(galileo_handle_int)
45
46
47 .align 5
48 .set reorder
49ll_gt64120_irq:
50 li a0,4
51 move a1,sp
52 jal do_IRQ
53 nop
54 j ret_from_irq
55 nop
56
57 .align 5
58 .set reorder
59ll_compare_irq:
60 li a0,7
61 move a1,sp
62 jal do_IRQ
63 nop
64 j ret_from_irq
65 nop
66
67 .align 5
68 .set reorder
69ll_pci_intA:
70 move a0,sp
71 jal pci_intA
72 nop
73 j ret_from_irq
74 nop
75
76#if 0
77 .align 5
78 .set reorder
79ll_pci_intB:
80 move a0,sp
81 jal pci_intB
82 nop
83 j ret_from_irq
84 nop
85
86 .align 5
87 .set reorder
88ll_pci_intC:
89 move a0,sp
90 jal pci_intC
91 nop
92 j ret_from_irq
93 nop
94#endif
95
96 .align 5
97 .set reorder
98ll_pci_intD:
99 move a0,sp
100 jal pci_intD
101 nop
102 j ret_from_irq
103 nop
104
105 .align 5
106 .set reorder
107ll_serial_irq:
108 li a0,6
109 move a1,sp
110 jal do_IRQ
111 nop
112 j ret_from_irq
113 nop
diff --git a/arch/mips/gt64120/ev64120/irq.c b/arch/mips/gt64120/ev64120/irq.c
index 3b186159b21a..46c468b26b30 100644
--- a/arch/mips/gt64120/ev64120/irq.c
+++ b/arch/mips/gt64120/ev64120/irq.c
@@ -46,14 +46,22 @@
46#include <asm/system.h> 46#include <asm/system.h>
47#include <asm/gt64120.h> 47#include <asm/gt64120.h>
48 48
49asmlinkage inline void pci_intA(struct pt_regs *regs) 49asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
50{ 50{
51 do_IRQ(GT_INTA, regs); 51 unsigned int pending = read_c0_status() & read_c0_cause();
52} 52
53 53 if (pending & STATUSF_IP4) /* int2 hardware line (timer) */
54asmlinkage inline void pci_intD(struct pt_regs *regs) 54 do_IRQ(4, regs);
55{ 55 else if (pending & STATUSF_IP2) /* int0 hardware line */
56 do_IRQ(GT_INTD, regs); 56 do_IRQ(GT_INTA, regs);
57 else if (pending & STATUSF_IP5) /* int3 hardware line */
58 do_IRQ(GT_INTD, regs);
59 else if (pending & STATUSF_IP6) /* int4 hardware line */
60 do_IRQ(6, regs);
61 else if (pending & STATUSF_IP7) /* compare int */
62 do_IRQ(7, regs);
63 else
64 spurious_interrupt(regs);
57} 65}
58 66
59static void disable_ev64120_irq(unsigned int irq_nr) 67static void disable_ev64120_irq(unsigned int irq_nr)
@@ -109,16 +117,11 @@ static struct hw_interrupt_type ev64120_irq_type = {
109 117
110void gt64120_irq_setup(void) 118void gt64120_irq_setup(void)
111{ 119{
112 extern asmlinkage void galileo_handle_int(void);
113
114 /* 120 /*
115 * Clear all of the interrupts while we change the able around a bit. 121 * Clear all of the interrupts while we change the able around a bit.
116 */ 122 */
117 clear_c0_status(ST0_IM); 123 clear_c0_status(ST0_IM);
118 124
119 /* Sets the exception_handler array. */
120 set_except_vector(0, galileo_handle_int);
121
122 local_irq_disable(); 125 local_irq_disable();
123 126
124 /* 127 /*
diff --git a/arch/mips/gt64120/momenco_ocelot/Makefile b/arch/mips/gt64120/momenco_ocelot/Makefile
index 7b59c6567c79..6f708df8373b 100644
--- a/arch/mips/gt64120/momenco_ocelot/Makefile
+++ b/arch/mips/gt64120/momenco_ocelot/Makefile
@@ -2,7 +2,7 @@
2# Makefile for Momentum's Ocelot board. 2# Makefile for Momentum's Ocelot board.
3# 3#
4 4
5obj-y += int-handler.o irq.o prom.o reset.o setup.o 5obj-y += irq.o prom.o reset.o setup.o
6 6
7obj-$(CONFIG_KGDB) += dbg_io.o 7obj-$(CONFIG_KGDB) += dbg_io.o
8 8
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 808acef248cc..000000000000
--- a/arch/mips/gt64120/momenco_ocelot/int-handler.S
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 * Copyright 2001 MontaVista Software Inc.
3 * Author: jsun@mvista.com or jsun@junsun.net
4 *
5 * First-level interrupt dispatcher for ocelot board.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12#include <asm/asm.h>
13#include <asm/mipsregs.h>
14#include <asm/addrspace.h>
15#include <asm/regdef.h>
16#include <asm/stackframe.h>
17
18/*
19 * first level interrupt dispatcher for ocelot board -
20 * We check for the timer first, then check PCI ints A and D.
21 * Then check for serial IRQ and fall through.
22 */
23 .align 5
24 NESTED(ocelot_handle_int, PT_SIZE, sp)
25 SAVE_ALL
26 CLI
27 .set at
28 mfc0 t0, CP0_CAUSE
29 mfc0 t2, CP0_STATUS
30
31 and t0, t2
32
33 andi t1, t0, STATUSF_IP2 /* int0 hardware line */
34 bnez t1, ll_pri_enet_irq
35 andi t1, t0, STATUSF_IP3 /* int1 hardware line */
36 bnez t1, ll_sec_enet_irq
37 andi t1, t0, STATUSF_IP4 /* int2 hardware line */
38 bnez t1, ll_uart1_irq
39 andi t1, t0, STATUSF_IP5 /* int3 hardware line */
40 bnez t1, ll_cpci_irq
41 andi t1, t0, STATUSF_IP6 /* int4 hardware line */
42 bnez t1, ll_galileo_irq
43 andi t1, t0, STATUSF_IP7 /* cpu timer */
44 bnez t1, ll_cputimer_irq
45
46 /* now look at the extended interrupts */
47 mfc0 t0, CP0_CAUSE
48 cfc0 t1, CP0_S1_INTCONTROL
49
50 /* shift the mask 8 bits left to line up the bits */
51 sll t2, t1, 8
52
53 and t0, t2
54 srl t0, t0, 16
55
56 andi t1, t0, STATUSF_IP8 /* int6 hardware line */
57 bnez t1, ll_pmc1_irq
58 andi t1, t0, STATUSF_IP9 /* int7 hardware line */
59 bnez t1, ll_pmc2_irq
60 andi t1, t0, STATUSF_IP10 /* int8 hardware line */
61 bnez t1, ll_cpci_abcd_irq
62 andi t1, t0, STATUSF_IP11 /* int9 hardware line */
63 bnez t1, ll_uart2_irq
64
65 .set reorder
66
67 /* wrong alarm or masked ... */
68 j spurious_interrupt
69 nop
70 END(ocelot_handle_int)
71
72 .align 5
73ll_pri_enet_irq:
74 li a0, 2
75 move a1, sp
76 jal do_IRQ
77 j ret_from_irq
78
79ll_sec_enet_irq:
80 li a0, 3
81 move a1, sp
82 jal do_IRQ
83 j ret_from_irq
84
85ll_uart1_irq:
86 li a0, 4
87 move a1, sp
88 jal do_IRQ
89 j ret_from_irq
90
91ll_cpci_irq:
92 li a0, 5
93 move a1, sp
94 jal do_IRQ
95 j ret_from_irq
96
97ll_galileo_irq:
98 li a0, 6
99 move a1, sp
100 jal do_IRQ
101 j ret_from_irq
102
103ll_cputimer_irq:
104 li a0, 7
105 move a1, sp
106 jal do_IRQ
107 j ret_from_irq
108
109ll_pmc1_irq:
110 li a0, 8
111 move a1, sp
112 jal do_IRQ
113 j ret_from_irq
114
115ll_pmc2_irq:
116 li a0, 9
117 move a1, sp
118 jal do_IRQ
119 j ret_from_irq
120
121ll_cpci_abcd_irq:
122 li a0, 10
123 move a1, sp
124 jal do_IRQ
125 j ret_from_irq
126
127ll_uart2_irq:
128 li a0, 11
129 move a1, sp
130 jal do_IRQ
131 j ret_from_irq
diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c
index 4f108da71b23..885f67f32ea3 100644
--- a/arch/mips/gt64120/momenco_ocelot/irq.c
+++ b/arch/mips/gt64120/momenco_ocelot/irq.c
@@ -48,7 +48,38 @@
48#include <asm/mipsregs.h> 48#include <asm/mipsregs.h>
49#include <asm/system.h> 49#include <asm/system.h>
50 50
51extern asmlinkage void ocelot_handle_int(void); 51asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
52{
53 unsigned int pending = read_c0_status() & read_c0_cause();
54
55 if (pending & STATUSF_IP2) /* int0 hardware line */
56 do_IRQ(2, regs);
57 else if (pending & STATUSF_IP3) /* int1 hardware line */
58 do_IRQ(3, regs);
59 else if (pending & STATUSF_IP4) /* int2 hardware line */
60 do_IRQ(4, regs);
61 else if (pending & STATUSF_IP5) /* int3 hardware line */
62 do_IRQ(5, regs);
63 else if (pending & STATUSF_IP6) /* int4 hardware line */
64 do_IRQ(6, regs);
65 else if (pending & STATUSF_IP7) /* cpu timer */
66 do_IRQ(7, regs);
67 else {
68 /*
69 * Now look at the extended interrupts
70 */
71 pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
72
73 if (pending & STATUSF_IP8) /* int6 hardware line */
74 do_IRQ(8, regs);
75 else if (pending & STATUSF_IP9) /* int7 hardware line */
76 do_IRQ(9, regs);
77 else if (pending & STATUSF_IP10) /* int8 hardware line */
78 do_IRQ(10, regs);
79 else if (pending & STATUSF_IP11) /* int9 hardware line */
80 do_IRQ(11, regs);
81 }
82}
52 83
53void __init arch_init_irq(void) 84void __init arch_init_irq(void)
54{ 85{
@@ -59,9 +90,6 @@ void __init arch_init_irq(void)
59 clear_c0_status(ST0_IM); 90 clear_c0_status(ST0_IM);
60 local_irq_disable(); 91 local_irq_disable();
61 92
62 /* Sets the first-level interrupt dispatcher. */
63 set_except_vector(0, ocelot_handle_int);
64
65 mips_cpu_irq_init(0); 93 mips_cpu_irq_init(0);
66 rm7k_cpu_irq_init(8); 94 rm7k_cpu_irq_init(8);
67} 95}
diff --git a/arch/mips/ite-boards/generic/Makefile b/arch/mips/ite-boards/generic/Makefile
index 0e7853f43983..63431538d0ec 100644
--- a/arch/mips/ite-boards/generic/Makefile
+++ b/arch/mips/ite-boards/generic/Makefile
@@ -6,7 +6,7 @@
6# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files. 6# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files.
7# 7#
8 8
9obj-y += it8172_setup.o irq.o int-handler.o pmon_prom.o \ 9obj-y += it8172_setup.o irq.o pmon_prom.o \
10 time.o lpc.o puts.o reset.o 10 time.o lpc.o puts.o reset.o
11 11
12obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o 12obj-$(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 d190d8add9cb..000000000000
--- a/arch/mips/ite-boards/generic/int-handler.S
+++ /dev/null
@@ -1,63 +0,0 @@
1#include <asm/asm.h>
2#include <asm/mipsregs.h>
3#include <asm/regdef.h>
4#include <asm/stackframe.h>
5
6 .text
7 .set macro
8 .set noat
9 .align 5
10
11NESTED(it8172_IRQ, PT_SIZE, sp)
12 SAVE_ALL
13 CLI # Important: mark KERNEL mode !
14
15 /* We're working with 'reorder' set at this point. */
16 /*
17 * Get pending interrupts
18 */
19
20 mfc0 t0,CP0_CAUSE # get pending interrupts
21 mfc0 t1,CP0_STATUS # get enabled interrupts
22 and t0,t1 # isolate allowed ones
23
24 andi t0,0xff00 # isolate pending bits
25 beqz t0, 3f # spurious interrupt
26
27 andi a0, t0, CAUSEF_IP7
28 beq a0, zero, 1f
29
30 li a0, 127 # MIPS_CPU_TIMER_IRQ = (NR_IRQS-1)
31 move a1, sp
32 jal ll_timer_interrupt
33 j ret_from_irq
34 nop
35
361:
37 andi a0, t0, CAUSEF_IP2 # the only int we expect at this time
38 beq a0, zero, 3f
39 move a0,sp
40 jal it8172_hw0_irqdispatch
41
42 mfc0 t0,CP0_STATUS # disable interrupts
43 ori t0,1
44 xori t0,1
45 mtc0 t0,CP0_STATUS
46 nop
47 nop
48 nop
49
50 la a1, ret_from_irq
51 jr a1
52 nop
53
543:
55 move a0, sp
56 jal mips_spurious_interrupt
57 nop
58 la a1, ret_from_irq
59 jr a1
60 nop
61
62END(it8172_IRQ)
63
diff --git a/arch/mips/ite-boards/generic/irq.c b/arch/mips/ite-boards/generic/irq.c
index e67f96129491..77be7216bdd0 100644
--- a/arch/mips/ite-boards/generic/irq.c
+++ b/arch/mips/ite-boards/generic/irq.c
@@ -62,12 +62,8 @@
62 62
63#define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4) 63#define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
64 64
65void disable_it8172_irq(unsigned int irq_nr);
66void enable_it8172_irq(unsigned int irq_nr);
67
68extern void set_debug_traps(void); 65extern void set_debug_traps(void);
69extern void mips_timer_interrupt(int irq, struct pt_regs *regs); 66extern void mips_timer_interrupt(int irq, struct pt_regs *regs);
70extern asmlinkage void it8172_IRQ(void);
71 67
72struct it8172_intc_regs volatile *it8172_hw0_icregs = 68struct it8172_intc_regs volatile *it8172_hw0_icregs =
73 (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE)); 69 (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE));
@@ -181,8 +177,6 @@ void __init arch_init_irq(void)
181 int i; 177 int i;
182 unsigned long flags; 178 unsigned long flags;
183 179
184 set_except_vector(0, it8172_IRQ);
185
186 /* mask all interrupts */ 180 /* mask all interrupts */
187 it8172_hw0_icregs->lb_mask = 0xffff; 181 it8172_hw0_icregs->lb_mask = 0xffff;
188 it8172_hw0_icregs->lpc_mask = 0xffff; 182 it8172_hw0_icregs->lpc_mask = 0xffff;
@@ -282,6 +276,18 @@ void it8172_hw0_irqdispatch(struct pt_regs *regs)
282 do_IRQ(irq, regs); 276 do_IRQ(irq, regs);
283} 277}
284 278
279asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
280{
281 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
282
283 if (!pending)
284 mips_spurious_interrupt(regs);
285 else if (pending & CAUSEF_IP7)
286 ll_timer_interrupt(127, regs);
287 else if (pending & CAUSEF_IP2)
288 it8172_hw0_irqdispatch(regs);
289}
290
285void show_pending_irqs(void) 291void show_pending_irqs(void)
286{ 292{
287 fputs("intstatus: "); 293 fputs("intstatus: ");
diff --git a/arch/mips/ite-boards/generic/time.c b/arch/mips/ite-boards/generic/time.c
index b79817bb6cce..dee497a91807 100644
--- a/arch/mips/ite-boards/generic/time.c
+++ b/arch/mips/ite-boards/generic/time.c
@@ -29,6 +29,7 @@
29#include <linux/sched.h> 29#include <linux/sched.h>
30#include <linux/time.h> 30#include <linux/time.h>
31#include <linux/spinlock.h> 31#include <linux/spinlock.h>
32#include <linux/mc146818rtc.h>
32 33
33#include <asm/time.h> 34#include <asm/time.h>
34#include <asm/mipsregs.h> 35#include <asm/mipsregs.h>
diff --git a/arch/mips/ite-boards/ivr/init.c b/arch/mips/ite-boards/ivr/init.c
index b774db035b31..05cf9218c432 100644
--- a/arch/mips/ite-boards/ivr/init.c
+++ b/arch/mips/ite-boards/ivr/init.c
@@ -34,13 +34,13 @@
34#include <asm/bootinfo.h> 34#include <asm/bootinfo.h>
35#include <linux/string.h> 35#include <linux/string.h>
36#include <linux/kernel.h> 36#include <linux/kernel.h>
37#include <asm/sections.h>
37#include <asm/it8172/it8172.h> 38#include <asm/it8172/it8172.h>
38#include <asm/it8172/it8172_dbg.h> 39#include <asm/it8172/it8172_dbg.h>
39 40
40int prom_argc; 41int prom_argc;
41char **prom_argv, **prom_envp; 42char **prom_argv, **prom_envp;
42 43
43extern char _end;
44extern void __init prom_init_cmdline(void); 44extern void __init prom_init_cmdline(void);
45extern unsigned long __init prom_get_memsize(void); 45extern unsigned long __init prom_get_memsize(void);
46extern void __init it8172_init_ram_resource(unsigned long memsize); 46extern 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 e8ec8be66a80..ea2a754cafe5 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 @@
34#include <asm/bootinfo.h> 34#include <asm/bootinfo.h>
35#include <linux/string.h> 35#include <linux/string.h>
36#include <linux/kernel.h> 36#include <linux/kernel.h>
37#include <asm/sections.h>
37#include <asm/it8172/it8172.h> 38#include <asm/it8172/it8172.h>
38#include <asm/it8172/it8172_dbg.h> 39#include <asm/it8172/it8172_dbg.h>
39 40
40int prom_argc; 41int prom_argc;
41char **prom_argv, **prom_envp; 42char **prom_argv, **prom_envp;
42 43
43extern char _end;
44extern void __init prom_init_cmdline(void); 44extern void __init prom_init_cmdline(void);
45extern unsigned long __init prom_get_memsize(void); 45extern unsigned long __init prom_get_memsize(void);
46extern void __init it8172_init_ram_resource(unsigned long memsize); 46extern void __init it8172_init_ram_resource(unsigned long memsize);
diff --git a/arch/mips/jazz/Makefile b/arch/mips/jazz/Makefile
index 85749246a671..02bd39add891 100644
--- a/arch/mips/jazz/Makefile
+++ b/arch/mips/jazz/Makefile
@@ -2,6 +2,6 @@
2# Makefile for the Jazz family specific parts of the kernel 2# Makefile for the Jazz family specific parts of the kernel
3# 3#
4 4
5obj-y := int-handler.o irq.o jazzdma.o reset.o setup.o 5obj-y := irq.o jazzdma.o reset.o setup.o
6 6
7EXTRA_AFLAGS := $(CFLAGS) 7EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/jazz/int-handler.S b/arch/mips/jazz/int-handler.S
deleted file mode 100644
index dc752c67b528..000000000000
--- a/arch/mips/jazz/int-handler.S
+++ /dev/null
@@ -1,282 +0,0 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle and Andreas Busse
7 *
8 * Jazz family specific interrupt stuff
9 *
10 * To do: On Jazz machines we remap some non-ISA interrupts to ISA
11 * interrupts. These interrupts should use their own vectors.
12 * Squeeze the last cycles out of the handlers. Only a dead
13 * cycle is a good cycle.
14 */
15#include <asm/asm.h>
16#include <asm/mipsregs.h>
17#include <asm/jazz.h>
18#include <asm/regdef.h>
19#include <asm/stackframe.h>
20
21/*
22 * jazz_handle_int: Interrupt handler for the ACER Pica-61 boards
23 */
24 .set noreorder
25
26 NESTED(jazz_handle_int, PT_SIZE, ra)
27 .set noat
28 SAVE_ALL
29 CLI
30 .set at
31
32 /*
33 * Get pending interrupts
34 */
35 mfc0 t0,CP0_CAUSE # get pending interrupts
36 mfc0 t1,CP0_STATUS # get enabled interrupts
37 and t0,t1 # isolate allowed ones
38 andi t0,0xff00 # isolate pending bits
39 beqz t0,3f
40 sll t0,16 # delay slot
41
42 /*
43 * Find irq with highest priority
44 * FIXME: This is slow - use binary search
45 */
46 la t1,ll_vectors
471: bltz t0,2f # found pending irq
48 sll t0,1
49 b 1b
50 subu t1,PTRSIZE # delay slot
51
52 /*
53 * Do the low-level stuff
54 */
552: lw t0,(t1)
56 jr t0
57 nop # delay slot
58 END(jazz_handle_int)
59
60ll_sw0: li s1,~IE_SW0
61 mfc0 t0,CP0_CAUSE
62 and t0,s1
63 mtc0 t0,CP0_CAUSE
64 PANIC("Unimplemented sw0 handler")
65
66ll_sw1: li s1,~IE_SW1
67 mfc0 t0,CP0_CAUSE
68 and t0,s1
69 mtc0 t0,CP0_CAUSE
70 PANIC("Unimplemented sw1 handler")
71
72ll_local_dma: li s1,~IE_IRQ0
73 PANIC("Unimplemented local_dma handler")
74
75ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE
76#if PTRSIZE == 8 /* True 64 bit kernel */
77 dsll t0,1
78#endif
79 .set reorder
80 LONG_L t0,local_vector(t0)
81 jr t0
82 .set noreorder
83
84/*
85 * The braindead PICA hardware gives us no way to distinguish if we really
86 * received interrupt 7 from the (E)ISA bus or if we just received an
87 * interrupt with no findable cause. This sometimes happens with braindead
88 * cards. Oh well - for all the Jazz boxes slots are more or less just
89 * whistles and bells and we're aware of the problem.
90 */
91ll_isa_irq: lw a0, JAZZ_EISA_IRQ_ACK
92
93 jal do_IRQ
94 move a1,sp
95
96 j ret_from_irq
97 nop
98
99/*
100 * Hmm... This is not just a plain PC clone so the question is
101 * which devices on Jazz machines can generate an (E)ISA NMI?
102 * (Writing to nonexistent memory?)
103 */
104ll_isa_nmi: li s1,~IE_IRQ3
105 PANIC("Unimplemented isa_nmi handler")
106
107/*
108 * Timer IRQ - remapped to be more similar to an IBM compatible.
109 *
110 * The timer interrupt is handled specially to ensure that the jiffies
111 * variable is updated at all times. Specifically, the timer interrupt is
112 * just like the complete handlers except that it is invoked with interrupts
113 * disabled and should never re-enable them. If other interrupts were
114 * allowed to be processed while the timer interrupt is active, then the
115 * other interrupts would have to avoid using the jiffies variable for delay
116 * and interval timing operations to avoid hanging the system.
117 */
118ll_timer: lw zero,JAZZ_TIMER_REGISTER # timer irq cleared on read
119 li s1,~IE_IRQ4
120
121 li a0, JAZZ_TIMER_IRQ
122 jal do_IRQ
123 move a1,sp
124
125 mfc0 t0,CP0_STATUS # disable interrupts again
126 ori t0,1
127 xori t0,1
128 mtc0 t0,CP0_STATUS
129
130 j ret_from_irq
131 nop
132
133/*
134 * CPU count/compare IRQ (unused)
135 */
136ll_count: j ret_from_irq
137 mtc0 zero,CP0_COMPARE
138
139#if 0
140/*
141 * Call the handler for the interrupt
142 * (Currently unused)
143 */
144call_real: /*
145 * temporarily disable interrupt
146 */
147 mfc0 t2,CP0_STATUS
148 and t2,s1
149 mtc0 t2,CP0_STATUS
150 nor s1,zero,s1
151 jal do_IRQ
152
153 /*
154 * reenable interrupt
155 */
156 mfc0 t2,CP0_STATUS
157 or t2,s1
158 mtc0 t2,CP0_STATUS
159 j ret_from_irq
160#endif
161
162 .data
163 PTR ll_sw0 # SW0
164 PTR ll_sw1 # SW1
165 PTR ll_local_dma # Local DMA
166 PTR ll_local_dev # Local devices
167 PTR ll_isa_irq # ISA IRQ
168 PTR ll_isa_nmi # ISA NMI
169 PTR ll_timer # Timer
170ll_vectors: PTR ll_count # Count/Compare IRQ
171
172 /*
173 * Interrupt handlers for local devices.
174 */
175 .text
176 .set reorder
177loc_no_irq: PANIC("Unimplemented loc_no_irq handler")
178/*
179 * Parallel port IRQ
180 */
181loc_parallel: li s1,~JAZZ_IE_PARALLEL
182 li a0,JAZZ_PARALLEL_IRQ
183 b loc_call
184
185/*
186 * Floppy IRQ
187 */
188loc_floppy: li s1,~JAZZ_IE_FLOPPY
189 li a0,JAZZ_FLOPPY_IRQ
190 b loc_call
191
192/*
193 * Sound IRQ
194 */
195loc_sound: PANIC("Unimplemented loc_sound handler")
196loc_video: PANIC("Unimplemented loc_video handler")
197
198/*
199 * Ethernet interrupt handler
200 */
201loc_ethernet: li s1,~JAZZ_IE_ETHERNET
202 li a0,JAZZ_ETHERNET_IRQ
203 b loc_call
204
205/*
206 * SCSI interrupt handler
207 */
208loc_scsi: li s1,~JAZZ_IE_SCSI
209 li a0,JAZZ_SCSI_IRQ
210 b loc_call
211
212/*
213 * Keyboard interrupt handler
214 */
215loc_keyboard: li s1,~JAZZ_IE_KEYBOARD
216 li a0,JAZZ_KEYBOARD_IRQ
217 b loc_call
218
219/*
220 * Mouse interrupt handler
221 */
222loc_mouse: li s1,~JAZZ_IE_MOUSE
223 li a0,JAZZ_MOUSE_IRQ
224 b loc_call
225
226/*
227 * Serial port 1 IRQ
228 */
229loc_serial1: li s1,~JAZZ_IE_SERIAL1
230 li a0,JAZZ_SERIAL1_IRQ
231 b loc_call
232
233/*
234 * Serial port 2 IRQ
235 */
236loc_serial2: li s1,~JAZZ_IE_SERIAL2
237 li a0,JAZZ_SERIAL2_IRQ
238 b loc_call
239
240/*
241 * Call the interrupt handler for an interrupt generated by a
242 * local device.
243 */
244loc_call: /*
245 * Temporarily disable interrupt source
246 */
247 lhu t2,JAZZ_IO_IRQ_ENABLE
248 and t2,s1
249 sh t2,JAZZ_IO_IRQ_ENABLE
250
251 nor s1,zero,s1
252 jal do_IRQ
253
254 /*
255 * Reenable interrupt
256 */
257 lhu t2,JAZZ_IO_IRQ_ENABLE
258 or t2,s1
259 sh t2,JAZZ_IO_IRQ_ENABLE
260
261 j ret_from_irq
262
263/*
264 * "Jump extender" to reach spurious_interrupt
265 */
2663: j spurious_interrupt
267
268/*
269 * Vectors for interrupts generated by local devices
270 */
271 .data
272local_vector: PTR loc_no_irq
273 PTR loc_parallel
274 PTR loc_floppy
275 PTR loc_sound
276 PTR loc_video
277 PTR loc_ethernet
278 PTR loc_scsi
279 PTR loc_keyboard
280 PTR loc_mouse
281 PTR loc_serial1
282 PTR loc_serial2
diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c
index b309b1bcf2e8..becc9accd495 100644
--- a/arch/mips/jazz/irq.c
+++ b/arch/mips/jazz/irq.c
@@ -15,8 +15,6 @@
15#include <asm/io.h> 15#include <asm/io.h>
16#include <asm/jazz.h> 16#include <asm/jazz.h>
17 17
18extern asmlinkage void jazz_handle_int(void);
19
20static DEFINE_SPINLOCK(r4030_lock); 18static DEFINE_SPINLOCK(r4030_lock);
21 19
22static void enable_r4030_irq(unsigned int irq) 20static void enable_r4030_irq(unsigned int irq)
@@ -90,10 +88,82 @@ void __init init_r4030_ints(void)
90 */ 88 */
91void __init arch_init_irq(void) 89void __init arch_init_irq(void)
92{ 90{
93 set_except_vector(0, jazz_handle_int);
94
95 init_i8259_irqs(); /* Integrated i8259 */ 91 init_i8259_irqs(); /* Integrated i8259 */
96 init_r4030_ints(); 92 init_r4030_ints();
97 93
98 change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1); 94 change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1);
99} 95}
96
97static void loc_call(unsigned int irq, struct pt_regs *regs, unsigned int mask)
98{
99 r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
100 r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) & mask);
101 do_IRQ(irq, regs);
102 r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
103 r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | mask);
104}
105
106static void ll_local_dev(struct pt_regs *regs)
107{
108 switch (r4030_read_reg32(JAZZ_IO_IRQ_SOURCE)) {
109 case 0:
110 panic("Unimplemented loc_no_irq handler");
111 break;
112 case 4:
113 loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_PARALLEL);
114 break;
115 case 8:
116 loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_FLOPPY);
117 break;
118 case 12:
119 panic("Unimplemented loc_sound handler");
120 break;
121 case 16:
122 panic("Unimplemented loc_video handler");
123 break;
124 case 20:
125 loc_call(JAZZ_ETHERNET_IRQ, regs, JAZZ_IE_ETHERNET);
126 break;
127 case 24:
128 loc_call(JAZZ_SCSI_IRQ, regs, JAZZ_IE_SCSI);
129 break;
130 case 28:
131 loc_call(JAZZ_KEYBOARD_IRQ, regs, JAZZ_IE_KEYBOARD);
132 break;
133 case 32:
134 loc_call(JAZZ_MOUSE_IRQ, regs, JAZZ_IE_MOUSE);
135 break;
136 case 36:
137 loc_call(JAZZ_SERIAL1_IRQ, regs, JAZZ_IE_SERIAL1);
138 break;
139 case 40:
140 loc_call(JAZZ_SERIAL2_IRQ, regs, JAZZ_IE_SERIAL2);
141 break;
142 }
143}
144
145asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
146{
147 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
148
149 if (pending & IE_IRQ5)
150 write_c0_compare(0);
151 else if (pending & IE_IRQ4) {
152 r4030_read_reg32(JAZZ_TIMER_REGISTER);
153 do_IRQ(JAZZ_TIMER_IRQ, regs);
154 } else if (pending & IE_IRQ3)
155 panic("Unimplemented ISA NMI handler");
156 else if (pending & IE_IRQ2)
157 do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK), regs);
158 else if (pending & IE_IRQ1) {
159 ll_local_dev(regs);
160 } else if (unlikely(pending & IE_IRQ0))
161 panic("Unimplemented local_dma handler");
162 else if (pending & IE_SW1) {
163 clear_c0_cause(IE_SW1);
164 panic("Unimplemented sw1 handler");
165 } else if (pending & IE_SW0) {
166 clear_c0_cause(IE_SW0);
167 panic("Unimplemented sw0 handler");
168 }
169}
diff --git a/arch/mips/jmr3927/common/rtc_ds1742.c b/arch/mips/jmr3927/common/rtc_ds1742.c
index a6bd3f4d3049..e6561345d12a 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)
60 unsigned long flags; 60 unsigned long flags;
61 61
62 spin_lock_irqsave(&rtc_lock, flags); 62 spin_lock_irqsave(&rtc_lock, flags);
63 CMOS_WRITE(RTC_READ, RTC_CONTROL); 63 rtc_write(RTC_READ, RTC_CONTROL);
64 second = BCD2BIN(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); 64 second = BCD2BIN(rtc_read(RTC_SECONDS) & RTC_SECONDS_MASK);
65 minute = BCD2BIN(CMOS_READ(RTC_MINUTES)); 65 minute = BCD2BIN(rtc_read(RTC_MINUTES));
66 hour = BCD2BIN(CMOS_READ(RTC_HOURS)); 66 hour = BCD2BIN(rtc_read(RTC_HOURS));
67 day = BCD2BIN(CMOS_READ(RTC_DATE)); 67 day = BCD2BIN(rtc_read(RTC_DATE));
68 month = BCD2BIN(CMOS_READ(RTC_MONTH)); 68 month = BCD2BIN(rtc_read(RTC_MONTH));
69 year = BCD2BIN(CMOS_READ(RTC_YEAR)); 69 year = BCD2BIN(rtc_read(RTC_YEAR));
70 century = BCD2BIN(CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK); 70 century = BCD2BIN(rtc_read(RTC_CENTURY) & RTC_CENTURY_MASK);
71 CMOS_WRITE(0, RTC_CONTROL); 71 rtc_write(0, RTC_CONTROL);
72 spin_unlock_irqrestore(&rtc_lock, flags); 72 spin_unlock_irqrestore(&rtc_lock, flags);
73 73
74 year += century * 100; 74 year += century * 100;
@@ -87,16 +87,16 @@ rtc_ds1742_set_time(unsigned long t)
87 unsigned long flags; 87 unsigned long flags;
88 88
89 spin_lock_irqsave(&rtc_lock, flags); 89 spin_lock_irqsave(&rtc_lock, flags);
90 CMOS_WRITE(RTC_READ, RTC_CONTROL); 90 rtc_write(RTC_READ, RTC_CONTROL);
91 cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); 91 cmos_second = (u8)(rtc_read(RTC_SECONDS) & RTC_SECONDS_MASK);
92 cmos_minute = (u8)CMOS_READ(RTC_MINUTES); 92 cmos_minute = (u8)rtc_read(RTC_MINUTES);
93 cmos_hour = (u8)CMOS_READ(RTC_HOURS); 93 cmos_hour = (u8)rtc_read(RTC_HOURS);
94 cmos_day = (u8)CMOS_READ(RTC_DATE); 94 cmos_day = (u8)rtc_read(RTC_DATE);
95 cmos_month = (u8)CMOS_READ(RTC_MONTH); 95 cmos_month = (u8)rtc_read(RTC_MONTH);
96 cmos_year = (u8)CMOS_READ(RTC_YEAR); 96 cmos_year = (u8)rtc_read(RTC_YEAR);
97 cmos_century = CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK; 97 cmos_century = rtc_read(RTC_CENTURY) & RTC_CENTURY_MASK;
98 98
99 CMOS_WRITE(RTC_WRITE, RTC_CONTROL); 99 rtc_write(RTC_WRITE, RTC_CONTROL);
100 100
101 /* convert */ 101 /* convert */
102 to_tm(t, &tm); 102 to_tm(t, &tm);
@@ -104,18 +104,18 @@ rtc_ds1742_set_time(unsigned long t)
104 /* check each field one by one */ 104 /* check each field one by one */
105 year = BIN2BCD(tm.tm_year - EPOCH); 105 year = BIN2BCD(tm.tm_year - EPOCH);
106 if (year != cmos_year) { 106 if (year != cmos_year) {
107 CMOS_WRITE(year,RTC_YEAR); 107 rtc_write(year,RTC_YEAR);
108 } 108 }
109 109
110 month = BIN2BCD(tm.tm_mon); 110 month = BIN2BCD(tm.tm_mon);
111 if (month != (cmos_month & 0x1f)) { 111 if (month != (cmos_month & 0x1f)) {
112 CMOS_WRITE((month & 0x1f) | (cmos_month & ~0x1f),RTC_MONTH); 112 rtc_write((month & 0x1f) | (cmos_month & ~0x1f),RTC_MONTH);
113 } 113 }
114 114
115 day = BIN2BCD(tm.tm_mday); 115 day = BIN2BCD(tm.tm_mday);
116 if (day != cmos_day) { 116 if (day != cmos_day) {
117 117
118 CMOS_WRITE(day, RTC_DATE); 118 rtc_write(day, RTC_DATE);
119 } 119 }
120 120
121 if (cmos_hour & 0x40) { 121 if (cmos_hour & 0x40) {
@@ -130,20 +130,20 @@ rtc_ds1742_set_time(unsigned long t)
130 /* 24 hour format */ 130 /* 24 hour format */
131 hour = BIN2BCD(tm.tm_hour) & 0x3f; 131 hour = BIN2BCD(tm.tm_hour) & 0x3f;
132 } 132 }
133 if (hour != cmos_hour) CMOS_WRITE(hour, RTC_HOURS); 133 if (hour != cmos_hour) rtc_write(hour, RTC_HOURS);
134 134
135 minute = BIN2BCD(tm.tm_min); 135 minute = BIN2BCD(tm.tm_min);
136 if (minute != cmos_minute) { 136 if (minute != cmos_minute) {
137 CMOS_WRITE(minute, RTC_MINUTES); 137 rtc_write(minute, RTC_MINUTES);
138 } 138 }
139 139
140 second = BIN2BCD(tm.tm_sec); 140 second = BIN2BCD(tm.tm_sec);
141 if (second != cmos_second) { 141 if (second != cmos_second) {
142 CMOS_WRITE(second & RTC_SECONDS_MASK,RTC_SECONDS); 142 rtc_write(second & RTC_SECONDS_MASK,RTC_SECONDS);
143 } 143 }
144 144
145 /* RTC_CENTURY and RTC_CONTROL share same address... */ 145 /* RTC_CENTURY and RTC_CONTROL share same address... */
146 CMOS_WRITE(cmos_century, RTC_CONTROL); 146 rtc_write(cmos_century, RTC_CONTROL);
147 spin_unlock_irqrestore(&rtc_lock, flags); 147 spin_unlock_irqrestore(&rtc_lock, flags);
148 148
149 return 0; 149 return 0;
@@ -163,9 +163,9 @@ rtc_ds1742_init(unsigned long base)
163 rtc_mips_set_time = rtc_ds1742_set_time; 163 rtc_mips_set_time = rtc_ds1742_set_time;
164 164
165 /* clear oscillator stop bit */ 165 /* clear oscillator stop bit */
166 CMOS_WRITE(RTC_READ, RTC_CONTROL); 166 rtc_write(RTC_READ, RTC_CONTROL);
167 cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); 167 cmos_second = (u8)(rtc_read(RTC_SECONDS) & RTC_SECONDS_MASK);
168 CMOS_WRITE(RTC_WRITE, RTC_CONTROL); 168 rtc_write(RTC_WRITE, RTC_CONTROL);
169 CMOS_WRITE(cmos_second, RTC_SECONDS); /* clear msb */ 169 rtc_write(cmos_second, RTC_SECONDS); /* clear msb */
170 CMOS_WRITE(0, RTC_CONTROL); 170 rtc_write(0, RTC_CONTROL);
171} 171}
diff --git a/arch/mips/jmr3927/rbhma3100/Makefile b/arch/mips/jmr3927/rbhma3100/Makefile
index 75bf418b94c0..baf5077813c1 100644
--- a/arch/mips/jmr3927/rbhma3100/Makefile
+++ b/arch/mips/jmr3927/rbhma3100/Makefile
@@ -2,7 +2,7 @@
2# Makefile for TOSHIBA JMR-TX3927 board 2# Makefile for TOSHIBA JMR-TX3927 board
3# 3#
4 4
5obj-y += init.o int-handler.o irq.o setup.o 5obj-y += init.o irq.o setup.o
6obj-$(CONFIG_RUNTIME_DEBUG) += debug.o 6obj-$(CONFIG_RUNTIME_DEBUG) += debug.o
7obj-$(CONFIG_KGDB) += kgdb_io.o 7obj-$(CONFIG_KGDB) += kgdb_io.o
8 8
diff --git a/arch/mips/jmr3927/rbhma3100/int-handler.S b/arch/mips/jmr3927/rbhma3100/int-handler.S
deleted file mode 100644
index f85bbf407542..000000000000
--- a/arch/mips/jmr3927/rbhma3100/int-handler.S
+++ /dev/null
@@ -1,74 +0,0 @@
1/*
2 * Copyright 2001 MontaVista Software Inc.
3 * Author: MontaVista Software, Inc.
4 * ahennessy@mvista.com
5 *
6 * Based on arch/mips/tsdb/kernel/int-handler.S
7 *
8 * Copyright (C) 2000-2001 Toshiba Corporation
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
18 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
21 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
22 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 675 Mass Ave, Cambridge, MA 02139, USA.
29 */
30
31#include <asm/asm.h>
32#include <asm/mipsregs.h>
33#include <asm/regdef.h>
34#include <asm/stackframe.h>
35#include <asm/jmr3927/jmr3927.h>
36
37 /* A lot of complication here is taken away because:
38 *
39 * 1) We handle one interrupt and return, sitting in a loop
40 * and moving across all the pending IRQ bits in the cause
41 * register is _NOT_ the answer, the common case is one
42 * pending IRQ so optimize in that direction.
43 *
44 * 2) We need not check against bits in the status register
45 * IRQ mask, that would make this routine slow as hell.
46 *
47 * 3) Linux only thinks in terms of all IRQs on or all IRQs
48 * off, nothing in between like BSD spl() brain-damage.
49 *
50 */
51
52/* Flush write buffer (needed?)
53 * NOTE: TX39xx performs "non-blocking load", so explicitly use the target
54 * register of LBU to flush immediately.
55 */
56#define FLUSH_WB(tmp) \
57 la tmp, JMR3927_IOC_REV_ADDR; \
58 lbu tmp, (tmp); \
59 move tmp, zero;
60
61 .text
62 .set noreorder
63 .set noat
64 .align 5
65 NESTED(jmr3927_IRQ, PT_SIZE, sp)
66 SAVE_ALL
67 CLI
68 .set at
69 jal jmr3927_irc_irqdispatch
70 move a0, sp
71 FLUSH_WB(t0)
72 j ret_from_irq
73 nop
74 END(jmr3927_IRQ)
diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c
index 2810727f1d4e..11304d1354f4 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)
77} 77}
78#endif 78#endif
79 79
80extern asmlinkage void jmr3927_IRQ(void);
81
82#define irc_dlevel 0 80#define irc_dlevel 0
83#define irc_elevel 1 81#define irc_elevel 1
84 82
@@ -262,7 +260,7 @@ void jmr3927_spurious(struct pt_regs *regs)
262 regs->cp0_cause, regs->cp0_epc, regs->regs[31]); 260 regs->cp0_cause, regs->cp0_epc, regs->regs[31]);
263} 261}
264 262
265void jmr3927_irc_irqdispatch(struct pt_regs *regs) 263asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
266{ 264{
267 int irq; 265 int irq;
268 266
@@ -398,8 +396,6 @@ void __init arch_init_irq(void)
398 396
399 jmr3927_irq_init(NR_ISA_IRQS); 397 jmr3927_irq_init(NR_ISA_IRQS);
400 398
401 set_except_vector(0, jmr3927_IRQ);
402
403 /* setup irq space */ 399 /* setup irq space */
404 add_tb_irq_space(&jmr3927_isac_irqspace); 400 add_tb_irq_space(&jmr3927_isac_irqspace);
405 add_tb_irq_space(&jmr3927_ioc_irqspace); 401 add_tb_irq_space(&jmr3927_ioc_irqspace);
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 309d54cceda3..34e8a256765c 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
34 34
35obj-$(CONFIG_SMP) += smp.o 35obj-$(CONFIG_SMP) += smp.o
36 36
37obj-$(CONFIG_MIPS_MT_SMP) += smp_mt.o 37obj-$(CONFIG_MIPS_MT) += mips-mt.o
38obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
39obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
38 40
41obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o
39obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o 42obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o
40obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o 43obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o
41 44
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index ca6b03c773be..92b28b674d6f 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -69,6 +69,9 @@ void output_ptreg_defines(void)
69 offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr); 69 offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr);
70 offset("#define PT_STATUS ", struct pt_regs, cp0_status); 70 offset("#define PT_STATUS ", struct pt_regs, cp0_status);
71 offset("#define PT_CAUSE ", struct pt_regs, cp0_cause); 71 offset("#define PT_CAUSE ", struct pt_regs, cp0_cause);
72#ifdef CONFIG_MIPS_MT_SMTC
73 offset("#define PT_TCSTATUS ", struct pt_regs, cp0_tcstatus);
74#endif /* CONFIG_MIPS_MT_SMTC */
72 size("#define PT_SIZE ", struct pt_regs); 75 size("#define PT_SIZE ", struct pt_regs);
73 linefeed; 76 linefeed;
74} 77}
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 83c87fe4ee4f..d101d2fb24ca 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -17,6 +17,9 @@
17#include <asm/isadep.h> 17#include <asm/isadep.h>
18#include <asm/thread_info.h> 18#include <asm/thread_info.h>
19#include <asm/war.h> 19#include <asm/war.h>
20#ifdef CONFIG_MIPS_MT_SMTC
21#include <asm/mipsmtregs.h>
22#endif
20 23
21#ifdef CONFIG_PREEMPT 24#ifdef CONFIG_PREEMPT
22 .macro preempt_stop 25 .macro preempt_stop
@@ -75,6 +78,37 @@ FEXPORT(syscall_exit)
75 bnez t0, syscall_exit_work 78 bnez t0, syscall_exit_work
76 79
77FEXPORT(restore_all) # restore full frame 80FEXPORT(restore_all) # restore full frame
81#ifdef CONFIG_MIPS_MT_SMTC
82/* Detect and execute deferred IPI "interrupts" */
83 move a0,sp
84 jal deferred_smtc_ipi
85/* Re-arm any temporarily masked interrupts not explicitly "acked" */
86 mfc0 v0, CP0_TCSTATUS
87 ori v1, v0, TCSTATUS_IXMT
88 mtc0 v1, CP0_TCSTATUS
89 andi v0, TCSTATUS_IXMT
90 ehb
91 mfc0 t0, CP0_TCCONTEXT
92 DMT 9 # dmt t1
93 jal mips_ihb
94 mfc0 t2, CP0_STATUS
95 andi t3, t0, 0xff00
96 or t2, t2, t3
97 mtc0 t2, CP0_STATUS
98 ehb
99 andi t1, t1, VPECONTROL_TE
100 beqz t1, 1f
101 EMT
1021:
103 mfc0 v1, CP0_TCSTATUS
104 /* We set IXMT above, XOR should cler it here */
105 xori v1, v1, TCSTATUS_IXMT
106 or v1, v0, v1
107 mtc0 v1, CP0_TCSTATUS
108 ehb
109 xor t0, t0, t3
110 mtc0 t0, CP0_TCCONTEXT
111#endif /* CONFIG_MIPS_MT_SMTC */
78 .set noat 112 .set noat
79 RESTORE_TEMP 113 RESTORE_TEMP
80 RESTORE_AT 114 RESTORE_AT
@@ -120,28 +154,17 @@ syscall_exit_work:
120 jal do_syscall_trace 154 jal do_syscall_trace
121 b resume_userspace 155 b resume_userspace
122 156
157#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT)
158
123/* 159/*
124 * Common spurious interrupt handler. 160 * MIPS32R2 Instruction Hazard Barrier - must be called
161 *
162 * For C code use the inline version named instruction_hazard().
125 */ 163 */
126LEAF(spurious_interrupt) 164LEAF(mips_ihb)
127 /* 165 .set mips32r2
128 * Someone tried to fool us by sending an interrupt but we 166 jr.hb ra
129 * couldn't find a cause for it. 167 nop
130 */ 168 END(mips_ihb)
131 PTR_LA t1, irq_err_count 169
132#ifdef CONFIG_SMP 170#endif /* CONFIG_CPU_MIPSR2 or CONFIG_MIPS_MT */
1331: ll t0, (t1)
134 addiu t0, 1
135 sc t0, (t1)
136#if R10000_LLSC_WAR
137 beqzl t0, 1b
138#else
139 beqz t0, 1b
140#endif
141#else
142 lw t0, (t1)
143 addiu t0, 1
144 sw t0, (t1)
145#endif
146 j ret_from_irq
147 END(spurious_interrupt)
diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S
index 235ad9f6bd35..10f28fb9f008 100644
--- a/arch/mips/kernel/gdb-low.S
+++ b/arch/mips/kernel/gdb-low.S
@@ -283,11 +283,33 @@
283 */ 283 */
284 284
2853: 2853:
286#ifdef CONFIG_MIPS_MT_SMTC
287 /* Read-modify write of Status must be atomic */
288 mfc0 t2, CP0_TCSTATUS
289 ori t1, t2, TCSTATUS_IXMT
290 mtc0 t1, CP0_TCSTATUS
291 andi t2, t2, TCSTATUS_IXMT
292 ehb
293 DMT 9 # dmt t1
294 jal mips_ihb
295 nop
296#endif /* CONFIG_MIPS_MT_SMTC */
286 mfc0 t0, CP0_STATUS 297 mfc0 t0, CP0_STATUS
287 ori t0, 0x1f 298 ori t0, 0x1f
288 xori t0, 0x1f 299 xori t0, 0x1f
289 mtc0 t0, CP0_STATUS 300 mtc0 t0, CP0_STATUS
290 301#ifdef CONFIG_MIPS_MT_SMTC
302 andi t1, t1, VPECONTROL_TE
303 beqz t1, 9f
304 nop
305 EMT # emt
3069:
307 mfc0 t1, CP0_TCSTATUS
308 xori t1, t1, TCSTATUS_IXMT
309 or t1, t1, t2
310 mtc0 t1, CP0_TCSTATUS
311 ehb
312#endif /* CONFIG_MIPS_MT_SMTC */
291 LONG_L v0, GDB_FR_STATUS(sp) 313 LONG_L v0, GDB_FR_STATUS(sp)
292 LONG_L v1, GDB_FR_EPC(sp) 314 LONG_L v1, GDB_FR_EPC(sp)
293 mtc0 v0, CP0_STATUS 315 mtc0 v0, CP0_STATUS
diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c
index d4f88e0af24c..6ecbdc1fefd1 100644
--- a/arch/mips/kernel/gdb-stub.c
+++ b/arch/mips/kernel/gdb-stub.c
@@ -140,6 +140,7 @@
140#include <asm/system.h> 140#include <asm/system.h>
141#include <asm/gdb-stub.h> 141#include <asm/gdb-stub.h>
142#include <asm/inst.h> 142#include <asm/inst.h>
143#include <asm/smp.h>
143 144
144/* 145/*
145 * external low-level support routines 146 * external low-level support routines
@@ -669,6 +670,64 @@ static void kgdb_wait(void *arg)
669 local_irq_restore(flags); 670 local_irq_restore(flags);
670} 671}
671 672
673/*
674 * GDB stub needs to call kgdb_wait on all processor with interrupts
675 * disabled, so it uses it's own special variant.
676 */
677static int kgdb_smp_call_kgdb_wait(void)
678{
679#ifdef CONFIG_SMP
680 struct call_data_struct data;
681 int i, cpus = num_online_cpus() - 1;
682 int cpu = smp_processor_id();
683
684 /*
685 * Can die spectacularly if this CPU isn't yet marked online
686 */
687 BUG_ON(!cpu_online(cpu));
688
689 if (!cpus)
690 return 0;
691
692 if (spin_is_locked(&smp_call_lock)) {
693 /*
694 * Some other processor is trying to make us do something
695 * but we're not going to respond... give up
696 */
697 return -1;
698 }
699
700 /*
701 * We will continue here, accepting the fact that
702 * the kernel may deadlock if another CPU attempts
703 * to call smp_call_function now...
704 */
705
706 data.func = kgdb_wait;
707 data.info = NULL;
708 atomic_set(&data.started, 0);
709 data.wait = 0;
710
711 spin_lock(&smp_call_lock);
712 call_data = &data;
713 mb();
714
715 /* Send a message to all other CPUs and wait for them to respond */
716 for (i = 0; i < NR_CPUS; i++)
717 if (cpu_online(i) && i != cpu)
718 core_send_ipi(i, SMP_CALL_FUNCTION);
719
720 /* Wait for response */
721 /* FIXME: lock-up detection, backtrace on lock-up */
722 while (atomic_read(&data.started) != cpus)
723 barrier();
724
725 call_data = NULL;
726 spin_unlock(&smp_call_lock);
727#endif
728
729 return 0;
730}
672 731
673/* 732/*
674 * This function does all command processing for interfacing to gdb. It 733 * This function does all command processing for interfacing to gdb. It
@@ -718,7 +777,7 @@ void handle_exception (struct gdb_regs *regs)
718 /* 777 /*
719 * force other cpus to enter kgdb 778 * force other cpus to enter kgdb
720 */ 779 */
721 smp_call_function(kgdb_wait, NULL, 0, 0); 780 kgdb_smp_call_kgdb_wait();
722 781
723 /* 782 /*
724 * If we're in breakpoint() increment the PC 783 * If we're in breakpoint() increment the PC
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index 13f22d1d0e8b..ff7af369f286 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -12,6 +12,7 @@
12#include <linux/init.h> 12#include <linux/init.h>
13 13
14#include <asm/asm.h> 14#include <asm/asm.h>
15#include <asm/asmmacro.h>
15#include <asm/cacheops.h> 16#include <asm/cacheops.h>
16#include <asm/regdef.h> 17#include <asm/regdef.h>
17#include <asm/fpregdef.h> 18#include <asm/fpregdef.h>
@@ -122,6 +123,20 @@ handle_vcei:
122 .set pop 123 .set pop
123 END(except_vec3_r4000) 124 END(except_vec3_r4000)
124 125
126 __FINIT
127
128 .align 5
129NESTED(handle_int, PT_SIZE, sp)
130 SAVE_ALL
131 CLI
132
133 PTR_LA ra, ret_from_irq
134 move a0, sp
135 j plat_irq_dispatch
136 END(handle_int)
137
138 __INIT
139
125/* 140/*
126 * Special interrupt vector for MIPS64 ISA & embedded MIPS processors. 141 * Special interrupt vector for MIPS64 ISA & embedded MIPS processors.
127 * This is a dedicated interrupt exception vector which reduces the 142 * This is a dedicated interrupt exception vector which reduces the
@@ -157,6 +172,15 @@ NESTED(except_vec_vi, 0, sp)
157 SAVE_AT 172 SAVE_AT
158 .set push 173 .set push
159 .set noreorder 174 .set noreorder
175#ifdef CONFIG_MIPS_MT_SMTC
176 /*
177 * To keep from blindly blocking *all* interrupts
178 * during service by SMTC kernel, we also want to
179 * pass the IM value to be cleared.
180 */
181EXPORT(except_vec_vi_mori)
182 ori a0, $0, 0
183#endif /* CONFIG_MIPS_MT_SMTC */
160EXPORT(except_vec_vi_lui) 184EXPORT(except_vec_vi_lui)
161 lui v0, 0 /* Patched */ 185 lui v0, 0 /* Patched */
162 j except_vec_vi_handler 186 j except_vec_vi_handler
@@ -173,6 +197,25 @@ EXPORT(except_vec_vi_end)
173NESTED(except_vec_vi_handler, 0, sp) 197NESTED(except_vec_vi_handler, 0, sp)
174 SAVE_TEMP 198 SAVE_TEMP
175 SAVE_STATIC 199 SAVE_STATIC
200#ifdef CONFIG_MIPS_MT_SMTC
201 /*
202 * SMTC has an interesting problem that interrupts are level-triggered,
203 * and the CLI macro will clear EXL, potentially causing a duplicate
204 * interrupt service invocation. So we need to clear the associated
205 * IM bit of Status prior to doing CLI, and restore it after the
206 * service routine has been invoked - we must assume that the
207 * service routine will have cleared the state, and any active
208 * level represents a new or otherwised unserviced event...
209 */
210 mfc0 t1, CP0_STATUS
211 and t0, a0, t1
212 mfc0 t2, CP0_TCCONTEXT
213 or t0, t0, t2
214 mtc0 t0, CP0_TCCONTEXT
215 xor t1, t1, t0
216 mtc0 t1, CP0_STATUS
217 ehb
218#endif /* CONFIG_MIPS_MT_SMTC */
176 CLI 219 CLI
177 move a0, sp 220 move a0, sp
178 jalr v0 221 jalr v0
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 2e9122a4213a..bdf6f6eff721 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -18,6 +18,7 @@
18#include <linux/threads.h> 18#include <linux/threads.h>
19 19
20#include <asm/asm.h> 20#include <asm/asm.h>
21#include <asm/asmmacro.h>
21#include <asm/regdef.h> 22#include <asm/regdef.h>
22#include <asm/page.h> 23#include <asm/page.h>
23#include <asm/mipsregs.h> 24#include <asm/mipsregs.h>
@@ -82,12 +83,33 @@
82 */ 83 */
83 .macro setup_c0_status set clr 84 .macro setup_c0_status set clr
84 .set push 85 .set push
86#ifdef CONFIG_MIPS_MT_SMTC
87 /*
88 * For SMTC, we need to set privilege and disable interrupts only for
89 * the current TC, using the TCStatus register.
90 */
91 mfc0 t0, CP0_TCSTATUS
92 /* Fortunately CU 0 is in the same place in both registers */
93 /* Set TCU0, TMX, TKSU (for later inversion) and IXMT */
94 li t1, ST0_CU0 | 0x08001c00
95 or t0, t1
96 /* Clear TKSU, leave IXMT */
97 xori t0, 0x00001800
98 mtc0 t0, CP0_TCSTATUS
99 ehb
100 /* We need to leave the global IE bit set, but clear EXL...*/
101 mfc0 t0, CP0_STATUS
102 or t0, ST0_CU0 | ST0_EXL | ST0_ERL | \set | \clr
103 xor t0, ST0_EXL | ST0_ERL | \clr
104 mtc0 t0, CP0_STATUS
105#else
85 mfc0 t0, CP0_STATUS 106 mfc0 t0, CP0_STATUS
86 or t0, ST0_CU0|\set|0x1f|\clr 107 or t0, ST0_CU0|\set|0x1f|\clr
87 xor t0, 0x1f|\clr 108 xor t0, 0x1f|\clr
88 mtc0 t0, CP0_STATUS 109 mtc0 t0, CP0_STATUS
89 .set noreorder 110 .set noreorder
90 sll zero,3 # ehb 111 sll zero,3 # ehb
112#endif
91 .set pop 113 .set pop
92 .endm 114 .endm
93 115
@@ -134,6 +156,24 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
134 156
135 ARC64_TWIDDLE_PC 157 ARC64_TWIDDLE_PC
136 158
159#ifdef CONFIG_MIPS_MT_SMTC
160 /*
161 * In SMTC kernel, "CLI" is thread-specific, in TCStatus.
162 * We still need to enable interrupts globally in Status,
163 * and clear EXL/ERL.
164 *
165 * TCContext is used to track interrupt levels under
166 * service in SMTC kernel. Clear for boot TC before
167 * allowing any interrupts.
168 */
169 mtc0 zero, CP0_TCCONTEXT
170
171 mfc0 t0, CP0_STATUS
172 ori t0, t0, 0xff1f
173 xori t0, t0, 0x001e
174 mtc0 t0, CP0_STATUS
175#endif /* CONFIG_MIPS_MT_SMTC */
176
137 PTR_LA t0, __bss_start # clear .bss 177 PTR_LA t0, __bss_start # clear .bss
138 LONG_S zero, (t0) 178 LONG_S zero, (t0)
139 PTR_LA t1, __bss_stop - LONGSIZE 179 PTR_LA t1, __bss_stop - LONGSIZE
@@ -166,8 +206,25 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
166 * function after setting up the stack and gp registers. 206 * function after setting up the stack and gp registers.
167 */ 207 */
168NESTED(smp_bootstrap, 16, sp) 208NESTED(smp_bootstrap, 16, sp)
209#ifdef CONFIG_MIPS_MT_SMTC
210 /*
211 * Read-modify-writes of Status must be atomic, and this
212 * is one case where CLI is invoked without EXL being
213 * necessarily set. The CLI and setup_c0_status will
214 * in fact be redundant for all but the first TC of
215 * each VPE being booted.
216 */
217 DMT 10 # dmt t2 /* t0, t1 are used by CLI and setup_c0_status() */
218 jal mips_ihb
219#endif /* CONFIG_MIPS_MT_SMTC */
169 setup_c0_status_sec 220 setup_c0_status_sec
170 smp_slave_setup 221 smp_slave_setup
222#ifdef CONFIG_MIPS_MT_SMTC
223 andi t2, t2, VPECONTROL_TE
224 beqz t2, 2f
225 EMT # emt
2262:
227#endif /* CONFIG_MIPS_MT_SMTC */
171 j start_secondary 228 j start_secondary
172 END(smp_bootstrap) 229 END(smp_bootstrap)
173#endif /* CONFIG_SMP */ 230#endif /* CONFIG_SMP */
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index b974ac9057f6..2125ba5f1d9b 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -187,6 +187,10 @@ handle_real_irq:
187 outb(cached_21,0x21); 187 outb(cached_21,0x21);
188 outb(0x60+irq,0x20); /* 'Specific EOI' to master */ 188 outb(0x60+irq,0x20); /* 'Specific EOI' to master */
189 } 189 }
190#ifdef CONFIG_MIPS_MT_SMTC
191 if (irq_hwmask[irq] & ST0_IM)
192 set_c0_status(irq_hwmask[irq] & ST0_IM);
193#endif /* CONFIG_MIPS_MT_SMTC */
190 spin_unlock_irqrestore(&i8259A_lock, flags); 194 spin_unlock_irqrestore(&i8259A_lock, flags);
191 return; 195 return;
192 196
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
index 3f653c7cfbf3..97ebdc754b9e 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)
76 mask_msc_irq(irq); 76 mask_msc_irq(irq);
77 if (!cpu_has_veic) 77 if (!cpu_has_veic)
78 MSCIC_WRITE(MSC01_IC_EOI, 0); 78 MSCIC_WRITE(MSC01_IC_EOI, 0);
79#ifdef CONFIG_MIPS_MT_SMTC
80 /* This actually needs to be a call into platform code */
81 if (irq_hwmask[irq] & ST0_IM)
82 set_c0_status(irq_hwmask[irq] & ST0_IM);
83#endif /* CONFIG_MIPS_MT_SMTC */
79} 84}
80 85
81/* 86/*
@@ -92,6 +97,10 @@ static void edge_mask_and_ack_msc_irq(unsigned int irq)
92 MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); 97 MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT);
93 MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); 98 MSCIC_WRITE(MSC01_IC_SUP+irq*8, r);
94 } 99 }
100#ifdef CONFIG_MIPS_MT_SMTC
101 if (irq_hwmask[irq] & ST0_IM)
102 set_c0_status(irq_hwmask[irq] & ST0_IM);
103#endif /* CONFIG_MIPS_MT_SMTC */
95} 104}
96 105
97/* 106/*
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index 3dd76b3d2967..3dce742e716f 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -38,6 +38,15 @@ void ack_bad_irq(unsigned int irq)
38 38
39atomic_t irq_err_count; 39atomic_t irq_err_count;
40 40
41#ifdef CONFIG_MIPS_MT_SMTC
42/*
43 * SMTC Kernel needs to manipulate low-level CPU interrupt mask
44 * in do_IRQ. These are passed in setup_irq_smtc() and stored
45 * in this table.
46 */
47unsigned long irq_hwmask[NR_IRQS];
48#endif /* CONFIG_MIPS_MT_SMTC */
49
41#undef do_IRQ 50#undef do_IRQ
42 51
43/* 52/*
@@ -49,6 +58,7 @@ asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs)
49{ 58{
50 irq_enter(); 59 irq_enter();
51 60
61 __DO_IRQ_SMTC_HOOK();
52 __do_IRQ(irq, regs); 62 __do_IRQ(irq, regs);
53 63
54 irq_exit(); 64 irq_exit();
@@ -101,6 +111,11 @@ skip:
101 return 0; 111 return 0;
102} 112}
103 113
114asmlinkage void spurious_interrupt(struct pt_regs *regs)
115{
116 atomic_inc(&irq_err_count);
117}
118
104#ifdef CONFIG_KGDB 119#ifdef CONFIG_KGDB
105extern void breakpoint(void); 120extern void breakpoint(void);
106extern void set_debug_traps(void); 121extern void set_debug_traps(void);
@@ -124,6 +139,9 @@ void __init init_IRQ(void)
124 irq_desc[i].depth = 1; 139 irq_desc[i].depth = 1;
125 irq_desc[i].handler = &no_irq_type; 140 irq_desc[i].handler = &no_irq_type;
126 spin_lock_init(&irq_desc[i].lock); 141 spin_lock_init(&irq_desc[i].lock);
142#ifdef CONFIG_MIPS_MT_SMTC
143 irq_hwmask[i] = 0;
144#endif /* CONFIG_MIPS_MT_SMTC */
127 } 145 }
128 146
129 arch_init_irq(); 147 arch_init_irq();
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
new file mode 100644
index 000000000000..f06a144c7881
--- /dev/null
+++ b/arch/mips/kernel/kspd.c
@@ -0,0 +1,398 @@
1/*
2 * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
3 *
4 * This program is free software; you can distribute it and/or modify it
5 * under the terms of the GNU General Public License (Version 2) as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
16 *
17 */
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/unistd.h>
21#include <linux/file.h>
22#include <linux/fs.h>
23#include <linux/syscalls.h>
24#include <linux/workqueue.h>
25#include <linux/errno.h>
26#include <linux/list.h>
27
28#include <asm/vpe.h>
29#include <asm/rtlx.h>
30#include <asm/kspd.h>
31
32static struct workqueue_struct *workqueue = NULL;
33static struct work_struct work;
34
35extern unsigned long cpu_khz;
36
37struct mtsp_syscall {
38 int cmd;
39 unsigned char abi;
40 unsigned char size;
41};
42
43struct mtsp_syscall_ret {
44 int retval;
45 int errno;
46};
47
48struct mtsp_syscall_generic {
49 int arg0;
50 int arg1;
51 int arg2;
52 int arg3;
53 int arg4;
54 int arg5;
55 int arg6;
56};
57
58static struct list_head kspd_notifylist;
59static int sp_stopping = 0;
60
61/* these should match with those in the SDE kit */
62#define MTSP_SYSCALL_BASE 0
63#define MTSP_SYSCALL_EXIT (MTSP_SYSCALL_BASE + 0)
64#define MTSP_SYSCALL_OPEN (MTSP_SYSCALL_BASE + 1)
65#define MTSP_SYSCALL_READ (MTSP_SYSCALL_BASE + 2)
66#define MTSP_SYSCALL_WRITE (MTSP_SYSCALL_BASE + 3)
67#define MTSP_SYSCALL_CLOSE (MTSP_SYSCALL_BASE + 4)
68#define MTSP_SYSCALL_LSEEK32 (MTSP_SYSCALL_BASE + 5)
69#define MTSP_SYSCALL_ISATTY (MTSP_SYSCALL_BASE + 6)
70#define MTSP_SYSCALL_GETTIME (MTSP_SYSCALL_BASE + 7)
71#define MTSP_SYSCALL_PIPEFREQ (MTSP_SYSCALL_BASE + 8)
72#define MTSP_SYSCALL_GETTOD (MTSP_SYSCALL_BASE + 9)
73
74#define MTSP_O_RDONLY 0x0000
75#define MTSP_O_WRONLY 0x0001
76#define MTSP_O_RDWR 0x0002
77#define MTSP_O_NONBLOCK 0x0004
78#define MTSP_O_APPEND 0x0008
79#define MTSP_O_SHLOCK 0x0010
80#define MTSP_O_EXLOCK 0x0020
81#define MTSP_O_ASYNC 0x0040
82#define MTSP_O_FSYNC O_SYNC
83#define MTSP_O_NOFOLLOW 0x0100
84#define MTSP_O_SYNC 0x0080
85#define MTSP_O_CREAT 0x0200
86#define MTSP_O_TRUNC 0x0400
87#define MTSP_O_EXCL 0x0800
88#define MTSP_O_BINARY 0x8000
89
90#define SP_VPE 1
91
92struct apsp_table {
93 int sp;
94 int ap;
95};
96
97/* we might want to do the mode flags too */
98struct apsp_table open_flags_table[] = {
99 { MTSP_O_RDWR, O_RDWR },
100 { MTSP_O_WRONLY, O_WRONLY },
101 { MTSP_O_CREAT, O_CREAT },
102 { MTSP_O_TRUNC, O_TRUNC },
103 { MTSP_O_NONBLOCK, O_NONBLOCK },
104 { MTSP_O_APPEND, O_APPEND },
105 { MTSP_O_NOFOLLOW, O_NOFOLLOW }
106};
107
108struct apsp_table syscall_command_table[] = {
109 { MTSP_SYSCALL_OPEN, __NR_open },
110 { MTSP_SYSCALL_CLOSE, __NR_close },
111 { MTSP_SYSCALL_READ, __NR_read },
112 { MTSP_SYSCALL_WRITE, __NR_write },
113 { MTSP_SYSCALL_LSEEK32, __NR_lseek }
114};
115
116static int sp_syscall(int num, int arg0, int arg1, int arg2, int arg3)
117{
118 register long int _num __asm__ ("$2") = num;
119 register long int _arg0 __asm__ ("$4") = arg0;
120 register long int _arg1 __asm__ ("$5") = arg1;
121 register long int _arg2 __asm__ ("$6") = arg2;
122 register long int _arg3 __asm__ ("$7") = arg3;
123
124 mm_segment_t old_fs;
125
126 old_fs = get_fs();
127 set_fs(KERNEL_DS);
128
129 __asm__ __volatile__ (
130 " syscall \n"
131 : "=r" (_num), "=r" (_arg3)
132 : "r" (_num), "r" (_arg0), "r" (_arg1), "r" (_arg2), "r" (_arg3));
133
134 set_fs(old_fs);
135
136 /* $a3 is error flag */
137 if (_arg3)
138 return -_num;
139
140 return _num;
141}
142
143static int translate_syscall_command(int cmd)
144{
145 int i;
146 int ret = -1;
147
148 for (i = 0; i < ARRAY_SIZE(syscall_command_table); i++) {
149 if ((cmd == syscall_command_table[i].sp))
150 return syscall_command_table[i].ap;
151 }
152
153 return ret;
154}
155
156static unsigned int translate_open_flags(int flags)
157{
158 int i;
159 unsigned int ret = 0;
160
161 for (i = 0; i < (sizeof(open_flags_table) / sizeof(struct apsp_table));
162 i++) {
163 if( (flags & open_flags_table[i].sp) ) {
164 ret |= open_flags_table[i].ap;
165 }
166 }
167
168 return ret;
169}
170
171
172static void sp_setfsuidgid( uid_t uid, gid_t gid)
173{
174 current->fsuid = uid;
175 current->fsgid = gid;
176
177 key_fsuid_changed(current);
178 key_fsgid_changed(current);
179}
180
181/*
182 * Expects a request to be on the sysio channel. Reads it. Decides whether
183 * its a linux syscall and runs it, or whatever. Puts the return code back
184 * into the request and sends the whole thing back.
185 */
186void sp_work_handle_request(void)
187{
188 struct mtsp_syscall sc;
189 struct mtsp_syscall_generic generic;
190 struct mtsp_syscall_ret ret;
191 struct kspd_notifications *n;
192 struct timeval tv;
193 struct timezone tz;
194 int cmd;
195
196 char *vcwd;
197 mm_segment_t old_fs;
198 int size;
199
200 ret.retval = -1;
201
202 if (!rtlx_read(RTLX_CHANNEL_SYSIO, &sc, sizeof(struct mtsp_syscall), 0)) {
203 printk(KERN_ERR "Expected request but nothing to read\n");
204 return;
205 }
206
207 size = sc.size;
208
209 if (size) {
210 if (!rtlx_read(RTLX_CHANNEL_SYSIO, &generic, size, 0)) {
211 printk(KERN_ERR "Expected request but nothing to read\n");
212 return;
213 }
214 }
215
216 /* Run the syscall at the priviledge of the user who loaded the
217 SP program */
218
219 if (vpe_getuid(SP_VPE))
220 sp_setfsuidgid( vpe_getuid(SP_VPE), vpe_getgid(SP_VPE));
221
222 switch (sc.cmd) {
223 /* needs the flags argument translating from SDE kit to
224 linux */
225 case MTSP_SYSCALL_PIPEFREQ:
226 ret.retval = cpu_khz * 1000;
227 ret.errno = 0;
228 break;
229
230 case MTSP_SYSCALL_GETTOD:
231 memset(&tz, 0, sizeof(tz));
232 if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv,
233 (int)&tz, 0,0)) == 0)
234 ret.retval = tv.tv_sec;
235
236 ret.errno = errno;
237 break;
238
239 case MTSP_SYSCALL_EXIT:
240 list_for_each_entry(n, &kspd_notifylist, list)
241 n->kspd_sp_exit(SP_VPE);
242 sp_stopping = 1;
243
244 printk(KERN_DEBUG "KSPD got exit syscall from SP exitcode %d\n",
245 generic.arg0);
246 break;
247
248 case MTSP_SYSCALL_OPEN:
249 generic.arg1 = translate_open_flags(generic.arg1);
250
251 vcwd = vpe_getcwd(SP_VPE);
252
253 /* change to the cwd of the process that loaded the SP program */
254 old_fs = get_fs();
255 set_fs(KERNEL_DS);
256 sys_chdir(vcwd);
257 set_fs(old_fs);
258
259 sc.cmd = __NR_open;
260
261 /* fall through */
262
263 default:
264 if ((sc.cmd >= __NR_Linux) &&
265 (sc.cmd <= (__NR_Linux + __NR_Linux_syscalls)) )
266 cmd = sc.cmd;
267 else
268 cmd = translate_syscall_command(sc.cmd);
269
270 if (cmd >= 0) {
271 ret.retval = sp_syscall(cmd, generic.arg0, generic.arg1,
272 generic.arg2, generic.arg3);
273 ret.errno = errno;
274 } else
275 printk(KERN_WARNING
276 "KSPD: Unknown SP syscall number %d\n", sc.cmd);
277 break;
278 } /* switch */
279
280 if (vpe_getuid(SP_VPE))
281 sp_setfsuidgid( 0, 0);
282
283 if ((rtlx_write(RTLX_CHANNEL_SYSIO, &ret, sizeof(struct mtsp_syscall_ret), 0))
284 < sizeof(struct mtsp_syscall_ret))
285 printk("KSPD: sp_work_handle_request failed to send to SP\n");
286}
287
288static void sp_cleanup(void)
289{
290 struct files_struct *files = current->files;
291 int i, j;
292 struct fdtable *fdt;
293
294 j = 0;
295
296 /*
297 * It is safe to dereference the fd table without RCU or
298 * ->file_lock
299 */
300 fdt = files_fdtable(files);
301 for (;;) {
302 unsigned long set;
303 i = j * __NFDBITS;
304 if (i >= fdt->max_fdset || i >= fdt->max_fds)
305 break;
306 set = fdt->open_fds->fds_bits[j++];
307 while (set) {
308 if (set & 1) {
309 struct file * file = xchg(&fdt->fd[i], NULL);
310 if (file)
311 filp_close(file, files);
312 }
313 i++;
314 set >>= 1;
315 }
316 }
317}
318
319static int channel_open = 0;
320
321/* the work handler */
322static void sp_work(void *data)
323{
324 if (!channel_open) {
325 if( rtlx_open(RTLX_CHANNEL_SYSIO, 1) != 0) {
326 printk("KSPD: unable to open sp channel\n");
327 sp_stopping = 1;
328 } else {
329 channel_open++;
330 printk(KERN_DEBUG "KSPD: SP channel opened\n");
331 }
332 } else {
333 /* wait for some data, allow it to sleep */
334 rtlx_read_poll(RTLX_CHANNEL_SYSIO, 1);
335
336 /* Check we haven't been woken because we are stopping */
337 if (!sp_stopping)
338 sp_work_handle_request();
339 }
340
341 if (!sp_stopping)
342 queue_work(workqueue, &work);
343 else
344 sp_cleanup();
345}
346
347static void startwork(int vpe)
348{
349 sp_stopping = channel_open = 0;
350
351 if (workqueue == NULL) {
352 if ((workqueue = create_singlethread_workqueue("kspd")) == NULL) {
353 printk(KERN_ERR "unable to start kspd\n");
354 return;
355 }
356
357 INIT_WORK(&work, sp_work, NULL);
358 queue_work(workqueue, &work);
359 } else
360 queue_work(workqueue, &work);
361
362}
363
364static void stopwork(int vpe)
365{
366 sp_stopping = 1;
367
368 printk(KERN_DEBUG "KSPD: SP stopping\n");
369}
370
371void kspd_notify(struct kspd_notifications *notify)
372{
373 list_add(&notify->list, &kspd_notifylist);
374}
375
376static struct vpe_notifications notify;
377static int kspd_module_init(void)
378{
379 INIT_LIST_HEAD(&kspd_notifylist);
380
381 notify.start = startwork;
382 notify.stop = stopwork;
383 vpe_notify(SP_VPE, &notify);
384
385 return 0;
386}
387
388static void kspd_module_exit(void)
389{
390
391}
392
393module_init(kspd_module_init);
394module_exit(kspd_module_exit);
395
396MODULE_DESCRIPTION("MIPS KSPD");
397MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
398MODULE_LICENSE("GPL");
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 3f40c37a9ee6..7c953bcc5f6a 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,
1182 return sys_readahead(fd, merge_64(a2, a3), count); 1182 return sys_readahead(fd, merge_64(a2, a3), count);
1183} 1183}
1184 1184
1185asmlinkage long sys32_sync_file_range(int fd, int __pad,
1186 unsigned long a2, unsigned long a3,
1187 unsigned long a4, unsigned long a5,
1188 int flags)
1189{
1190 return sys_sync_file_range(fd,
1191 merge_64(a2, a3), merge_64(a4, a5),
1192 flags);
1193}
1194
1185/* Argument list sizes for sys_socketcall */ 1195/* Argument list sizes for sys_socketcall */
1186#define AL(x) ((x) * sizeof(unsigned int)) 1196#define AL(x) ((x) * sizeof(unsigned int))
1187static unsigned char socketcall_nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), 1197static 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 000000000000..02237a685ec7
--- /dev/null
+++ b/arch/mips/kernel/mips-mt.c
@@ -0,0 +1,449 @@
1/*
2 * General MIPS MT support routines, usable in AP/SP, SMVP, or SMTC kernels
3 * Copyright (C) 2005 Mips Technologies, Inc
4 */
5
6#include <linux/kernel.h>
7#include <linux/sched.h>
8#include <linux/cpumask.h>
9#include <linux/interrupt.h>
10
11#include <asm/cpu.h>
12#include <asm/processor.h>
13#include <asm/atomic.h>
14#include <asm/system.h>
15#include <asm/hardirq.h>
16#include <asm/mmu_context.h>
17#include <asm/smp.h>
18#include <asm/mipsmtregs.h>
19#include <asm/r4kcache.h>
20#include <asm/cacheflush.h>
21
22/*
23 * CPU mask used to set process affinity for MT VPEs/TCs with FPUs
24 */
25
26cpumask_t mt_fpu_cpumask;
27
28#ifdef CONFIG_MIPS_MT_FPAFF
29
30#include <linux/cpu.h>
31#include <linux/delay.h>
32#include <asm/uaccess.h>
33
34unsigned long mt_fpemul_threshold = 0;
35
36/*
37 * Replacement functions for the sys_sched_setaffinity() and
38 * sys_sched_getaffinity() system calls, so that we can integrate
39 * FPU affinity with the user's requested processor affinity.
40 * This code is 98% identical with the sys_sched_setaffinity()
41 * and sys_sched_getaffinity() system calls, and should be
42 * updated when kernel/sched.c changes.
43 */
44
45/*
46 * find_process_by_pid - find a process with a matching PID value.
47 * used in sys_sched_set/getaffinity() in kernel/sched.c, so
48 * cloned here.
49 */
50static inline task_t *find_process_by_pid(pid_t pid)
51{
52 return pid ? find_task_by_pid(pid) : current;
53}
54
55
56/*
57 * mipsmt_sys_sched_setaffinity - set the cpu affinity of a process
58 */
59asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
60 unsigned long __user *user_mask_ptr)
61{
62 cpumask_t new_mask;
63 cpumask_t effective_mask;
64 int retval;
65 task_t *p;
66
67 if (len < sizeof(new_mask))
68 return -EINVAL;
69
70 if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
71 return -EFAULT;
72
73 lock_cpu_hotplug();
74 read_lock(&tasklist_lock);
75
76 p = find_process_by_pid(pid);
77 if (!p) {
78 read_unlock(&tasklist_lock);
79 unlock_cpu_hotplug();
80 return -ESRCH;
81 }
82
83 /*
84 * It is not safe to call set_cpus_allowed with the
85 * tasklist_lock held. We will bump the task_struct's
86 * usage count and drop tasklist_lock before invoking
87 * set_cpus_allowed.
88 */
89 get_task_struct(p);
90
91 retval = -EPERM;
92 if ((current->euid != p->euid) && (current->euid != p->uid) &&
93 !capable(CAP_SYS_NICE)) {
94 read_unlock(&tasklist_lock);
95 goto out_unlock;
96 }
97
98 /* Record new user-specified CPU set for future reference */
99 p->thread.user_cpus_allowed = new_mask;
100
101 /* Unlock the task list */
102 read_unlock(&tasklist_lock);
103
104 /* Compute new global allowed CPU set if necessary */
105 if( (p->thread.mflags & MF_FPUBOUND)
106 && cpus_intersects(new_mask, mt_fpu_cpumask)) {
107 cpus_and(effective_mask, new_mask, mt_fpu_cpumask);
108 retval = set_cpus_allowed(p, effective_mask);
109 } else {
110 p->thread.mflags &= ~MF_FPUBOUND;
111 retval = set_cpus_allowed(p, new_mask);
112 }
113
114
115out_unlock:
116 put_task_struct(p);
117 unlock_cpu_hotplug();
118 return retval;
119}
120
121/*
122 * mipsmt_sys_sched_getaffinity - get the cpu affinity of a process
123 */
124asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
125 unsigned long __user *user_mask_ptr)
126{
127 unsigned int real_len;
128 cpumask_t mask;
129 int retval;
130 task_t *p;
131
132 real_len = sizeof(mask);
133 if (len < real_len)
134 return -EINVAL;
135
136 lock_cpu_hotplug();
137 read_lock(&tasklist_lock);
138
139 retval = -ESRCH;
140 p = find_process_by_pid(pid);
141 if (!p)
142 goto out_unlock;
143
144 retval = 0;
145
146 cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map);
147
148out_unlock:
149 read_unlock(&tasklist_lock);
150 unlock_cpu_hotplug();
151 if (retval)
152 return retval;
153 if (copy_to_user(user_mask_ptr, &mask, real_len))
154 return -EFAULT;
155 return real_len;
156}
157
158#endif /* CONFIG_MIPS_MT_FPAFF */
159
160/*
161 * Dump new MIPS MT state for the core. Does not leave TCs halted.
162 * Takes an argument which taken to be a pre-call MVPControl value.
163 */
164
165void mips_mt_regdump(unsigned long mvpctl)
166{
167 unsigned long flags;
168 unsigned long vpflags;
169 unsigned long mvpconf0;
170 int nvpe;
171 int ntc;
172 int i;
173 int tc;
174 unsigned long haltval;
175 unsigned long tcstatval;
176#ifdef CONFIG_MIPS_MT_SMTC
177 void smtc_soft_dump(void);
178#endif /* CONFIG_MIPT_MT_SMTC */
179
180 local_irq_save(flags);
181 vpflags = dvpe();
182 printk("=== MIPS MT State Dump ===\n");
183 printk("-- Global State --\n");
184 printk(" MVPControl Passed: %08lx\n", mvpctl);
185 printk(" MVPControl Read: %08lx\n", vpflags);
186 printk(" MVPConf0 : %08lx\n", (mvpconf0 = read_c0_mvpconf0()));
187 nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
188 ntc = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
189 printk("-- per-VPE State --\n");
190 for(i = 0; i < nvpe; i++) {
191 for(tc = 0; tc < ntc; tc++) {
192 settc(tc);
193 if((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) {
194 printk(" VPE %d\n", i);
195 printk(" VPEControl : %08lx\n", read_vpe_c0_vpecontrol());
196 printk(" VPEConf0 : %08lx\n", read_vpe_c0_vpeconf0());
197 printk(" VPE%d.Status : %08lx\n",
198 i, read_vpe_c0_status());
199 printk(" VPE%d.EPC : %08lx\n", i, read_vpe_c0_epc());
200 printk(" VPE%d.Cause : %08lx\n", i, read_vpe_c0_cause());
201 printk(" VPE%d.Config7 : %08lx\n",
202 i, read_vpe_c0_config7());
203 break; /* Next VPE */
204 }
205 }
206 }
207 printk("-- per-TC State --\n");
208 for(tc = 0; tc < ntc; tc++) {
209 settc(tc);
210 if(read_tc_c0_tcbind() == read_c0_tcbind()) {
211 /* Are we dumping ourself? */
212 haltval = 0; /* Then we're not halted, and mustn't be */
213 tcstatval = flags; /* And pre-dump TCStatus is flags */
214 printk(" TC %d (current TC with VPE EPC above)\n", tc);
215 } else {
216 haltval = read_tc_c0_tchalt();
217 write_tc_c0_tchalt(1);
218 tcstatval = read_tc_c0_tcstatus();
219 printk(" TC %d\n", tc);
220 }
221 printk(" TCStatus : %08lx\n", tcstatval);
222 printk(" TCBind : %08lx\n", read_tc_c0_tcbind());
223 printk(" TCRestart : %08lx\n", read_tc_c0_tcrestart());
224 printk(" TCHalt : %08lx\n", haltval);
225 printk(" TCContext : %08lx\n", read_tc_c0_tccontext());
226 if (!haltval)
227 write_tc_c0_tchalt(0);
228 }
229#ifdef CONFIG_MIPS_MT_SMTC
230 smtc_soft_dump();
231#endif /* CONFIG_MIPT_MT_SMTC */
232 printk("===========================\n");
233 evpe(vpflags);
234 local_irq_restore(flags);
235}
236
237static int mt_opt_norps = 0;
238static int mt_opt_rpsctl = -1;
239static int mt_opt_nblsu = -1;
240static int mt_opt_forceconfig7 = 0;
241static int mt_opt_config7 = -1;
242
243static int __init rps_disable(char *s)
244{
245 mt_opt_norps = 1;
246 return 1;
247}
248__setup("norps", rps_disable);
249
250static int __init rpsctl_set(char *str)
251{
252 get_option(&str, &mt_opt_rpsctl);
253 return 1;
254}
255__setup("rpsctl=", rpsctl_set);
256
257static int __init nblsu_set(char *str)
258{
259 get_option(&str, &mt_opt_nblsu);
260 return 1;
261}
262__setup("nblsu=", nblsu_set);
263
264static int __init config7_set(char *str)
265{
266 get_option(&str, &mt_opt_config7);
267 mt_opt_forceconfig7 = 1;
268 return 1;
269}
270__setup("config7=", config7_set);
271
272/* Experimental cache flush control parameters that should go away some day */
273int mt_protiflush = 0;
274int mt_protdflush = 0;
275int mt_n_iflushes = 1;
276int mt_n_dflushes = 1;
277
278static int __init set_protiflush(char *s)
279{
280 mt_protiflush = 1;
281 return 1;
282}
283__setup("protiflush", set_protiflush);
284
285static int __init set_protdflush(char *s)
286{
287 mt_protdflush = 1;
288 return 1;
289}
290__setup("protdflush", set_protdflush);
291
292static int __init niflush(char *s)
293{
294 get_option(&s, &mt_n_iflushes);
295 return 1;
296}
297__setup("niflush=", niflush);
298
299static int __init ndflush(char *s)
300{
301 get_option(&s, &mt_n_dflushes);
302 return 1;
303}
304__setup("ndflush=", ndflush);
305#ifdef CONFIG_MIPS_MT_FPAFF
306static int fpaff_threshold = -1;
307
308static int __init fpaff_thresh(char *str)
309{
310 get_option(&str, &fpaff_threshold);
311 return 1;
312}
313
314__setup("fpaff=", fpaff_thresh);
315#endif /* CONFIG_MIPS_MT_FPAFF */
316
317static unsigned int itc_base = 0;
318
319static int __init set_itc_base(char *str)
320{
321 get_option(&str, &itc_base);
322 return 1;
323}
324
325__setup("itcbase=", set_itc_base);
326
327void mips_mt_set_cpuoptions(void)
328{
329 unsigned int oconfig7 = read_c0_config7();
330 unsigned int nconfig7 = oconfig7;
331
332 if (mt_opt_norps) {
333 printk("\"norps\" option deprectated: use \"rpsctl=\"\n");
334 }
335 if (mt_opt_rpsctl >= 0) {
336 printk("34K return prediction stack override set to %d.\n",
337 mt_opt_rpsctl);
338 if (mt_opt_rpsctl)
339 nconfig7 |= (1 << 2);
340 else
341 nconfig7 &= ~(1 << 2);
342 }
343 if (mt_opt_nblsu >= 0) {
344 printk("34K ALU/LSU sync override set to %d.\n", mt_opt_nblsu);
345 if (mt_opt_nblsu)
346 nconfig7 |= (1 << 5);
347 else
348 nconfig7 &= ~(1 << 5);
349 }
350 if (mt_opt_forceconfig7) {
351 printk("CP0.Config7 forced to 0x%08x.\n", mt_opt_config7);
352 nconfig7 = mt_opt_config7;
353 }
354 if (oconfig7 != nconfig7) {
355 __asm__ __volatile("sync");
356 write_c0_config7(nconfig7);
357 ehb ();
358 printk("Config7: 0x%08x\n", read_c0_config7());
359 }
360
361 /* Report Cache management debug options */
362 if (mt_protiflush)
363 printk("I-cache flushes single-threaded\n");
364 if (mt_protdflush)
365 printk("D-cache flushes single-threaded\n");
366 if (mt_n_iflushes != 1)
367 printk("I-Cache Flushes Repeated %d times\n", mt_n_iflushes);
368 if (mt_n_dflushes != 1)
369 printk("D-Cache Flushes Repeated %d times\n", mt_n_dflushes);
370
371#ifdef CONFIG_MIPS_MT_FPAFF
372 /* FPU Use Factor empirically derived from experiments on 34K */
373#define FPUSEFACTOR 333
374
375 if (fpaff_threshold >= 0) {
376 mt_fpemul_threshold = fpaff_threshold;
377 } else {
378 mt_fpemul_threshold =
379 (FPUSEFACTOR * (loops_per_jiffy/(500000/HZ))) / HZ;
380 }
381 printk("FPU Affinity set after %ld emulations\n",
382 mt_fpemul_threshold);
383#endif /* CONFIG_MIPS_MT_FPAFF */
384
385 if (itc_base != 0) {
386 /*
387 * Configure ITC mapping. This code is very
388 * specific to the 34K core family, which uses
389 * a special mode bit ("ITC") in the ErrCtl
390 * register to enable access to ITC control
391 * registers via cache "tag" operations.
392 */
393 unsigned long ectlval;
394 unsigned long itcblkgrn;
395
396 /* ErrCtl register is known as "ecc" to Linux */
397 ectlval = read_c0_ecc();
398 write_c0_ecc(ectlval | (0x1 << 26));
399 ehb();
400#define INDEX_0 (0x80000000)
401#define INDEX_8 (0x80000008)
402 /* Read "cache tag" for Dcache pseudo-index 8 */
403 cache_op(Index_Load_Tag_D, INDEX_8);
404 ehb();
405 itcblkgrn = read_c0_dtaglo();
406 itcblkgrn &= 0xfffe0000;
407 /* Set for 128 byte pitch of ITC cells */
408 itcblkgrn |= 0x00000c00;
409 /* Stage in Tag register */
410 write_c0_dtaglo(itcblkgrn);
411 ehb();
412 /* Write out to ITU with CACHE op */
413 cache_op(Index_Store_Tag_D, INDEX_8);
414 /* Now set base address, and turn ITC on with 0x1 bit */
415 write_c0_dtaglo((itc_base & 0xfffffc00) | 0x1 );
416 ehb();
417 /* Write out to ITU with CACHE op */
418 cache_op(Index_Store_Tag_D, INDEX_0);
419 write_c0_ecc(ectlval);
420 ehb();
421 printk("Mapped %ld ITC cells starting at 0x%08x\n",
422 ((itcblkgrn & 0x7fe00000) >> 20), itc_base);
423 }
424}
425
426/*
427 * Function to protect cache flushes from concurrent execution
428 * depends on MP software model chosen.
429 */
430
431void mt_cflush_lockdown(void)
432{
433#ifdef CONFIG_MIPS_MT_SMTC
434 void smtc_cflush_lockdown(void);
435
436 smtc_cflush_lockdown();
437#endif /* CONFIG_MIPS_MT_SMTC */
438 /* FILL IN VSMP and AP/SP VERSIONS HERE */
439}
440
441void mt_cflush_release(void)
442{
443#ifdef CONFIG_MIPS_MT_SMTC
444 void smtc_cflush_release(void);
445
446 smtc_cflush_release();
447#endif /* CONFIG_MIPS_MT_SMTC */
448 /* FILL IN VSMP and AP/SP VERSIONS HERE */
449}
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index e042f9d2ba31..0a71a4c33716 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);
28/* 28/*
29 * String functions 29 * String functions
30 */ 30 */
31EXPORT_SYMBOL(memchr);
32EXPORT_SYMBOL(memcmp);
33EXPORT_SYMBOL(memset); 31EXPORT_SYMBOL(memset);
34EXPORT_SYMBOL(memcpy); 32EXPORT_SYMBOL(memcpy);
35EXPORT_SYMBOL(memmove); 33EXPORT_SYMBOL(memmove);
36EXPORT_SYMBOL(strcat);
37EXPORT_SYMBOL(strchr);
38#ifdef CONFIG_64BIT
39EXPORT_SYMBOL(strncmp);
40#endif
41EXPORT_SYMBOL(strlen);
42EXPORT_SYMBOL(strncat);
43EXPORT_SYMBOL(strnlen);
44EXPORT_SYMBOL(strrchr);
45EXPORT_SYMBOL(strstr);
46 34
47EXPORT_SYMBOL(kernel_thread); 35EXPORT_SYMBOL(kernel_thread);
48 36
@@ -61,6 +49,3 @@ EXPORT_SYMBOL(__strnlen_user_asm);
61EXPORT_SYMBOL(csum_partial); 49EXPORT_SYMBOL(csum_partial);
62 50
63EXPORT_SYMBOL(invalid_pte_table); 51EXPORT_SYMBOL(invalid_pte_table);
64#ifdef CONFIG_GENERIC_IRQ_PROBE
65EXPORT_SYMBOL(probe_irq_mask);
66#endif
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index c66db5e5ab62..199a06e873c6 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -41,6 +41,10 @@
41#include <asm/elf.h> 41#include <asm/elf.h>
42#include <asm/isadep.h> 42#include <asm/isadep.h>
43#include <asm/inst.h> 43#include <asm/inst.h>
44#ifdef CONFIG_MIPS_MT_SMTC
45#include <asm/mipsmtregs.h>
46extern void smtc_idle_loop_hook(void);
47#endif /* CONFIG_MIPS_MT_SMTC */
44 48
45/* 49/*
46 * The idle thread. There's no useful work to be done, so just try to conserve 50 * 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)
51{ 55{
52 /* endless idle loop with no priority at all */ 56 /* endless idle loop with no priority at all */
53 while (1) { 57 while (1) {
54 while (!need_resched()) 58 while (!need_resched()) {
59#ifdef CONFIG_MIPS_MT_SMTC
60 smtc_idle_loop_hook();
61#endif /* CONFIG_MIPS_MT_SMTC */
55 if (cpu_wait) 62 if (cpu_wait)
56 (*cpu_wait)(); 63 (*cpu_wait)();
64 }
57 preempt_enable_no_resched(); 65 preempt_enable_no_resched();
58 schedule(); 66 schedule();
59 preempt_disable(); 67 preempt_disable();
@@ -177,6 +185,17 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
177 childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); 185 childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
178 clear_tsk_thread_flag(p, TIF_USEDFPU); 186 clear_tsk_thread_flag(p, TIF_USEDFPU);
179 187
188#ifdef CONFIG_MIPS_MT_FPAFF
189 /*
190 * FPU affinity support is cleaner if we track the
191 * user-visible CPU affinity from the very beginning.
192 * The generic cpus_allowed mask will already have
193 * been copied from the parent before copy_thread
194 * is invoked.
195 */
196 p->thread.user_cpus_allowed = p->cpus_allowed;
197#endif /* CONFIG_MIPS_MT_FPAFF */
198
180 if (clone_flags & CLONE_SETTLS) 199 if (clone_flags & CLONE_SETTLS)
181 ti->tp_value = regs->regs[7]; 200 ti->tp_value = regs->regs[7];
182 201
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index f838b36cc765..f3106d0771b0 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)
248 break; 248 break;
249 case FPC_EIR: { /* implementation / version register */ 249 case FPC_EIR: { /* implementation / version register */
250 unsigned int flags; 250 unsigned int flags;
251#ifdef CONFIG_MIPS_MT_SMTC
252 unsigned int irqflags;
253 unsigned int mtflags;
254#endif /* CONFIG_MIPS_MT_SMTC */
251 255
252 if (!cpu_has_fpu) 256 if (!cpu_has_fpu)
253 break; 257 break;
254 258
259#ifdef CONFIG_MIPS_MT_SMTC
260 /* Read-modify-write of Status must be atomic */
261 local_irq_save(irqflags);
262 mtflags = dmt();
263#endif /* CONFIG_MIPS_MT_SMTC */
264
255 preempt_disable(); 265 preempt_disable();
256 if (cpu_has_mipsmt) { 266 if (cpu_has_mipsmt) {
257 unsigned int vpflags = dvpe(); 267 unsigned int vpflags = dvpe();
@@ -266,6 +276,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
266 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 276 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
267 write_c0_status(flags); 277 write_c0_status(flags);
268 } 278 }
279#ifdef CONFIG_MIPS_MT_SMTC
280 emt(mtflags);
281 local_irq_restore(irqflags);
282#endif /* CONFIG_MIPS_MT_SMTC */
269 preempt_enable(); 283 preempt_enable();
270 break; 284 break;
271 } 285 }
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index 0d5cf97af727..8704dc0496ea 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)
173 break; 173 break;
174 case FPC_EIR: { /* implementation / version register */ 174 case FPC_EIR: { /* implementation / version register */
175 unsigned int flags; 175 unsigned int flags;
176#ifdef CONFIG_MIPS_MT_SMTC
177 unsigned int irqflags;
178 unsigned int mtflags;
179#endif /* CONFIG_MIPS_MT_SMTC */
176 180
177 if (!cpu_has_fpu) { 181 if (!cpu_has_fpu) {
178 tmp = 0; 182 tmp = 0;
179 break; 183 break;
180 } 184 }
181 185
186#ifdef CONFIG_MIPS_MT_SMTC
187 /* Read-modify-write of Status must be atomic */
188 local_irq_save(irqflags);
189 mtflags = dmt();
190#endif /* CONFIG_MIPS_MT_SMTC */
191
182 preempt_disable(); 192 preempt_disable();
183 if (cpu_has_mipsmt) { 193 if (cpu_has_mipsmt) {
184 unsigned int vpflags = dvpe(); 194 unsigned int vpflags = dvpe();
@@ -193,6 +203,10 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
193 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 203 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
194 write_c0_status(flags); 204 write_c0_status(flags);
195 } 205 }
206#ifdef CONFIG_MIPS_MT_SMTC
207 emt(mtflags);
208 local_irq_restore(irqflags);
209#endif /* CONFIG_MIPS_MT_SMTC */
196 preempt_enable(); 210 preempt_enable();
197 break; 211 break;
198 } 212 }
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index d2afbd19a9c8..0b1b54acee9f 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -88,7 +88,18 @@
88 88
89 PTR_ADDIU t0, $28, _THREAD_SIZE - 32 89 PTR_ADDIU t0, $28, _THREAD_SIZE - 32
90 set_saved_sp t0, t1, t2 90 set_saved_sp t0, t1, t2
91 91#ifdef CONFIG_MIPS_MT_SMTC
92 /* Read-modify-writes of Status must be atomic on a VPE */
93 mfc0 t2, CP0_TCSTATUS
94 ori t1, t2, TCSTATUS_IXMT
95 mtc0 t1, CP0_TCSTATUS
96 andi t2, t2, TCSTATUS_IXMT
97 ehb
98 DMT 8 # dmt t0
99 move t1,ra
100 jal mips_ihb
101 move ra,t1
102#endif /* CONFIG_MIPS_MT_SMTC */
92 mfc0 t1, CP0_STATUS /* Do we really need this? */ 103 mfc0 t1, CP0_STATUS /* Do we really need this? */
93 li a3, 0xff01 104 li a3, 0xff01
94 and t1, a3 105 and t1, a3
@@ -97,6 +108,18 @@
97 and a2, a3 108 and a2, a3
98 or a2, t1 109 or a2, t1
99 mtc0 a2, CP0_STATUS 110 mtc0 a2, CP0_STATUS
111#ifdef CONFIG_MIPS_MT_SMTC
112 ehb
113 andi t0, t0, VPECONTROL_TE
114 beqz t0, 1f
115 emt
1161:
117 mfc0 t1, CP0_TCSTATUS
118 xori t1, t1, TCSTATUS_IXMT
119 or t1, t1, t2
120 mtc0 t1, CP0_TCSTATUS
121 ehb
122#endif /* CONFIG_MIPS_MT_SMTC */
100 move v0, a0 123 move v0, a0
101 jr ra 124 jr ra
102 END(resume) 125 END(resume)
@@ -131,10 +154,19 @@ LEAF(_restore_fp)
131#define FPU_DEFAULT 0x00000000 154#define FPU_DEFAULT 0x00000000
132 155
133LEAF(_init_fpu) 156LEAF(_init_fpu)
157#ifdef CONFIG_MIPS_MT_SMTC
158 /* Rather than manipulate per-VPE Status, set per-TC bit in TCStatus */
159 mfc0 t0, CP0_TCSTATUS
160 /* Bit position is the same for Status, TCStatus */
161 li t1, ST0_CU1
162 or t0, t1
163 mtc0 t0, CP0_TCSTATUS
164#else /* Normal MIPS CU1 enable */
134 mfc0 t0, CP0_STATUS 165 mfc0 t0, CP0_STATUS
135 li t1, ST0_CU1 166 li t1, ST0_CU1
136 or t0, t1 167 or t0, t1
137 mtc0 t0, CP0_STATUS 168 mtc0 t0, CP0_STATUS
169#endif /* CONFIG_MIPS_MT_SMTC */
138 fpu_enable_hazard 170 fpu_enable_hazard
139 171
140 li t1, FPU_DEFAULT 172 li t1, FPU_DEFAULT
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index 986a9cf23067..6179805af9f0 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -21,45 +21,44 @@
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/fs.h> 22#include <linux/fs.h>
23#include <linux/init.h> 23#include <linux/init.h>
24#include <asm/uaccess.h>
25#include <linux/slab.h>
26#include <linux/list.h>
27#include <linux/vmalloc.h>
28#include <linux/elf.h>
29#include <linux/seq_file.h>
30#include <linux/syscalls.h>
31#include <linux/moduleloader.h>
24#include <linux/interrupt.h> 32#include <linux/interrupt.h>
25#include <linux/irq.h>
26#include <linux/poll.h> 33#include <linux/poll.h>
27#include <linux/sched.h> 34#include <linux/sched.h>
28#include <linux/wait.h> 35#include <linux/wait.h>
29
30#include <asm/mipsmtregs.h> 36#include <asm/mipsmtregs.h>
31#include <asm/bitops.h> 37#include <asm/cacheflush.h>
38#include <asm/atomic.h>
32#include <asm/cpu.h> 39#include <asm/cpu.h>
33#include <asm/processor.h> 40#include <asm/processor.h>
41#include <asm/system.h>
42#include <asm/vpe.h>
34#include <asm/rtlx.h> 43#include <asm/rtlx.h>
35#include <asm/uaccess.h>
36 44
37#define RTLX_TARG_VPE 1 45#define RTLX_TARG_VPE 1
38 46
39static struct rtlx_info *rtlx; 47static struct rtlx_info *rtlx;
40static int major; 48static int major;
41static char module_name[] = "rtlx"; 49static char module_name[] = "rtlx";
42static struct irqaction irq;
43static int irq_num;
44
45static inline int spacefree(int read, int write, int size)
46{
47 if (read == write) {
48 /*
49 * never fill the buffer completely, so indexes are always
50 * equal if empty and only empty, or !equal if data available
51 */
52 return size - 1;
53 }
54
55 return ((read + size - write) % size) - 1;
56}
57 50
58static struct chan_waitqueues { 51static struct chan_waitqueues {
59 wait_queue_head_t rt_queue; 52 wait_queue_head_t rt_queue;
60 wait_queue_head_t lx_queue; 53 wait_queue_head_t lx_queue;
54 int in_open;
61} channel_wqs[RTLX_CHANNELS]; 55} channel_wqs[RTLX_CHANNELS];
62 56
57static struct irqaction irq;
58static int irq_num;
59static struct vpe_notifications notify;
60static int sp_stopping = 0;
61
63extern void *vpe_get_shared(int index); 62extern void *vpe_get_shared(int index);
64 63
65static void rtlx_dispatch(struct pt_regs *regs) 64static void rtlx_dispatch(struct pt_regs *regs)
@@ -67,174 +66,298 @@ static void rtlx_dispatch(struct pt_regs *regs)
67 do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs); 66 do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs);
68} 67}
69 68
69
70/* Interrupt handler may be called before rtlx_init has otherwise had
71 a chance to run.
72*/
70static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) 73static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
71{ 74{
72 int i; 75 int i;
73 76
74 for (i = 0; i < RTLX_CHANNELS; i++) { 77 for (i = 0; i < RTLX_CHANNELS; i++) {
75 struct rtlx_channel *chan = &rtlx->channel[i]; 78 wake_up(&channel_wqs[i].lx_queue);
76 79 wake_up(&channel_wqs[i].rt_queue);
77 if (chan->lx_read != chan->lx_write)
78 wake_up_interruptible(&channel_wqs[i].lx_queue);
79 } 80 }
80 81
81 return IRQ_HANDLED; 82 return IRQ_HANDLED;
82} 83}
83 84
84/* call when we have the address of the shared structure from the SP side. */ 85static __attribute_used__ void dump_rtlx(void)
85static int rtlx_init(struct rtlx_info *rtlxi)
86{ 86{
87 int i; 87 int i;
88 88
89 if (rtlxi->id != RTLX_ID) { 89 printk("id 0x%lx state %d\n", rtlx->id, rtlx->state);
90 printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi);
91 return -ENOEXEC;
92 }
93 90
94 /* initialise the wait queues */
95 for (i = 0; i < RTLX_CHANNELS; i++) { 91 for (i = 0; i < RTLX_CHANNELS; i++) {
96 init_waitqueue_head(&channel_wqs[i].rt_queue); 92 struct rtlx_channel *chan = &rtlx->channel[i];
97 init_waitqueue_head(&channel_wqs[i].lx_queue);
98 }
99 93
100 /* set up for interrupt handling */ 94 printk(" rt_state %d lx_state %d buffer_size %d\n",
101 memset(&irq, 0, sizeof(struct irqaction)); 95 chan->rt_state, chan->lx_state, chan->buffer_size);
102 96
103 if (cpu_has_vint) 97 printk(" rt_read %d rt_write %d\n",
104 set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); 98 chan->rt_read, chan->rt_write);
105 99
106 irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ; 100 printk(" lx_read %d lx_write %d\n",
107 irq.handler = rtlx_interrupt; 101 chan->lx_read, chan->lx_write);
108 irq.flags = SA_INTERRUPT; 102
109 irq.name = "RTLX"; 103 printk(" rt_buffer <%s>\n", chan->rt_buffer);
110 irq.dev_id = rtlx; 104 printk(" lx_buffer <%s>\n", chan->lx_buffer);
111 setup_irq(irq_num, &irq); 105 }
106}
107
108/* call when we have the address of the shared structure from the SP side. */
109static int rtlx_init(struct rtlx_info *rtlxi)
110{
111 if (rtlxi->id != RTLX_ID) {
112 printk(KERN_ERR "no valid RTLX id at 0x%p 0x%x\n", rtlxi, rtlxi->id);
113 return -ENOEXEC;
114 }
112 115
113 rtlx = rtlxi; 116 rtlx = rtlxi;
114 117
115 return 0; 118 return 0;
116} 119}
117 120
118/* only allow one open process at a time to open each channel */ 121/* notifications */
119static int rtlx_open(struct inode *inode, struct file *filp) 122static void starting(int vpe)
120{ 123{
121 int minor, ret; 124 int i;
125 sp_stopping = 0;
126
127 /* force a reload of rtlx */
128 rtlx=NULL;
129
130 /* wake up any sleeping rtlx_open's */
131 for (i = 0; i < RTLX_CHANNELS; i++)
132 wake_up_interruptible(&channel_wqs[i].lx_queue);
133}
134
135static void stopping(int vpe)
136{
137 int i;
138
139 sp_stopping = 1;
140 for (i = 0; i < RTLX_CHANNELS; i++)
141 wake_up_interruptible(&channel_wqs[i].lx_queue);
142}
143
144
145int rtlx_open(int index, int can_sleep)
146{
147 int ret;
122 struct rtlx_channel *chan; 148 struct rtlx_channel *chan;
149 volatile struct rtlx_info **p;
123 150
124 /* assume only 1 device at the mo. */ 151 if (index >= RTLX_CHANNELS) {
125 minor = MINOR(inode->i_rdev); 152 printk(KERN_DEBUG "rtlx_open index out of range\n");
153 return -ENOSYS;
154 }
155
156 if (channel_wqs[index].in_open) {
157 printk(KERN_DEBUG "rtlx_open channel %d already opened\n", index);
158 return -EBUSY;
159 }
160
161 channel_wqs[index].in_open++;
126 162
127 if (rtlx == NULL) { 163 if (rtlx == NULL) {
128 struct rtlx_info **p;
129 if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { 164 if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
130 printk(KERN_ERR "vpe_get_shared is NULL. " 165 if (can_sleep) {
131 "Has an SP program been loaded?\n"); 166 DECLARE_WAITQUEUE(wait, current);
132 return -EFAULT; 167
168 /* go to sleep */
169 add_wait_queue(&channel_wqs[index].lx_queue, &wait);
170
171 set_current_state(TASK_INTERRUPTIBLE);
172 while ((p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
173 schedule();
174 set_current_state(TASK_INTERRUPTIBLE);
175 }
176
177 set_current_state(TASK_RUNNING);
178 remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
179
180 /* back running */
181 } else {
182 printk( KERN_DEBUG "No SP program loaded, and device "
183 "opened with O_NONBLOCK\n");
184 channel_wqs[index].in_open = 0;
185 return -ENOSYS;
186 }
133 } 187 }
134 188
135 if (*p == NULL) { 189 if (*p == NULL) {
136 printk(KERN_ERR "vpe_shared %p %p\n", p, *p); 190 if (can_sleep) {
137 return -EFAULT; 191 DECLARE_WAITQUEUE(wait, current);
192
193 /* go to sleep */
194 add_wait_queue(&channel_wqs[index].lx_queue, &wait);
195
196 set_current_state(TASK_INTERRUPTIBLE);
197 while (*p == NULL) {
198 schedule();
199
200 /* reset task state to interruptable otherwise
201 we'll whizz round here like a very fast loopy
202 thing. schedule() appears to return with state
203 set to TASK_RUNNING.
204
205 If the loaded SP program, for whatever reason,
206 doesn't set up the shared structure *p will never
207 become true. So whoever connected to either /dev/rt?
208 or if it was kspd, will then take up rather a lot of
209 processor cycles.
210 */
211
212 set_current_state(TASK_INTERRUPTIBLE);
213 }
214
215 set_current_state(TASK_RUNNING);
216 remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
217
218 /* back running */
219 }
220 else {
221 printk(" *vpe_get_shared is NULL. "
222 "Has an SP program been loaded?\n");
223 channel_wqs[index].in_open = 0;
224 return -ENOSYS;
225 }
226 }
227
228 if ((unsigned int)*p < KSEG0) {
229 printk(KERN_WARNING "vpe_get_shared returned an invalid pointer "
230 "maybe an error code %d\n", (int)*p);
231 channel_wqs[index].in_open = 0;
232 return -ENOSYS;
138 } 233 }
139 234
140 if ((ret = rtlx_init(*p)) < 0) 235 if ((ret = rtlx_init(*p)) < 0) {
141 return ret; 236 channel_wqs[index].in_open = 0;
237 return ret;
238 }
142 } 239 }
143 240
144 chan = &rtlx->channel[minor]; 241 chan = &rtlx->channel[index];
145 242
146 if (test_and_set_bit(RTLX_STATE_OPENED, &chan->lx_state)) 243 if (chan->lx_state == RTLX_STATE_OPENED) {
147 return -EBUSY; 244 channel_wqs[index].in_open = 0;
245 return -EBUSY;
246 }
148 247
248 chan->lx_state = RTLX_STATE_OPENED;
249 channel_wqs[index].in_open = 0;
149 return 0; 250 return 0;
150} 251}
151 252
152static int rtlx_release(struct inode *inode, struct file *filp) 253int rtlx_release(int index)
153{ 254{
154 int minor = MINOR(inode->i_rdev); 255 rtlx->channel[index].lx_state = RTLX_STATE_UNUSED;
155
156 clear_bit(RTLX_STATE_OPENED, &rtlx->channel[minor].lx_state);
157 smp_mb__after_clear_bit();
158
159 return 0; 256 return 0;
160} 257}
161 258
162static unsigned int rtlx_poll(struct file *file, poll_table * wait) 259unsigned int rtlx_read_poll(int index, int can_sleep)
163{ 260{
164 int minor; 261 struct rtlx_channel *chan;
165 unsigned int mask = 0;
166 struct rtlx_channel *chan;
167 262
168 minor = MINOR(file->f_dentry->d_inode->i_rdev); 263 if (rtlx == NULL)
169 chan = &rtlx->channel[minor]; 264 return 0;
170 265
171 poll_wait(file, &channel_wqs[minor].rt_queue, wait); 266 chan = &rtlx->channel[index];
172 poll_wait(file, &channel_wqs[minor].lx_queue, wait);
173 267
174 /* data available to read? */ 268 /* data available to read? */
175 if (chan->lx_read != chan->lx_write) 269 if (chan->lx_read == chan->lx_write) {
176 mask |= POLLIN | POLLRDNORM; 270 if (can_sleep) {
271 DECLARE_WAITQUEUE(wait, current);
177 272
178 /* space to write */ 273 /* go to sleep */
179 if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size)) 274 add_wait_queue(&channel_wqs[index].lx_queue, &wait);
180 mask |= POLLOUT | POLLWRNORM;
181 275
182 return mask; 276 set_current_state(TASK_INTERRUPTIBLE);
277 while (chan->lx_read == chan->lx_write) {
278 schedule();
279
280 set_current_state(TASK_INTERRUPTIBLE);
281
282 if (sp_stopping) {
283 set_current_state(TASK_RUNNING);
284 remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
285 return 0;
286 }
287 }
288
289 set_current_state(TASK_RUNNING);
290 remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
291
292 /* back running */
293 }
294 else
295 return 0;
296 }
297
298 return (chan->lx_write + chan->buffer_size - chan->lx_read)
299 % chan->buffer_size;
183} 300}
184 301
185static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count, 302static inline int write_spacefree(int read, int write, int size)
186 loff_t * ppos)
187{ 303{
188 unsigned long failed; 304 if (read == write) {
189 size_t fl = 0L; 305 /*
190 int minor; 306 * Never fill the buffer completely, so indexes are always
191 struct rtlx_channel *lx; 307 * equal if empty and only empty, or !equal if data available
192 DECLARE_WAITQUEUE(wait, current); 308 */
309 return size - 1;
310 }
193 311
194 minor = MINOR(file->f_dentry->d_inode->i_rdev); 312 return ((read + size - write) % size) - 1;
195 lx = &rtlx->channel[minor]; 313}
196 314
197 /* data available? */ 315unsigned int rtlx_write_poll(int index)
198 if (lx->lx_write == lx->lx_read) { 316{
199 if (file->f_flags & O_NONBLOCK) 317 struct rtlx_channel *chan = &rtlx->channel[index];
200 return 0; /* -EAGAIN makes cat whinge */ 318 return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size);
319}
201 320
202 /* go to sleep */ 321static inline void copy_to(void *dst, void *src, size_t count, int user)
203 add_wait_queue(&channel_wqs[minor].lx_queue, &wait); 322{
204 set_current_state(TASK_INTERRUPTIBLE); 323 if (user)
324 copy_to_user(dst, src, count);
325 else
326 memcpy(dst, src, count);
327}
205 328
206 while (lx->lx_write == lx->lx_read) 329static inline void copy_from(void *dst, void *src, size_t count, int user)
207 schedule(); 330{
331 if (user)
332 copy_from_user(dst, src, count);
333 else
334 memcpy(dst, src, count);
335}
208 336
209 set_current_state(TASK_RUNNING); 337ssize_t rtlx_read(int index, void *buff, size_t count, int user)
210 remove_wait_queue(&channel_wqs[minor].lx_queue, &wait); 338{
339 size_t fl = 0L;
340 struct rtlx_channel *lx;
211 341
212 /* back running */ 342 if (rtlx == NULL)
213 } 343 return -ENOSYS;
344
345 lx = &rtlx->channel[index];
214 346
215 /* find out how much in total */ 347 /* find out how much in total */
216 count = min(count, 348 count = min(count,
217 (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size); 349 (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read)
350 % lx->buffer_size);
218 351
219 /* then how much from the read pointer onwards */ 352 /* then how much from the read pointer onwards */
220 fl = min(count, (size_t)lx->buffer_size - lx->lx_read); 353 fl = min( count, (size_t)lx->buffer_size - lx->lx_read);
221 354
222 failed = copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl); 355 copy_to(buff, &lx->lx_buffer[lx->lx_read], fl, user);
223 if (failed) {
224 count = fl - failed;
225 goto out;
226 }
227 356
228 /* and if there is anything left at the beginning of the buffer */ 357 /* and if there is anything left at the beginning of the buffer */
229 if (count - fl) { 358 if ( count - fl )
230 failed = copy_to_user (buffer + fl, lx->lx_buffer, count - fl); 359 copy_to (buff + fl, lx->lx_buffer, count - fl, user);
231 if (failed) {
232 count -= failed;
233 goto out;
234 }
235 }
236 360
237out:
238 /* update the index */ 361 /* update the index */
239 lx->lx_read += count; 362 lx->lx_read += count;
240 lx->lx_read %= lx->buffer_size; 363 lx->lx_read %= lx->buffer_size;
@@ -242,20 +365,101 @@ out:
242 return count; 365 return count;
243} 366}
244 367
245static ssize_t rtlx_write(struct file *file, const char __user * buffer, 368ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
369{
370 struct rtlx_channel *rt;
371 size_t fl;
372
373 if (rtlx == NULL)
374 return(-ENOSYS);
375
376 rt = &rtlx->channel[index];
377
378 /* total number of bytes to copy */
379 count = min(count,
380 (size_t)write_spacefree(rt->rt_read, rt->rt_write,
381 rt->buffer_size));
382
383 /* first bit from write pointer to the end of the buffer, or count */
384 fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
385
386 copy_from (&rt->rt_buffer[rt->rt_write], buffer, fl, user);
387
388 /* if there's any left copy to the beginning of the buffer */
389 if( count - fl )
390 copy_from (rt->rt_buffer, buffer + fl, count - fl, user);
391
392 rt->rt_write += count;
393 rt->rt_write %= rt->buffer_size;
394
395 return(count);
396}
397
398
399static int file_open(struct inode *inode, struct file *filp)
400{
401 int minor = MINOR(inode->i_rdev);
402
403 return rtlx_open(minor, (filp->f_flags & O_NONBLOCK) ? 0 : 1);
404}
405
406static int file_release(struct inode *inode, struct file *filp)
407{
408 int minor;
409 minor = MINOR(inode->i_rdev);
410
411 return rtlx_release(minor);
412}
413
414static unsigned int file_poll(struct file *file, poll_table * wait)
415{
416 int minor;
417 unsigned int mask = 0;
418
419 minor = MINOR(file->f_dentry->d_inode->i_rdev);
420
421 poll_wait(file, &channel_wqs[minor].rt_queue, wait);
422 poll_wait(file, &channel_wqs[minor].lx_queue, wait);
423
424 if (rtlx == NULL)
425 return 0;
426
427 /* data available to read? */
428 if (rtlx_read_poll(minor, 0))
429 mask |= POLLIN | POLLRDNORM;
430
431 /* space to write */
432 if (rtlx_write_poll(minor))
433 mask |= POLLOUT | POLLWRNORM;
434
435 return mask;
436}
437
438static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
439 loff_t * ppos)
440{
441 int minor = MINOR(file->f_dentry->d_inode->i_rdev);
442
443 /* data available? */
444 if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) {
445 return 0; // -EAGAIN makes cat whinge
446 }
447
448 return rtlx_read(minor, buffer, count, 1);
449}
450
451static ssize_t file_write(struct file *file, const char __user * buffer,
246 size_t count, loff_t * ppos) 452 size_t count, loff_t * ppos)
247{ 453{
248 unsigned long failed;
249 int minor; 454 int minor;
250 struct rtlx_channel *rt; 455 struct rtlx_channel *rt;
251 size_t fl;
252 DECLARE_WAITQUEUE(wait, current); 456 DECLARE_WAITQUEUE(wait, current);
253 457
254 minor = MINOR(file->f_dentry->d_inode->i_rdev); 458 minor = MINOR(file->f_dentry->d_inode->i_rdev);
255 rt = &rtlx->channel[minor]; 459 rt = &rtlx->channel[minor];
256 460
257 /* any space left... */ 461 /* any space left... */
258 if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) { 462 if (!rtlx_write_poll(minor)) {
259 463
260 if (file->f_flags & O_NONBLOCK) 464 if (file->f_flags & O_NONBLOCK)
261 return -EAGAIN; 465 return -EAGAIN;
@@ -263,61 +467,64 @@ static ssize_t rtlx_write(struct file *file, const char __user * buffer,
263 add_wait_queue(&channel_wqs[minor].rt_queue, &wait); 467 add_wait_queue(&channel_wqs[minor].rt_queue, &wait);
264 set_current_state(TASK_INTERRUPTIBLE); 468 set_current_state(TASK_INTERRUPTIBLE);
265 469
266 while (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) 470 while (!rtlx_write_poll(minor))
267 schedule(); 471 schedule();
268 472
269 set_current_state(TASK_RUNNING); 473 set_current_state(TASK_RUNNING);
270 remove_wait_queue(&channel_wqs[minor].rt_queue, &wait); 474 remove_wait_queue(&channel_wqs[minor].rt_queue, &wait);
271 } 475 }
272 476
273 /* total number of bytes to copy */ 477 return rtlx_write(minor, (void *)buffer, count, 1);
274 count = min(count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) );
275
276 /* first bit from write pointer to the end of the buffer, or count */
277 fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
278
279 failed = copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl);
280 if (failed) {
281 count = fl - failed;
282 goto out;
283 }
284
285 /* if there's any left copy to the beginning of the buffer */
286 if (count - fl) {
287 failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
288 if (failed) {
289 count -= failed;
290 goto out;
291 }
292 }
293
294out:
295 rt->rt_write += count;
296 rt->rt_write %= rt->buffer_size;
297
298 return count;
299} 478}
300 479
301static struct file_operations rtlx_fops = { 480static struct file_operations rtlx_fops = {
302 .owner = THIS_MODULE, 481 .owner = THIS_MODULE,
303 .open = rtlx_open, 482 .open = file_open,
304 .release = rtlx_release, 483 .release = file_release,
305 .write = rtlx_write, 484 .write = file_write,
306 .read = rtlx_read, 485 .read = file_read,
307 .poll = rtlx_poll 486 .poll = file_poll
308}; 487};
309 488
489static struct irqaction rtlx_irq = {
490 .handler = rtlx_interrupt,
491 .flags = SA_INTERRUPT,
492 .name = "RTLX",
493};
494
495static int rtlx_irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
496
310static char register_chrdev_failed[] __initdata = 497static char register_chrdev_failed[] __initdata =
311 KERN_ERR "rtlx_module_init: unable to register device\n"; 498 KERN_ERR "rtlx_module_init: unable to register device\n";
312 499
313static int __init rtlx_module_init(void) 500static int rtlx_module_init(void)
314{ 501{
502 int i;
503
315 major = register_chrdev(0, module_name, &rtlx_fops); 504 major = register_chrdev(0, module_name, &rtlx_fops);
316 if (major < 0) { 505 if (major < 0) {
317 printk(register_chrdev_failed); 506 printk(register_chrdev_failed);
318 return major; 507 return major;
319 } 508 }
320 509
510 /* initialise the wait queues */
511 for (i = 0; i < RTLX_CHANNELS; i++) {
512 init_waitqueue_head(&channel_wqs[i].rt_queue);
513 init_waitqueue_head(&channel_wqs[i].lx_queue);
514 channel_wqs[i].in_open = 0;
515 }
516
517 /* set up notifiers */
518 notify.start = starting;
519 notify.stop = stopping;
520 vpe_notify(RTLX_TARG_VPE, &notify);
521
522 if (cpu_has_vint)
523 set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
524
525 rtlx_irq.dev_id = rtlx;
526 setup_irq(rtlx_irq_num, &rtlx_irq);
527
321 return 0; 528 return 0;
322} 529}
323 530
@@ -330,5 +537,5 @@ module_init(rtlx_module_init);
330module_exit(rtlx_module_exit); 537module_exit(rtlx_module_exit);
331 538
332MODULE_DESCRIPTION("MIPS RTLX"); 539MODULE_DESCRIPTION("MIPS RTLX");
333MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc."); 540MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
334MODULE_LICENSE("GPL"); 541MODULE_LICENSE("GPL");
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 2f2dc54b2e26..a0ac0e5f61ad 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -569,8 +569,19 @@ einval: li v0, -EINVAL
569 sys sys_tkill 2 569 sys sys_tkill 2
570 sys sys_sendfile64 5 570 sys sys_sendfile64 5
571 sys sys_futex 6 571 sys sys_futex 6
572#ifdef CONFIG_MIPS_MT_FPAFF
573 /*
574 * For FPU affinity scheduling on MIPS MT processors, we need to
575 * intercept sys_sched_xxxaffinity() calls until we get a proper hook
576 * in kernel/sched.c. Considered only temporary we only support these
577 * hooks for the 32-bit kernel - there is no MIPS64 MT processor atm.
578 */
579 sys mipsmt_sys_sched_setaffinity 3
580 sys mipsmt_sys_sched_getaffinity 3
581#else
572 sys sys_sched_setaffinity 3 582 sys sys_sched_setaffinity 3
573 sys sys_sched_getaffinity 3 /* 4240 */ 583 sys sys_sched_getaffinity 3 /* 4240 */
584#endif /* CONFIG_MIPS_MT_FPAFF */
574 sys sys_io_setup 2 585 sys sys_io_setup 2
575 sys sys_io_destroy 1 586 sys sys_io_destroy 1
576 sys sys_io_getevents 5 587 sys sys_io_getevents 5
@@ -634,6 +645,8 @@ einval: li v0, -EINVAL
634 sys sys_pselect6 6 645 sys sys_pselect6 6
635 sys sys_ppoll 5 646 sys sys_ppoll 5
636 sys sys_unshare 1 647 sys sys_unshare 1
648 sys sys_splice 4
649 sys sys_sync_file_range 7 /* 4305 */
637 .endm 650 .endm
638 651
639 /* We pre-compute the number of _instruction_ bytes needed to 652 /* 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 98bf25df56f3..9ba750887377 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -460,3 +460,5 @@ sys_call_table:
460 PTR sys_pselect6 /* 5260 */ 460 PTR sys_pselect6 /* 5260 */
461 PTR sys_ppoll 461 PTR sys_ppoll
462 PTR sys_unshare 462 PTR sys_unshare
463 PTR sys_splice
464 PTR sys_sync_file_range
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 05a2c0567dae..942aca26f9c4 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -386,3 +386,5 @@ EXPORT(sysn32_call_table)
386 PTR sys_pselect6 386 PTR sys_pselect6
387 PTR sys_ppoll /* 6265 */ 387 PTR sys_ppoll /* 6265 */
388 PTR sys_unshare 388 PTR sys_unshare
389 PTR sys_splice
390 PTR sys_sync_file_range
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 19c4ca481b02..b53a9207f530 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -508,4 +508,6 @@ sys_call_table:
508 PTR sys_pselect6 508 PTR sys_pselect6
509 PTR sys_ppoll 509 PTR sys_ppoll
510 PTR sys_unshare 510 PTR sys_unshare
511 PTR sys_splice
512 PTR sys32_sync_file_range /* 4305 */
511 .size sys_call_table,.-sys_call_table 513 .size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index dcbfd27071f0..bcf1b10e518f 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -529,7 +529,10 @@ void __init setup_arch(char **cmdline_p)
529 529
530int __init fpu_disable(char *s) 530int __init fpu_disable(char *s)
531{ 531{
532 cpu_data[0].options &= ~MIPS_CPU_FPU; 532 int i;
533
534 for (i = 0; i < NR_CPUS; i++)
535 cpu_data[i].options &= ~MIPS_CPU_FPU;
533 536
534 return 1; 537 return 1;
535} 538}
diff --git a/arch/mips/kernel/smp_mt.c b/arch/mips/kernel/smp-mt.c
index 993b8bf56aaf..57770902b9ae 100644
--- a/arch/mips/kernel/smp_mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -1,8 +1,4 @@
1/* 1/*
2 * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved.
3 *
4 * Elizabeth Clarke (beth@mips.com)
5 *
6 * This program is free software; you can distribute it and/or modify it 2 * This program is free software; you can distribute it and/or modify it
7 * under the terms of the GNU General Public License (Version 2) as 3 * under the terms of the GNU General Public License (Version 2) as
8 * published by the Free Software Foundation. 4 * published by the Free Software Foundation.
@@ -16,6 +12,10 @@
16 * with this program; if not, write to the Free Software Foundation, Inc., 12 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 13 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
18 * 14 *
15 * Copyright (C) 2004, 05, 06 MIPS Technologies, Inc.
16 * Elizabeth Clarke (beth@mips.com)
17 * Ralf Baechle (ralf@linux-mips.org)
18 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
19 */ 19 */
20#include <linux/kernel.h> 20#include <linux/kernel.h>
21#include <linux/sched.h> 21#include <linux/sched.h>
@@ -24,6 +24,7 @@
24#include <linux/compiler.h> 24#include <linux/compiler.h>
25 25
26#include <asm/atomic.h> 26#include <asm/atomic.h>
27#include <asm/cacheflush.h>
27#include <asm/cpu.h> 28#include <asm/cpu.h>
28#include <asm/processor.h> 29#include <asm/processor.h>
29#include <asm/system.h> 30#include <asm/system.h>
@@ -33,8 +34,8 @@
33#include <asm/time.h> 34#include <asm/time.h>
34#include <asm/mipsregs.h> 35#include <asm/mipsregs.h>
35#include <asm/mipsmtregs.h> 36#include <asm/mipsmtregs.h>
36#include <asm/cacheflush.h> 37#include <asm/mips_mt.h>
37#include <asm/mips-boards/maltaint.h> 38#include <asm/mips-boards/maltaint.h> /* This is f*cking wrong */
38 39
39#define MIPS_CPU_IPI_RESCHED_IRQ 0 40#define MIPS_CPU_IPI_RESCHED_IRQ 0
40#define MIPS_CPU_IPI_CALL_IRQ 1 41#define MIPS_CPU_IPI_CALL_IRQ 1
@@ -66,6 +67,7 @@ void __init sanitize_tlb_entries(void)
66 if (!cpu_has_mipsmt) 67 if (!cpu_has_mipsmt)
67 return; 68 return;
68 69
70 /* Enable VPC */
69 set_c0_mvpcontrol(MVPCONTROL_VPC); 71 set_c0_mvpcontrol(MVPCONTROL_VPC);
70 72
71 back_to_back_c0_hazard(); 73 back_to_back_c0_hazard();
@@ -106,12 +108,12 @@ void __init sanitize_tlb_entries(void)
106 108
107static void ipi_resched_dispatch (struct pt_regs *regs) 109static void ipi_resched_dispatch (struct pt_regs *regs)
108{ 110{
109 do_IRQ(MIPS_CPU_IPI_RESCHED_IRQ, regs); 111 do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ, regs);
110} 112}
111 113
112static void ipi_call_dispatch (struct pt_regs *regs) 114static void ipi_call_dispatch (struct pt_regs *regs)
113{ 115{
114 do_IRQ(MIPS_CPU_IPI_CALL_IRQ, regs); 116 do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ, regs);
115} 117}
116 118
117irqreturn_t ipi_resched_interrupt(int irq, void *dev_id, struct pt_regs *regs) 119irqreturn_t ipi_resched_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -148,6 +150,11 @@ void plat_smp_setup(void)
148 unsigned long val; 150 unsigned long val;
149 int i, num; 151 int i, num;
150 152
153#ifdef CONFIG_MIPS_MT_FPAFF
154 /* If we have an FPU, enroll ourselves in the FPU-full mask */
155 if (cpu_has_fpu)
156 cpu_set(0, mt_fpu_cpumask);
157#endif /* CONFIG_MIPS_MT_FPAFF */
151 if (!cpu_has_mipsmt) 158 if (!cpu_has_mipsmt)
152 return; 159 return;
153 160
@@ -155,6 +162,8 @@ void plat_smp_setup(void)
155 dvpe(); 162 dvpe();
156 dmt(); 163 dmt();
157 164
165 mips_mt_set_cpuoptions();
166
158 /* Put MVPE's into 'configuration state' */ 167 /* Put MVPE's into 'configuration state' */
159 set_c0_mvpcontrol(MVPCONTROL_VPC); 168 set_c0_mvpcontrol(MVPCONTROL_VPC);
160 169
@@ -189,11 +198,13 @@ void plat_smp_setup(void)
189 198
190 if (i != 0) { 199 if (i != 0) {
191 write_vpe_c0_status((read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); 200 write_vpe_c0_status((read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
192 write_vpe_c0_cause(read_vpe_c0_cause() & ~CAUSEF_IP);
193 201
194 /* set config to be the same as vpe0, particularly kseg0 coherency alg */ 202 /* set config to be the same as vpe0, particularly kseg0 coherency alg */
195 write_vpe_c0_config( read_c0_config()); 203 write_vpe_c0_config( read_c0_config());
196 204
205 /* make sure there are no software interrupts pending */
206 write_vpe_c0_cause(read_vpe_c0_cause() & ~(C_SW1|C_SW0));
207
197 /* Propagate Config7 */ 208 /* Propagate Config7 */
198 write_vpe_c0_config7(read_c0_config7()); 209 write_vpe_c0_config7(read_c0_config7());
199 } 210 }
@@ -233,16 +244,16 @@ void plat_smp_setup(void)
233 /* We'll wait until starting the secondaries before starting MVPE */ 244 /* We'll wait until starting the secondaries before starting MVPE */
234 245
235 printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); 246 printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
247}
236 248
249void __init plat_prepare_cpus(unsigned int max_cpus)
250{
237 /* set up ipi interrupts */ 251 /* set up ipi interrupts */
238 if (cpu_has_vint) { 252 if (cpu_has_vint) {
239 set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); 253 set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
240 set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); 254 set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
241 } 255 }
242}
243 256
244void __init plat_prepare_cpus(unsigned int max_cpus)
245{
246 cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ; 257 cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
247 cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ; 258 cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ;
248 259
@@ -287,7 +298,8 @@ void prom_boot_secondary(int cpu, struct task_struct *idle)
287 /* global pointer */ 298 /* global pointer */
288 write_tc_gpr_gp((unsigned long)gp); 299 write_tc_gpr_gp((unsigned long)gp);
289 300
290 flush_icache_range((unsigned long)gp, (unsigned long)(gp + 1)); 301 flush_icache_range((unsigned long)gp,
302 (unsigned long)(gp + sizeof(struct thread_info)));
291 303
292 /* finally out of configuration and into chaos */ 304 /* finally out of configuration and into chaos */
293 clear_c0_mvpcontrol(MVPCONTROL_VPC); 305 clear_c0_mvpcontrol(MVPCONTROL_VPC);
@@ -305,6 +317,12 @@ void prom_smp_finish(void)
305{ 317{
306 write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ)); 318 write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
307 319
320#ifdef CONFIG_MIPS_MT_FPAFF
321 /* If we have an FPU, enroll ourselves in the FPU-full mask */
322 if (cpu_has_fpu)
323 cpu_set(smp_processor_id(), mt_fpu_cpumask);
324#endif /* CONFIG_MIPS_MT_FPAFF */
325
308 local_irq_enable(); 326 local_irq_enable();
309} 327}
310 328
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 78d171bfa331..d42f358754ad 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -38,6 +38,10 @@
38#include <asm/mmu_context.h> 38#include <asm/mmu_context.h>
39#include <asm/smp.h> 39#include <asm/smp.h>
40 40
41#ifdef CONFIG_MIPS_MT_SMTC
42#include <asm/mipsmtregs.h>
43#endif /* CONFIG_MIPS_MT_SMTC */
44
41cpumask_t phys_cpu_present_map; /* Bitmask of available CPUs */ 45cpumask_t phys_cpu_present_map; /* Bitmask of available CPUs */
42volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ 46volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */
43cpumask_t cpu_online_map; /* Bitmask of currently online CPUs */ 47cpumask_t cpu_online_map; /* Bitmask of currently online CPUs */
@@ -85,6 +89,10 @@ asmlinkage void start_secondary(void)
85{ 89{
86 unsigned int cpu; 90 unsigned int cpu;
87 91
92#ifdef CONFIG_MIPS_MT_SMTC
93 /* Only do cpu_probe for first TC of CPU */
94 if ((read_c0_tcbind() & TCBIND_CURTC) == 0)
95#endif /* CONFIG_MIPS_MT_SMTC */
88 cpu_probe(); 96 cpu_probe();
89 cpu_report(); 97 cpu_report();
90 per_cpu_trap_init(); 98 per_cpu_trap_init();
@@ -179,11 +187,13 @@ int smp_call_function (void (*func) (void *info), void *info, int retry,
179 if (wait) 187 if (wait)
180 while (atomic_read(&data.finished) != cpus) 188 while (atomic_read(&data.finished) != cpus)
181 barrier(); 189 barrier();
190 call_data = NULL;
182 spin_unlock(&smp_call_lock); 191 spin_unlock(&smp_call_lock);
183 192
184 return 0; 193 return 0;
185} 194}
186 195
196
187void smp_call_function_interrupt(void) 197void smp_call_function_interrupt(void)
188{ 198{
189 void (*func) (void *info) = call_data->func; 199 void (*func) (void *info) = call_data->func;
@@ -446,5 +456,3 @@ subsys_initcall(topology_init);
446 456
447EXPORT_SYMBOL(flush_tlb_page); 457EXPORT_SYMBOL(flush_tlb_page);
448EXPORT_SYMBOL(flush_tlb_one); 458EXPORT_SYMBOL(flush_tlb_one);
449EXPORT_SYMBOL(cpu_data);
450EXPORT_SYMBOL(synchronize_irq);
diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S
new file mode 100644
index 000000000000..c9d65196d917
--- /dev/null
+++ b/arch/mips/kernel/smtc-asm.S
@@ -0,0 +1,130 @@
1/*
2 * Assembly Language Functions for MIPS MT SMTC support
3 */
4
5/*
6 * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. */
7
8#include <asm/regdef.h>
9#include <asm/asmmacro.h>
10#include <asm/stackframe.h>
11#include <asm/stackframe.h>
12
13/*
14 * "Software Interrupt" linkage.
15 *
16 * This is invoked when an "Interrupt" is sent from one TC to another,
17 * where the TC to be interrupted is halted, has it's Restart address
18 * and Status values saved by the "remote control" thread, then modified
19 * to cause execution to begin here, in kenel mode. This code then
20 * disguises the TC state as that of an exception and transfers
21 * control to the general exception or vectored interrupt handler.
22 */
23 .set noreorder
24
25/*
26The __smtc_ipi_vector would use k0 and k1 as temporaries and
271) Set EXL (this is per-VPE, so this can't be done by proxy!)
282) Restore the K/CU and IXMT bits to the pre "exception" state
29 (EXL means no interrupts and access to the kernel map).
303) Set EPC to be the saved value of TCRestart.
314) Jump to the exception handler entry point passed by the sender.
32
33CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED??
34*/
35
36/*
37 * Reviled and slandered vision: Set EXL and restore K/CU/IXMT
38 * state of pre-halt thread, then save everything and call
39 * thought some function pointer to imaginary_exception, which
40 * will parse a register value or memory message queue to
41 * deliver things like interprocessor interrupts. On return
42 * from that function, jump to the global ret_from_irq code
43 * to invoke the scheduler and return as appropriate.
44 */
45
46#define PT_PADSLOT4 (PT_R0-8)
47#define PT_PADSLOT5 (PT_R0-4)
48
49 .text
50 .align 5
51FEXPORT(__smtc_ipi_vector)
52 .set noat
53 /* Disable thread scheduling to make Status update atomic */
54 DMT 27 # dmt k1
55 ehb
56 /* Set EXL */
57 mfc0 k0,CP0_STATUS
58 ori k0,k0,ST0_EXL
59 mtc0 k0,CP0_STATUS
60 ehb
61 /* Thread scheduling now inhibited by EXL. Restore TE state. */
62 andi k1,k1,VPECONTROL_TE
63 beqz k1,1f
64 emt
651:
66 /*
67 * The IPI sender has put some information on the anticipated
68 * kernel stack frame. If we were in user mode, this will be
69 * built above the saved kernel SP. If we were already in the
70 * kernel, it will be built above the current CPU SP.
71 *
72 * Were we in kernel mode, as indicated by CU0?
73 */
74 sll k1,k0,3
75 .set noreorder
76 bltz k1,2f
77 move k1,sp
78 .set reorder
79 /*
80 * If previously in user mode, set CU0 and use kernel stack.
81 */
82 li k1,ST0_CU0
83 or k1,k1,k0
84 mtc0 k1,CP0_STATUS
85 ehb
86 get_saved_sp
87 /* Interrupting TC will have pre-set values in slots in the new frame */
882: subu k1,k1,PT_SIZE
89 /* Load TCStatus Value */
90 lw k0,PT_TCSTATUS(k1)
91 /* Write it to TCStatus to restore CU/KSU/IXMT state */
92 mtc0 k0,$2,1
93 ehb
94 lw k0,PT_EPC(k1)
95 mtc0 k0,CP0_EPC
96 /* Save all will redundantly recompute the SP, but use it for now */
97 SAVE_ALL
98 CLI
99 move a0,sp
100 /* Function to be invoked passed stack pad slot 5 */
101 lw t0,PT_PADSLOT5(sp)
102 /* Argument from sender passed in stack pad slot 4 */
103 lw a1,PT_PADSLOT4(sp)
104 jalr t0
105 nop
106 j ret_from_irq
107 nop
108
109/*
110 * Called from idle loop to provoke processing of queued IPIs
111 * First IPI message in queue passed as argument.
112 */
113
114LEAF(self_ipi)
115 /* Before anything else, block interrupts */
116 mfc0 t0,CP0_TCSTATUS
117 ori t1,t0,TCSTATUS_IXMT
118 mtc0 t1,CP0_TCSTATUS
119 ehb
120 /* We know we're in kernel mode, so prepare stack frame */
121 subu t1,sp,PT_SIZE
122 sw ra,PT_EPC(t1)
123 sw a0,PT_PADSLOT4(t1)
124 la t2,ipi_decode
125 sw t2,PT_PADSLOT5(t1)
126 /* Save pre-disable value of TCStatus */
127 sw t0,PT_TCSTATUS(t1)
128 j __smtc_ipi_vector
129 nop
130END(self_ipi)
diff --git a/arch/mips/kernel/smtc-proc.c b/arch/mips/kernel/smtc-proc.c
new file mode 100644
index 000000000000..6f3709996172
--- /dev/null
+++ b/arch/mips/kernel/smtc-proc.c
@@ -0,0 +1,93 @@
1/*
2 * /proc hooks for SMTC kernel
3 * Copyright (C) 2005 Mips Technologies, Inc
4 */
5
6#include <linux/kernel.h>
7#include <linux/sched.h>
8#include <linux/cpumask.h>
9#include <linux/interrupt.h>
10
11#include <asm/cpu.h>
12#include <asm/processor.h>
13#include <asm/atomic.h>
14#include <asm/system.h>
15#include <asm/hardirq.h>
16#include <asm/mmu_context.h>
17#include <asm/smp.h>
18#include <asm/mipsregs.h>
19#include <asm/cacheflush.h>
20#include <linux/proc_fs.h>
21
22#include <asm/smtc_proc.h>
23
24/*
25 * /proc diagnostic and statistics hooks
26 */
27
28/*
29 * Statistics gathered
30 */
31unsigned long selfipis[NR_CPUS];
32
33struct smtc_cpu_proc smtc_cpu_stats[NR_CPUS];
34
35static struct proc_dir_entry *smtc_stats;
36
37atomic_t smtc_fpu_recoveries;
38
39static int proc_read_smtc(char *page, char **start, off_t off,
40 int count, int *eof, void *data)
41{
42 int totalen = 0;
43 int len;
44 int i;
45 extern unsigned long ebase;
46
47 len = sprintf(page, "SMTC Status Word: 0x%08x\n", smtc_status);
48 totalen += len;
49 page += len;
50 len = sprintf(page, "Config7: 0x%08x\n", read_c0_config7());
51 totalen += len;
52 page += len;
53 len = sprintf(page, "EBASE: 0x%08lx\n", ebase);
54 totalen += len;
55 page += len;
56 len = sprintf(page, "Counter Interrupts taken per CPU (TC)\n");
57 totalen += len;
58 page += len;
59 for (i=0; i < NR_CPUS; i++) {
60 len = sprintf(page, "%d: %ld\n", i, smtc_cpu_stats[i].timerints);
61 totalen += len;
62 page += len;
63 }
64 len = sprintf(page, "Self-IPIs by CPU:\n");
65 totalen += len;
66 page += len;
67 for(i = 0; i < NR_CPUS; i++) {
68 len = sprintf(page, "%d: %ld\n", i, smtc_cpu_stats[i].selfipis);
69 totalen += len;
70 page += len;
71 }
72 len = sprintf(page, "%d Recoveries of \"stolen\" FPU\n",
73 atomic_read(&smtc_fpu_recoveries));
74 totalen += len;
75 page += len;
76
77 return totalen;
78}
79
80void init_smtc_stats(void)
81{
82 int i;
83
84 for (i=0; i<NR_CPUS; i++) {
85 smtc_cpu_stats[i].timerints = 0;
86 smtc_cpu_stats[i].selfipis = 0;
87 }
88
89 atomic_set(&smtc_fpu_recoveries, 0);
90
91 smtc_stats = create_proc_read_entry("smtc", 0444, NULL,
92 proc_read_smtc, NULL);
93}
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
new file mode 100644
index 000000000000..2e8e52c135e6
--- /dev/null
+++ b/arch/mips/kernel/smtc.c
@@ -0,0 +1,1322 @@
1/* Copyright (C) 2004 Mips Technologies, Inc */
2
3#include <linux/kernel.h>
4#include <linux/sched.h>
5#include <linux/cpumask.h>
6#include <linux/interrupt.h>
7
8#include <asm/cpu.h>
9#include <asm/processor.h>
10#include <asm/atomic.h>
11#include <asm/system.h>
12#include <asm/hardirq.h>
13#include <asm/hazards.h>
14#include <asm/mmu_context.h>
15#include <asm/smp.h>
16#include <asm/mipsregs.h>
17#include <asm/cacheflush.h>
18#include <asm/time.h>
19#include <asm/addrspace.h>
20#include <asm/smtc.h>
21#include <asm/smtc_ipi.h>
22#include <asm/smtc_proc.h>
23
24/*
25 * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set.
26 */
27
28/*
29 * MIPSCPU_INT_BASE is identically defined in both
30 * asm-mips/mips-boards/maltaint.h and asm-mips/mips-boards/simint.h,
31 * but as yet there's no properly organized include structure that
32 * will ensure that the right *int.h file will be included for a
33 * given platform build.
34 */
35
36#define MIPSCPU_INT_BASE 16
37
38#define MIPS_CPU_IPI_IRQ 1
39
40#define LOCK_MT_PRA() \
41 local_irq_save(flags); \
42 mtflags = dmt()
43
44#define UNLOCK_MT_PRA() \
45 emt(mtflags); \
46 local_irq_restore(flags)
47
48#define LOCK_CORE_PRA() \
49 local_irq_save(flags); \
50 mtflags = dvpe()
51
52#define UNLOCK_CORE_PRA() \
53 evpe(mtflags); \
54 local_irq_restore(flags)
55
56/*
57 * Data structures purely associated with SMTC parallelism
58 */
59
60
61/*
62 * Table for tracking ASIDs whose lifetime is prolonged.
63 */
64
65asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];
66
67/*
68 * Clock interrupt "latch" buffers, per "CPU"
69 */
70
71unsigned int ipi_timer_latch[NR_CPUS];
72
73/*
74 * Number of InterProcessor Interupt (IPI) message buffers to allocate
75 */
76
77#define IPIBUF_PER_CPU 4
78
79struct smtc_ipi_q IPIQ[NR_CPUS];
80struct smtc_ipi_q freeIPIq;
81
82
83/* Forward declarations */
84
85void ipi_decode(struct pt_regs *, struct smtc_ipi *);
86void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
87void setup_cross_vpe_interrupts(void);
88void init_smtc_stats(void);
89
90/* Global SMTC Status */
91
92unsigned int smtc_status = 0;
93
94/* Boot command line configuration overrides */
95
96static int vpelimit = 0;
97static int tclimit = 0;
98static int ipibuffers = 0;
99static int nostlb = 0;
100static int asidmask = 0;
101unsigned long smtc_asid_mask = 0xff;
102
103static int __init maxvpes(char *str)
104{
105 get_option(&str, &vpelimit);
106 return 1;
107}
108
109static int __init maxtcs(char *str)
110{
111 get_option(&str, &tclimit);
112 return 1;
113}
114
115static int __init ipibufs(char *str)
116{
117 get_option(&str, &ipibuffers);
118 return 1;
119}
120
121static int __init stlb_disable(char *s)
122{
123 nostlb = 1;
124 return 1;
125}
126
127static int __init asidmask_set(char *str)
128{
129 get_option(&str, &asidmask);
130 switch(asidmask) {
131 case 0x1:
132 case 0x3:
133 case 0x7:
134 case 0xf:
135 case 0x1f:
136 case 0x3f:
137 case 0x7f:
138 case 0xff:
139 smtc_asid_mask = (unsigned long)asidmask;
140 break;
141 default:
142 printk("ILLEGAL ASID mask 0x%x from command line\n", asidmask);
143 }
144 return 1;
145}
146
147__setup("maxvpes=", maxvpes);
148__setup("maxtcs=", maxtcs);
149__setup("ipibufs=", ipibufs);
150__setup("nostlb", stlb_disable);
151__setup("asidmask=", asidmask_set);
152
153/* Enable additional debug checks before going into CPU idle loop */
154#define SMTC_IDLE_HOOK_DEBUG
155
156#ifdef SMTC_IDLE_HOOK_DEBUG
157
158static int hang_trig = 0;
159
160static int __init hangtrig_enable(char *s)
161{
162 hang_trig = 1;
163 return 1;
164}
165
166
167__setup("hangtrig", hangtrig_enable);
168
169#define DEFAULT_BLOCKED_IPI_LIMIT 32
170
171static int timerq_limit = DEFAULT_BLOCKED_IPI_LIMIT;
172
173static int __init tintq(char *str)
174{
175 get_option(&str, &timerq_limit);
176 return 1;
177}
178
179__setup("tintq=", tintq);
180
181int imstuckcount[2][8];
182/* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */
183int vpemask[2][8] = {{0,1,1,0,0,0,0,1},{0,1,0,0,0,0,0,1}};
184int tcnoprog[NR_CPUS];
185static atomic_t idle_hook_initialized = {0};
186static int clock_hang_reported[NR_CPUS];
187
188#endif /* SMTC_IDLE_HOOK_DEBUG */
189
190/* Initialize shared TLB - the should probably migrate to smtc_setup_cpus() */
191
192void __init sanitize_tlb_entries(void)
193{
194 printk("Deprecated sanitize_tlb_entries() invoked\n");
195}
196
197
198/*
199 * Configure shared TLB - VPC configuration bit must be set by caller
200 */
201
202void smtc_configure_tlb(void)
203{
204 int i,tlbsiz,vpes;
205 unsigned long mvpconf0;
206 unsigned long config1val;
207
208 /* Set up ASID preservation table */
209 for (vpes=0; vpes<MAX_SMTC_TLBS; vpes++) {
210 for(i = 0; i < MAX_SMTC_ASIDS; i++) {
211 smtc_live_asid[vpes][i] = 0;
212 }
213 }
214 mvpconf0 = read_c0_mvpconf0();
215
216 if ((vpes = ((mvpconf0 & MVPCONF0_PVPE)
217 >> MVPCONF0_PVPE_SHIFT) + 1) > 1) {
218 /* If we have multiple VPEs, try to share the TLB */
219 if ((mvpconf0 & MVPCONF0_TLBS) && !nostlb) {
220 /*
221 * If TLB sizing is programmable, shared TLB
222 * size is the total available complement.
223 * Otherwise, we have to take the sum of all
224 * static VPE TLB entries.
225 */
226 if ((tlbsiz = ((mvpconf0 & MVPCONF0_PTLBE)
227 >> MVPCONF0_PTLBE_SHIFT)) == 0) {
228 /*
229 * If there's more than one VPE, there had better
230 * be more than one TC, because we need one to bind
231 * to each VPE in turn to be able to read
232 * its configuration state!
233 */
234 settc(1);
235 /* Stop the TC from doing anything foolish */
236 write_tc_c0_tchalt(TCHALT_H);
237 mips_ihb();
238 /* No need to un-Halt - that happens later anyway */
239 for (i=0; i < vpes; i++) {
240 write_tc_c0_tcbind(i);
241 /*
242 * To be 100% sure we're really getting the right
243 * information, we exit the configuration state
244 * and do an IHB after each rebinding.
245 */
246 write_c0_mvpcontrol(
247 read_c0_mvpcontrol() & ~ MVPCONTROL_VPC );
248 mips_ihb();
249 /*
250 * Only count if the MMU Type indicated is TLB
251 */
252 if(((read_vpe_c0_config() & MIPS_CONF_MT) >> 7) == 1) {
253 config1val = read_vpe_c0_config1();
254 tlbsiz += ((config1val >> 25) & 0x3f) + 1;
255 }
256
257 /* Put core back in configuration state */
258 write_c0_mvpcontrol(
259 read_c0_mvpcontrol() | MVPCONTROL_VPC );
260 mips_ihb();
261 }
262 }
263 write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB);
264
265 /*
266 * Setup kernel data structures to use software total,
267 * rather than read the per-VPE Config1 value. The values
268 * for "CPU 0" gets copied to all the other CPUs as part
269 * of their initialization in smtc_cpu_setup().
270 */
271
272 tlbsiz = tlbsiz & 0x3f; /* MIPS32 limits TLB indices to 64 */
273 cpu_data[0].tlbsize = tlbsiz;
274 smtc_status |= SMTC_TLB_SHARED;
275
276 printk("TLB of %d entry pairs shared by %d VPEs\n",
277 tlbsiz, vpes);
278 } else {
279 printk("WARNING: TLB Not Sharable on SMTC Boot!\n");
280 }
281 }
282}
283
284
285/*
286 * Incrementally build the CPU map out of constituent MIPS MT cores,
287 * using the specified available VPEs and TCs. Plaform code needs
288 * to ensure that each MIPS MT core invokes this routine on reset,
289 * one at a time(!).
290 *
291 * This version of the build_cpu_map and prepare_cpus routines assumes
292 * that *all* TCs of a MIPS MT core will be used for Linux, and that
293 * they will be spread across *all* available VPEs (to minimise the
294 * loss of efficiency due to exception service serialization).
295 * An improved version would pick up configuration information and
296 * possibly leave some TCs/VPEs as "slave" processors.
297 *
298 * Use c0_MVPConf0 to find out how many TCs are available, setting up
299 * phys_cpu_present_map and the logical/physical mappings.
300 */
301
302int __init mipsmt_build_cpu_map(int start_cpu_slot)
303{
304 int i, ntcs;
305
306 /*
307 * The CPU map isn't actually used for anything at this point,
308 * so it's not clear what else we should do apart from set
309 * everything up so that "logical" = "physical".
310 */
311 ntcs = ((read_c0_mvpconf0() & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
312 for (i=start_cpu_slot; i<NR_CPUS && i<ntcs; i++) {
313 cpu_set(i, phys_cpu_present_map);
314 __cpu_number_map[i] = i;
315 __cpu_logical_map[i] = i;
316 }
317 /* Initialize map of CPUs with FPUs */
318 cpus_clear(mt_fpu_cpumask);
319
320 /* One of those TC's is the one booting, and not a secondary... */
321 printk("%i available secondary CPU TC(s)\n", i - 1);
322
323 return i;
324}
325
326/*
327 * Common setup before any secondaries are started
328 * Make sure all CPU's are in a sensible state before we boot any of the
329 * secondaries.
330 *
331 * For MIPS MT "SMTC" operation, we set up all TCs, spread as evenly
332 * as possible across the available VPEs.
333 */
334
335static void smtc_tc_setup(int vpe, int tc, int cpu)
336{
337 settc(tc);
338 write_tc_c0_tchalt(TCHALT_H);
339 mips_ihb();
340 write_tc_c0_tcstatus((read_tc_c0_tcstatus()
341 & ~(TCSTATUS_TKSU | TCSTATUS_DA | TCSTATUS_IXMT))
342 | TCSTATUS_A);
343 write_tc_c0_tccontext(0);
344 /* Bind tc to vpe */
345 write_tc_c0_tcbind(vpe);
346 /* In general, all TCs should have the same cpu_data indications */
347 memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips));
348 /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */
349 if (cpu_data[0].cputype == CPU_34K)
350 cpu_data[cpu].options &= ~MIPS_CPU_FPU;
351 cpu_data[cpu].vpe_id = vpe;
352 cpu_data[cpu].tc_id = tc;
353}
354
355
356void mipsmt_prepare_cpus(void)
357{
358 int i, vpe, tc, ntc, nvpe, tcpervpe, slop, cpu;
359 unsigned long flags;
360 unsigned long val;
361 int nipi;
362 struct smtc_ipi *pipi;
363
364 /* disable interrupts so we can disable MT */
365 local_irq_save(flags);
366 /* disable MT so we can configure */
367 dvpe();
368 dmt();
369
370 freeIPIq.lock = SPIN_LOCK_UNLOCKED;
371
372 /*
373 * We probably don't have as many VPEs as we do SMP "CPUs",
374 * but it's possible - and in any case we'll never use more!
375 */
376 for (i=0; i<NR_CPUS; i++) {
377 IPIQ[i].head = IPIQ[i].tail = NULL;
378 IPIQ[i].lock = SPIN_LOCK_UNLOCKED;
379 IPIQ[i].depth = 0;
380 ipi_timer_latch[i] = 0;
381 }
382
383 /* cpu_data index starts at zero */
384 cpu = 0;
385 cpu_data[cpu].vpe_id = 0;
386 cpu_data[cpu].tc_id = 0;
387 cpu++;
388
389 /* Report on boot-time options */
390 mips_mt_set_cpuoptions ();
391 if (vpelimit > 0)
392 printk("Limit of %d VPEs set\n", vpelimit);
393 if (tclimit > 0)
394 printk("Limit of %d TCs set\n", tclimit);
395 if (nostlb) {
396 printk("Shared TLB Use Inhibited - UNSAFE for Multi-VPE Operation\n");
397 }
398 if (asidmask)
399 printk("ASID mask value override to 0x%x\n", asidmask);
400
401 /* Temporary */
402#ifdef SMTC_IDLE_HOOK_DEBUG
403 if (hang_trig)
404 printk("Logic Analyser Trigger on suspected TC hang\n");
405#endif /* SMTC_IDLE_HOOK_DEBUG */
406
407 /* Put MVPE's into 'configuration state' */
408 write_c0_mvpcontrol( read_c0_mvpcontrol() | MVPCONTROL_VPC );
409
410 val = read_c0_mvpconf0();
411 nvpe = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
412 if (vpelimit > 0 && nvpe > vpelimit)
413 nvpe = vpelimit;
414 ntc = ((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
415 if (ntc > NR_CPUS)
416 ntc = NR_CPUS;
417 if (tclimit > 0 && ntc > tclimit)
418 ntc = tclimit;
419 tcpervpe = ntc / nvpe;
420 slop = ntc % nvpe; /* Residual TCs, < NVPE */
421
422 /* Set up shared TLB */
423 smtc_configure_tlb();
424
425 for (tc = 0, vpe = 0 ; (vpe < nvpe) && (tc < ntc) ; vpe++) {
426 /*
427 * Set the MVP bits.
428 */
429 settc(tc);
430 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_MVP);
431 if (vpe != 0)
432 printk(", ");
433 printk("VPE %d: TC", vpe);
434 for (i = 0; i < tcpervpe; i++) {
435 /*
436 * TC 0 is bound to VPE 0 at reset,
437 * and is presumably executing this
438 * code. Leave it alone!
439 */
440 if (tc != 0) {
441 smtc_tc_setup(vpe,tc, cpu);
442 cpu++;
443 }
444 printk(" %d", tc);
445 tc++;
446 }
447 if (slop) {
448 if (tc != 0) {
449 smtc_tc_setup(vpe,tc, cpu);
450 cpu++;
451 }
452 printk(" %d", tc);
453 tc++;
454 slop--;
455 }
456 if (vpe != 0) {
457 /*
458 * Clear any stale software interrupts from VPE's Cause
459 */
460 write_vpe_c0_cause(0);
461
462 /*
463 * Clear ERL/EXL of VPEs other than 0
464 * and set restricted interrupt enable/mask.
465 */
466 write_vpe_c0_status((read_vpe_c0_status()
467 & ~(ST0_BEV | ST0_ERL | ST0_EXL | ST0_IM))
468 | (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP7
469 | ST0_IE));
470 /*
471 * set config to be the same as vpe0,
472 * particularly kseg0 coherency alg
473 */
474 write_vpe_c0_config(read_c0_config());
475 /* Clear any pending timer interrupt */
476 write_vpe_c0_compare(0);
477 /* Propagate Config7 */
478 write_vpe_c0_config7(read_c0_config7());
479 }
480 /* enable multi-threading within VPE */
481 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() | VPECONTROL_TE);
482 /* enable the VPE */
483 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
484 }
485
486 /*
487 * Pull any physically present but unused TCs out of circulation.
488 */
489 while (tc < (((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1)) {
490 cpu_clear(tc, phys_cpu_present_map);
491 cpu_clear(tc, cpu_present_map);
492 tc++;
493 }
494
495 /* release config state */
496 write_c0_mvpcontrol( read_c0_mvpcontrol() & ~ MVPCONTROL_VPC );
497
498 printk("\n");
499
500 /* Set up coprocessor affinity CPU mask(s) */
501
502 for (tc = 0; tc < ntc; tc++) {
503 if(cpu_data[tc].options & MIPS_CPU_FPU)
504 cpu_set(tc, mt_fpu_cpumask);
505 }
506
507 /* set up ipi interrupts... */
508
509 /* If we have multiple VPEs running, set up the cross-VPE interrupt */
510
511 if (nvpe > 1)
512 setup_cross_vpe_interrupts();
513
514 /* Set up queue of free IPI "messages". */
515 nipi = NR_CPUS * IPIBUF_PER_CPU;
516 if (ipibuffers > 0)
517 nipi = ipibuffers;
518
519 pipi = kmalloc(nipi *sizeof(struct smtc_ipi), GFP_KERNEL);
520 if (pipi == NULL)
521 panic("kmalloc of IPI message buffers failed\n");
522 else
523 printk("IPI buffer pool of %d buffers\n", nipi);
524 for (i = 0; i < nipi; i++) {
525 smtc_ipi_nq(&freeIPIq, pipi);
526 pipi++;
527 }
528
529 /* Arm multithreading and enable other VPEs - but all TCs are Halted */
530 emt(EMT_ENABLE);
531 evpe(EVPE_ENABLE);
532 local_irq_restore(flags);
533 /* Initialize SMTC /proc statistics/diagnostics */
534 init_smtc_stats();
535}
536
537
538/*
539 * Setup the PC, SP, and GP of a secondary processor and start it
540 * running!
541 * smp_bootstrap is the place to resume from
542 * __KSTK_TOS(idle) is apparently the stack pointer
543 * (unsigned long)idle->thread_info the gp
544 *
545 */
546void smtc_boot_secondary(int cpu, struct task_struct *idle)
547{
548 extern u32 kernelsp[NR_CPUS];
549 long flags;
550 int mtflags;
551
552 LOCK_MT_PRA();
553 if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
554 dvpe();
555 }
556 settc(cpu_data[cpu].tc_id);
557
558 /* pc */
559 write_tc_c0_tcrestart((unsigned long)&smp_bootstrap);
560
561 /* stack pointer */
562 kernelsp[cpu] = __KSTK_TOS(idle);
563 write_tc_gpr_sp(__KSTK_TOS(idle));
564
565 /* global pointer */
566 write_tc_gpr_gp((unsigned long)idle->thread_info);
567
568 smtc_status |= SMTC_MTC_ACTIVE;
569 write_tc_c0_tchalt(0);
570 if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
571 evpe(EVPE_ENABLE);
572 }
573 UNLOCK_MT_PRA();
574}
575
576void smtc_init_secondary(void)
577{
578 /*
579 * Start timer on secondary VPEs if necessary.
580 * mips_timer_setup should already have been invoked by init/main
581 * on "boot" TC. Like per_cpu_trap_init() hack, this assumes that
582 * SMTC init code assigns TCs consdecutively and in ascending order
583 * to across available VPEs.
584 */
585 if(((read_c0_tcbind() & TCBIND_CURTC) != 0)
586 && ((read_c0_tcbind() & TCBIND_CURVPE)
587 != cpu_data[smp_processor_id() - 1].vpe_id)){
588 write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ);
589 }
590
591 local_irq_enable();
592}
593
594void smtc_smp_finish(void)
595{
596 printk("TC %d going on-line as CPU %d\n",
597 cpu_data[smp_processor_id()].tc_id, smp_processor_id());
598}
599
600void smtc_cpus_done(void)
601{
602}
603
604/*
605 * Support for SMTC-optimized driver IRQ registration
606 */
607
608/*
609 * SMTC Kernel needs to manipulate low-level CPU interrupt mask
610 * in do_IRQ. These are passed in setup_irq_smtc() and stored
611 * in this table.
612 */
613
614int setup_irq_smtc(unsigned int irq, struct irqaction * new,
615 unsigned long hwmask)
616{
617 irq_hwmask[irq] = hwmask;
618
619 return setup_irq(irq, new);
620}
621
622/*
623 * IPI model for SMTC is tricky, because interrupts aren't TC-specific.
624 * Within a VPE one TC can interrupt another by different approaches.
625 * The easiest to get right would probably be to make all TCs except
626 * the target IXMT and set a software interrupt, but an IXMT-based
627 * scheme requires that a handler must run before a new IPI could
628 * be sent, which would break the "broadcast" loops in MIPS MT.
629 * A more gonzo approach within a VPE is to halt the TC, extract
630 * its Restart, Status, and a couple of GPRs, and program the Restart
631 * address to emulate an interrupt.
632 *
633 * Within a VPE, one can be confident that the target TC isn't in
634 * a critical EXL state when halted, since the write to the Halt
635 * register could not have issued on the writing thread if the
636 * halting thread had EXL set. So k0 and k1 of the target TC
637 * can be used by the injection code. Across VPEs, one can't
638 * be certain that the target TC isn't in a critical exception
639 * state. So we try a two-step process of sending a software
640 * interrupt to the target VPE, which either handles the event
641 * itself (if it was the target) or injects the event within
642 * the VPE.
643 */
644
645void smtc_ipi_qdump(void)
646{
647 int i;
648
649 for (i = 0; i < NR_CPUS ;i++) {
650 printk("IPIQ[%d]: head = 0x%x, tail = 0x%x, depth = %d\n",
651 i, (unsigned)IPIQ[i].head, (unsigned)IPIQ[i].tail,
652 IPIQ[i].depth);
653 }
654}
655
656/*
657 * The standard atomic.h primitives don't quite do what we want
658 * here: We need an atomic add-and-return-previous-value (which
659 * could be done with atomic_add_return and a decrement) and an
660 * atomic set/zero-and-return-previous-value (which can't really
661 * be done with the atomic.h primitives). And since this is
662 * MIPS MT, we can assume that we have LL/SC.
663 */
664static __inline__ int atomic_postincrement(unsigned int *pv)
665{
666 unsigned long result;
667
668 unsigned long temp;
669
670 __asm__ __volatile__(
671 "1: ll %0, %2 \n"
672 " addu %1, %0, 1 \n"
673 " sc %1, %2 \n"
674 " beqz %1, 1b \n"
675 " sync \n"
676 : "=&r" (result), "=&r" (temp), "=m" (*pv)
677 : "m" (*pv)
678 : "memory");
679
680 return result;
681}
682
683/* No longer used in IPI dispatch, but retained for future recycling */
684
685static __inline__ int atomic_postclear(unsigned int *pv)
686{
687 unsigned long result;
688
689 unsigned long temp;
690
691 __asm__ __volatile__(
692 "1: ll %0, %2 \n"
693 " or %1, $0, $0 \n"
694 " sc %1, %2 \n"
695 " beqz %1, 1b \n"
696 " sync \n"
697 : "=&r" (result), "=&r" (temp), "=m" (*pv)
698 : "m" (*pv)
699 : "memory");
700
701 return result;
702}
703
704
705void smtc_send_ipi(int cpu, int type, unsigned int action)
706{
707 int tcstatus;
708 struct smtc_ipi *pipi;
709 long flags;
710 int mtflags;
711
712 if (cpu == smp_processor_id()) {
713 printk("Cannot Send IPI to self!\n");
714 return;
715 }
716 /* Set up a descriptor, to be delivered either promptly or queued */
717 pipi = smtc_ipi_dq(&freeIPIq);
718 if (pipi == NULL) {
719 bust_spinlocks(1);
720 mips_mt_regdump(dvpe());
721 panic("IPI Msg. Buffers Depleted\n");
722 }
723 pipi->type = type;
724 pipi->arg = (void *)action;
725 pipi->dest = cpu;
726 if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
727 /* If not on same VPE, enqueue and send cross-VPE interupt */
728 smtc_ipi_nq(&IPIQ[cpu], pipi);
729 LOCK_CORE_PRA();
730 settc(cpu_data[cpu].tc_id);
731 write_vpe_c0_cause(read_vpe_c0_cause() | C_SW1);
732 UNLOCK_CORE_PRA();
733 } else {
734 /*
735 * Not sufficient to do a LOCK_MT_PRA (dmt) here,
736 * since ASID shootdown on the other VPE may
737 * collide with this operation.
738 */
739 LOCK_CORE_PRA();
740 settc(cpu_data[cpu].tc_id);
741 /* Halt the targeted TC */
742 write_tc_c0_tchalt(TCHALT_H);
743 mips_ihb();
744
745 /*
746 * Inspect TCStatus - if IXMT is set, we have to queue
747 * a message. Otherwise, we set up the "interrupt"
748 * of the other TC
749 */
750 tcstatus = read_tc_c0_tcstatus();
751
752 if ((tcstatus & TCSTATUS_IXMT) != 0) {
753 /*
754 * Spin-waiting here can deadlock,
755 * so we queue the message for the target TC.
756 */
757 write_tc_c0_tchalt(0);
758 UNLOCK_CORE_PRA();
759 /* Try to reduce redundant timer interrupt messages */
760 if(type == SMTC_CLOCK_TICK) {
761 if(atomic_postincrement(&ipi_timer_latch[cpu])!=0) {
762 smtc_ipi_nq(&freeIPIq, pipi);
763 return;
764 }
765 }
766 smtc_ipi_nq(&IPIQ[cpu], pipi);
767 } else {
768 post_direct_ipi(cpu, pipi);
769 write_tc_c0_tchalt(0);
770 UNLOCK_CORE_PRA();
771 }
772 }
773}
774
775/*
776 * Send IPI message to Halted TC, TargTC/TargVPE already having been set
777 */
778void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
779{
780 struct pt_regs *kstack;
781 unsigned long tcstatus;
782 unsigned long tcrestart;
783 extern u32 kernelsp[NR_CPUS];
784 extern void __smtc_ipi_vector(void);
785
786 /* Extract Status, EPC from halted TC */
787 tcstatus = read_tc_c0_tcstatus();
788 tcrestart = read_tc_c0_tcrestart();
789 /* If TCRestart indicates a WAIT instruction, advance the PC */
790 if ((tcrestart & 0x80000000)
791 && ((*(unsigned int *)tcrestart & 0xfe00003f) == 0x42000020)) {
792 tcrestart += 4;
793 }
794 /*
795 * Save on TC's future kernel stack
796 *
797 * CU bit of Status is indicator that TC was
798 * already running on a kernel stack...
799 */
800 if(tcstatus & ST0_CU0) {
801 /* Note that this "- 1" is pointer arithmetic */
802 kstack = ((struct pt_regs *)read_tc_gpr_sp()) - 1;
803 } else {
804 kstack = ((struct pt_regs *)kernelsp[cpu]) - 1;
805 }
806
807 kstack->cp0_epc = (long)tcrestart;
808 /* Save TCStatus */
809 kstack->cp0_tcstatus = tcstatus;
810 /* Pass token of operation to be performed kernel stack pad area */
811 kstack->pad0[4] = (unsigned long)pipi;
812 /* Pass address of function to be called likewise */
813 kstack->pad0[5] = (unsigned long)&ipi_decode;
814 /* Set interrupt exempt and kernel mode */
815 tcstatus |= TCSTATUS_IXMT;
816 tcstatus &= ~TCSTATUS_TKSU;
817 write_tc_c0_tcstatus(tcstatus);
818 ehb();
819 /* Set TC Restart address to be SMTC IPI vector */
820 write_tc_c0_tcrestart(__smtc_ipi_vector);
821}
822
823void ipi_resched_interrupt(struct pt_regs *regs)
824{
825 /* Return from interrupt should be enough to cause scheduler check */
826}
827
828
829void ipi_call_interrupt(struct pt_regs *regs)
830{
831 /* Invoke generic function invocation code in smp.c */
832 smp_call_function_interrupt();
833}
834
835void ipi_decode(struct pt_regs *regs, struct smtc_ipi *pipi)
836{
837 void *arg_copy = pipi->arg;
838 int type_copy = pipi->type;
839 int dest_copy = pipi->dest;
840
841 smtc_ipi_nq(&freeIPIq, pipi);
842 switch (type_copy) {
843 case SMTC_CLOCK_TICK:
844 /* Invoke Clock "Interrupt" */
845 ipi_timer_latch[dest_copy] = 0;
846#ifdef SMTC_IDLE_HOOK_DEBUG
847 clock_hang_reported[dest_copy] = 0;
848#endif /* SMTC_IDLE_HOOK_DEBUG */
849 local_timer_interrupt(0, NULL, regs);
850 break;
851 case LINUX_SMP_IPI:
852 switch ((int)arg_copy) {
853 case SMP_RESCHEDULE_YOURSELF:
854 ipi_resched_interrupt(regs);
855 break;
856 case SMP_CALL_FUNCTION:
857 ipi_call_interrupt(regs);
858 break;
859 default:
860 printk("Impossible SMTC IPI Argument 0x%x\n",
861 (int)arg_copy);
862 break;
863 }
864 break;
865 default:
866 printk("Impossible SMTC IPI Type 0x%x\n", type_copy);
867 break;
868 }
869}
870
871void deferred_smtc_ipi(struct pt_regs *regs)
872{
873 struct smtc_ipi *pipi;
874 unsigned long flags;
875/* DEBUG */
876 int q = smp_processor_id();
877
878 /*
879 * Test is not atomic, but much faster than a dequeue,
880 * and the vast majority of invocations will have a null queue.
881 */
882 if(IPIQ[q].head != NULL) {
883 while((pipi = smtc_ipi_dq(&IPIQ[q])) != NULL) {
884 /* ipi_decode() should be called with interrupts off */
885 local_irq_save(flags);
886 ipi_decode(regs, pipi);
887 local_irq_restore(flags);
888 }
889 }
890}
891
892/*
893 * Send clock tick to all TCs except the one executing the funtion
894 */
895
896void smtc_timer_broadcast(int vpe)
897{
898 int cpu;
899 int myTC = cpu_data[smp_processor_id()].tc_id;
900 int myVPE = cpu_data[smp_processor_id()].vpe_id;
901
902 smtc_cpu_stats[smp_processor_id()].timerints++;
903
904 for_each_online_cpu(cpu) {
905 if (cpu_data[cpu].vpe_id == myVPE &&
906 cpu_data[cpu].tc_id != myTC)
907 smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0);
908 }
909}
910
911/*
912 * Cross-VPE interrupts in the SMTC prototype use "software interrupts"
913 * set via cross-VPE MTTR manipulation of the Cause register. It would be
914 * in some regards preferable to have external logic for "doorbell" hardware
915 * interrupts.
916 */
917
918static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ;
919
920static irqreturn_t ipi_interrupt(int irq, void *dev_idm, struct pt_regs *regs)
921{
922 int my_vpe = cpu_data[smp_processor_id()].vpe_id;
923 int my_tc = cpu_data[smp_processor_id()].tc_id;
924 int cpu;
925 struct smtc_ipi *pipi;
926 unsigned long tcstatus;
927 int sent;
928 long flags;
929 unsigned int mtflags;
930 unsigned int vpflags;
931
932 /*
933 * So long as cross-VPE interrupts are done via
934 * MFTR/MTTR read-modify-writes of Cause, we need
935 * to stop other VPEs whenever the local VPE does
936 * anything similar.
937 */
938 local_irq_save(flags);
939 vpflags = dvpe();
940 clear_c0_cause(0x100 << MIPS_CPU_IPI_IRQ);
941 set_c0_status(0x100 << MIPS_CPU_IPI_IRQ);
942 irq_enable_hazard();
943 evpe(vpflags);
944 local_irq_restore(flags);
945
946 /*
947 * Cross-VPE Interrupt handler: Try to directly deliver IPIs
948 * queued for TCs on this VPE other than the current one.
949 * Return-from-interrupt should cause us to drain the queue
950 * for the current TC, so we ought not to have to do it explicitly here.
951 */
952
953 for_each_online_cpu(cpu) {
954 if (cpu_data[cpu].vpe_id != my_vpe)
955 continue;
956
957 pipi = smtc_ipi_dq(&IPIQ[cpu]);
958 if (pipi != NULL) {
959 if (cpu_data[cpu].tc_id != my_tc) {
960 sent = 0;
961 LOCK_MT_PRA();
962 settc(cpu_data[cpu].tc_id);
963 write_tc_c0_tchalt(TCHALT_H);
964 mips_ihb();
965 tcstatus = read_tc_c0_tcstatus();
966 if ((tcstatus & TCSTATUS_IXMT) == 0) {
967 post_direct_ipi(cpu, pipi);
968 sent = 1;
969 }
970 write_tc_c0_tchalt(0);
971 UNLOCK_MT_PRA();
972 if (!sent) {
973 smtc_ipi_req(&IPIQ[cpu], pipi);
974 }
975 } else {
976 /*
977 * ipi_decode() should be called
978 * with interrupts off
979 */
980 local_irq_save(flags);
981 ipi_decode(regs, pipi);
982 local_irq_restore(flags);
983 }
984 }
985 }
986
987 return IRQ_HANDLED;
988}
989
990static void ipi_irq_dispatch(struct pt_regs *regs)
991{
992 do_IRQ(cpu_ipi_irq, regs);
993}
994
995static struct irqaction irq_ipi;
996
997void setup_cross_vpe_interrupts(void)
998{
999 if (!cpu_has_vint)
1000 panic("SMTC Kernel requires Vectored Interupt support");
1001
1002 set_vi_handler(MIPS_CPU_IPI_IRQ, ipi_irq_dispatch);
1003
1004 irq_ipi.handler = ipi_interrupt;
1005 irq_ipi.flags = SA_INTERRUPT;
1006 irq_ipi.name = "SMTC_IPI";
1007
1008 setup_irq_smtc(cpu_ipi_irq, &irq_ipi, (0x100 << MIPS_CPU_IPI_IRQ));
1009
1010 irq_desc[cpu_ipi_irq].status |= IRQ_PER_CPU;
1011}
1012
1013/*
1014 * SMTC-specific hacks invoked from elsewhere in the kernel.
1015 */
1016
1017void smtc_idle_loop_hook(void)
1018{
1019#ifdef SMTC_IDLE_HOOK_DEBUG
1020 int im;
1021 int flags;
1022 int mtflags;
1023 int bit;
1024 int vpe;
1025 int tc;
1026 int hook_ntcs;
1027 /*
1028 * printk within DMT-protected regions can deadlock,
1029 * so buffer diagnostic messages for later output.
1030 */
1031 char *pdb_msg;
1032 char id_ho_db_msg[768]; /* worst-case use should be less than 700 */
1033
1034 if (atomic_read(&idle_hook_initialized) == 0) { /* fast test */
1035 if (atomic_add_return(1, &idle_hook_initialized) == 1) {
1036 int mvpconf0;
1037 /* Tedious stuff to just do once */
1038 mvpconf0 = read_c0_mvpconf0();
1039 hook_ntcs = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
1040 if (hook_ntcs > NR_CPUS)
1041 hook_ntcs = NR_CPUS;
1042 for (tc = 0; tc < hook_ntcs; tc++) {
1043 tcnoprog[tc] = 0;
1044 clock_hang_reported[tc] = 0;
1045 }
1046 for (vpe = 0; vpe < 2; vpe++)
1047 for (im = 0; im < 8; im++)
1048 imstuckcount[vpe][im] = 0;
1049 printk("Idle loop test hook initialized for %d TCs\n", hook_ntcs);
1050 atomic_set(&idle_hook_initialized, 1000);
1051 } else {
1052 /* Someone else is initializing in parallel - let 'em finish */
1053 while (atomic_read(&idle_hook_initialized) < 1000)
1054 ;
1055 }
1056 }
1057
1058 /* Have we stupidly left IXMT set somewhere? */
1059 if (read_c0_tcstatus() & 0x400) {
1060 write_c0_tcstatus(read_c0_tcstatus() & ~0x400);
1061 ehb();
1062 printk("Dangling IXMT in cpu_idle()\n");
1063 }
1064
1065 /* Have we stupidly left an IM bit turned off? */
1066#define IM_LIMIT 2000
1067 local_irq_save(flags);
1068 mtflags = dmt();
1069 pdb_msg = &id_ho_db_msg[0];
1070 im = read_c0_status();
1071 vpe = cpu_data[smp_processor_id()].vpe_id;
1072 for (bit = 0; bit < 8; bit++) {
1073 /*
1074 * In current prototype, I/O interrupts
1075 * are masked for VPE > 0
1076 */
1077 if (vpemask[vpe][bit]) {
1078 if (!(im & (0x100 << bit)))
1079 imstuckcount[vpe][bit]++;
1080 else
1081 imstuckcount[vpe][bit] = 0;
1082 if (imstuckcount[vpe][bit] > IM_LIMIT) {
1083 set_c0_status(0x100 << bit);
1084 ehb();
1085 imstuckcount[vpe][bit] = 0;
1086 pdb_msg += sprintf(pdb_msg,
1087 "Dangling IM %d fixed for VPE %d\n", bit,
1088 vpe);
1089 }
1090 }
1091 }
1092
1093 /*
1094 * Now that we limit outstanding timer IPIs, check for hung TC
1095 */
1096 for (tc = 0; tc < NR_CPUS; tc++) {
1097 /* Don't check ourself - we'll dequeue IPIs just below */
1098 if ((tc != smp_processor_id()) &&
1099 ipi_timer_latch[tc] > timerq_limit) {
1100 if (clock_hang_reported[tc] == 0) {
1101 pdb_msg += sprintf(pdb_msg,
1102 "TC %d looks hung with timer latch at %d\n",
1103 tc, ipi_timer_latch[tc]);
1104 clock_hang_reported[tc]++;
1105 }
1106 }
1107 }
1108 emt(mtflags);
1109 local_irq_restore(flags);
1110 if (pdb_msg != &id_ho_db_msg[0])
1111 printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg);
1112#endif /* SMTC_IDLE_HOOK_DEBUG */
1113 /*
1114 * To the extent that we've ever turned interrupts off,
1115 * we may have accumulated deferred IPIs. This is subtle.
1116 * If we use the smtc_ipi_qdepth() macro, we'll get an
1117 * exact number - but we'll also disable interrupts
1118 * and create a window of failure where a new IPI gets
1119 * queued after we test the depth but before we re-enable
1120 * interrupts. So long as IXMT never gets set, however,
1121 * we should be OK: If we pick up something and dispatch
1122 * it here, that's great. If we see nothing, but concurrent
1123 * with this operation, another TC sends us an IPI, IXMT
1124 * is clear, and we'll handle it as a real pseudo-interrupt
1125 * and not a pseudo-pseudo interrupt.
1126 */
1127 if (IPIQ[smp_processor_id()].depth > 0) {
1128 struct smtc_ipi *pipi;
1129 extern void self_ipi(struct smtc_ipi *);
1130
1131 if ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()])) != NULL) {
1132 self_ipi(pipi);
1133 smtc_cpu_stats[smp_processor_id()].selfipis++;
1134 }
1135 }
1136}
1137
1138void smtc_soft_dump(void)
1139{
1140 int i;
1141
1142 printk("Counter Interrupts taken per CPU (TC)\n");
1143 for (i=0; i < NR_CPUS; i++) {
1144 printk("%d: %ld\n", i, smtc_cpu_stats[i].timerints);
1145 }
1146 printk("Self-IPI invocations:\n");
1147 for (i=0; i < NR_CPUS; i++) {
1148 printk("%d: %ld\n", i, smtc_cpu_stats[i].selfipis);
1149 }
1150 smtc_ipi_qdump();
1151 printk("Timer IPI Backlogs:\n");
1152 for (i=0; i < NR_CPUS; i++) {
1153 printk("%d: %d\n", i, ipi_timer_latch[i]);
1154 }
1155 printk("%d Recoveries of \"stolen\" FPU\n",
1156 atomic_read(&smtc_fpu_recoveries));
1157}
1158
1159
1160/*
1161 * TLB management routines special to SMTC
1162 */
1163
1164void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
1165{
1166 unsigned long flags, mtflags, tcstat, prevhalt, asid;
1167 int tlb, i;
1168
1169 /*
1170 * It would be nice to be able to use a spinlock here,
1171 * but this is invoked from within TLB flush routines
1172 * that protect themselves with DVPE, so if a lock is
1173 * held by another TC, it'll never be freed.
1174 *
1175 * DVPE/DMT must not be done with interrupts enabled,
1176 * so even so most callers will already have disabled
1177 * them, let's be really careful...
1178 */
1179
1180 local_irq_save(flags);
1181 if (smtc_status & SMTC_TLB_SHARED) {
1182 mtflags = dvpe();
1183 tlb = 0;
1184 } else {
1185 mtflags = dmt();
1186 tlb = cpu_data[cpu].vpe_id;
1187 }
1188 asid = asid_cache(cpu);
1189
1190 do {
1191 if (!((asid += ASID_INC) & ASID_MASK) ) {
1192 if (cpu_has_vtag_icache)
1193 flush_icache_all();
1194 /* Traverse all online CPUs (hack requires contigous range) */
1195 for (i = 0; i < num_online_cpus(); i++) {
1196 /*
1197 * We don't need to worry about our own CPU, nor those of
1198 * CPUs who don't share our TLB.
1199 */
1200 if ((i != smp_processor_id()) &&
1201 ((smtc_status & SMTC_TLB_SHARED) ||
1202 (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id))) {
1203 settc(cpu_data[i].tc_id);
1204 prevhalt = read_tc_c0_tchalt() & TCHALT_H;
1205 if (!prevhalt) {
1206 write_tc_c0_tchalt(TCHALT_H);
1207 mips_ihb();
1208 }
1209 tcstat = read_tc_c0_tcstatus();
1210 smtc_live_asid[tlb][(tcstat & ASID_MASK)] |= (asiduse)(0x1 << i);
1211 if (!prevhalt)
1212 write_tc_c0_tchalt(0);
1213 }
1214 }
1215 if (!asid) /* fix version if needed */
1216 asid = ASID_FIRST_VERSION;
1217 local_flush_tlb_all(); /* start new asid cycle */
1218 }
1219 } while (smtc_live_asid[tlb][(asid & ASID_MASK)]);
1220
1221 /*
1222 * SMTC shares the TLB within VPEs and possibly across all VPEs.
1223 */
1224 for (i = 0; i < num_online_cpus(); i++) {
1225 if ((smtc_status & SMTC_TLB_SHARED) ||
1226 (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id))
1227 cpu_context(i, mm) = asid_cache(i) = asid;
1228 }
1229
1230 if (smtc_status & SMTC_TLB_SHARED)
1231 evpe(mtflags);
1232 else
1233 emt(mtflags);
1234 local_irq_restore(flags);
1235}
1236
1237/*
1238 * Invoked from macros defined in mmu_context.h
1239 * which must already have disabled interrupts
1240 * and done a DVPE or DMT as appropriate.
1241 */
1242
1243void smtc_flush_tlb_asid(unsigned long asid)
1244{
1245 int entry;
1246 unsigned long ehi;
1247
1248 entry = read_c0_wired();
1249
1250 /* Traverse all non-wired entries */
1251 while (entry < current_cpu_data.tlbsize) {
1252 write_c0_index(entry);
1253 ehb();
1254 tlb_read();
1255 ehb();
1256 ehi = read_c0_entryhi();
1257 if((ehi & ASID_MASK) == asid) {
1258 /*
1259 * Invalidate only entries with specified ASID,
1260 * makiing sure all entries differ.
1261 */
1262 write_c0_entryhi(CKSEG0 + (entry << (PAGE_SHIFT + 1)));
1263 write_c0_entrylo0(0);
1264 write_c0_entrylo1(0);
1265 mtc0_tlbw_hazard();
1266 tlb_write_indexed();
1267 }
1268 entry++;
1269 }
1270 write_c0_index(PARKED_INDEX);
1271 tlbw_use_hazard();
1272}
1273
1274/*
1275 * Support for single-threading cache flush operations.
1276 */
1277
1278int halt_state_save[NR_CPUS];
1279
1280/*
1281 * To really, really be sure that nothing is being done
1282 * by other TCs, halt them all. This code assumes that
1283 * a DVPE has already been done, so while their Halted
1284 * state is theoretically architecturally unstable, in
1285 * practice, it's not going to change while we're looking
1286 * at it.
1287 */
1288
1289void smtc_cflush_lockdown(void)
1290{
1291 int cpu;
1292
1293 for_each_online_cpu(cpu) {
1294 if (cpu != smp_processor_id()) {
1295 settc(cpu_data[cpu].tc_id);
1296 halt_state_save[cpu] = read_tc_c0_tchalt();
1297 write_tc_c0_tchalt(TCHALT_H);
1298 }
1299 }
1300 mips_ihb();
1301}
1302
1303/* It would be cheating to change the cpu_online states during a flush! */
1304
1305void smtc_cflush_release(void)
1306{
1307 int cpu;
1308
1309 /*
1310 * Start with a hazard barrier to ensure
1311 * that all CACHE ops have played through.
1312 */
1313 mips_ihb();
1314
1315 for_each_online_cpu(cpu) {
1316 if (cpu != smp_processor_id()) {
1317 settc(cpu_data[cpu].tc_id);
1318 write_tc_c0_tchalt(halt_state_save[cpu]);
1319 }
1320 }
1321 mips_ihb();
1322}
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 5e51a2d8f3f0..13ff4da598cd 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -116,8 +116,7 @@ static void c0_timer_ack(void)
116 write_c0_compare(expirelo); 116 write_c0_compare(expirelo);
117 117
118 /* Check to see if we have missed any timer interrupts. */ 118 /* Check to see if we have missed any timer interrupts. */
119 count = read_c0_count(); 119 while (((count = read_c0_count()) - expirelo) < 0x7fffffff) {
120 if ((count - expirelo) < 0x7fffffff) {
121 /* missed_timer_count++; */ 120 /* missed_timer_count++; */
122 expirelo = count + cycles_per_jiffy; 121 expirelo = count + cycles_per_jiffy;
123 write_c0_compare(expirelo); 122 write_c0_compare(expirelo);
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index bed0eb6cf55d..4901f0a37fca 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -42,6 +42,7 @@
42#include <asm/watch.h> 42#include <asm/watch.h>
43#include <asm/types.h> 43#include <asm/types.h>
44 44
45extern asmlinkage void handle_int(void);
45extern asmlinkage void handle_tlbm(void); 46extern asmlinkage void handle_tlbm(void);
46extern asmlinkage void handle_tlbl(void); 47extern asmlinkage void handle_tlbl(void);
47extern asmlinkage void handle_tlbs(void); 48extern asmlinkage void handle_tlbs(void);
@@ -279,9 +280,16 @@ static DEFINE_SPINLOCK(die_lock);
279NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs) 280NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs)
280{ 281{
281 static int die_counter; 282 static int die_counter;
283#ifdef CONFIG_MIPS_MT_SMTC
284 unsigned long dvpret = dvpe();
285#endif /* CONFIG_MIPS_MT_SMTC */
282 286
283 console_verbose(); 287 console_verbose();
284 spin_lock_irq(&die_lock); 288 spin_lock_irq(&die_lock);
289 bust_spinlocks(1);
290#ifdef CONFIG_MIPS_MT_SMTC
291 mips_mt_regdump(dvpret);
292#endif /* CONFIG_MIPS_MT_SMTC */
285 printk("%s[#%d]:\n", str, ++die_counter); 293 printk("%s[#%d]:\n", str, ++die_counter);
286 show_registers(regs); 294 show_registers(regs);
287 spin_unlock_irq(&die_lock); 295 spin_unlock_irq(&die_lock);
@@ -750,12 +758,43 @@ asmlinkage void do_cpu(struct pt_regs *regs)
750 &current->thread.fpu.soft); 758 &current->thread.fpu.soft);
751 if (sig) 759 if (sig)
752 force_sig(sig, current); 760 force_sig(sig, current);
761#ifdef CONFIG_MIPS_MT_FPAFF
762 else {
763 /*
764 * MIPS MT processors may have fewer FPU contexts
765 * than CPU threads. If we've emulated more than
766 * some threshold number of instructions, force
767 * migration to a "CPU" that has FP support.
768 */
769 if(mt_fpemul_threshold > 0
770 && ((current->thread.emulated_fp++
771 > mt_fpemul_threshold))) {
772 /*
773 * If there's no FPU present, or if the
774 * application has already restricted
775 * the allowed set to exclude any CPUs
776 * with FPUs, we'll skip the procedure.
777 */
778 if (cpus_intersects(current->cpus_allowed,
779 mt_fpu_cpumask)) {
780 cpumask_t tmask;
781
782 cpus_and(tmask,
783 current->thread.user_cpus_allowed,
784 mt_fpu_cpumask);
785 set_cpus_allowed(current, tmask);
786 current->thread.mflags |= MF_FPUBOUND;
787 }
788 }
789 }
790#endif /* CONFIG_MIPS_MT_FPAFF */
753 } 791 }
754 792
755 return; 793 return;
756 794
757 case 2: 795 case 2:
758 case 3: 796 case 3:
797 die_if_kernel("do_cpu invoked from kernel context!", regs);
759 break; 798 break;
760 } 799 }
761 800
@@ -793,6 +832,36 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
793 832
794asmlinkage void do_mt(struct pt_regs *regs) 833asmlinkage void do_mt(struct pt_regs *regs)
795{ 834{
835 int subcode;
836
837 die_if_kernel("MIPS MT Thread exception in kernel", regs);
838
839 subcode = (read_vpe_c0_vpecontrol() & VPECONTROL_EXCPT)
840 >> VPECONTROL_EXCPT_SHIFT;
841 switch (subcode) {
842 case 0:
843 printk(KERN_ERR "Thread Underflow\n");
844 break;
845 case 1:
846 printk(KERN_ERR "Thread Overflow\n");
847 break;
848 case 2:
849 printk(KERN_ERR "Invalid YIELD Qualifier\n");
850 break;
851 case 3:
852 printk(KERN_ERR "Gating Storage Exception\n");
853 break;
854 case 4:
855 printk(KERN_ERR "YIELD Scheduler Exception\n");
856 break;
857 case 5:
858 printk(KERN_ERR "Gating Storage Schedulier Exception\n");
859 break;
860 default:
861 printk(KERN_ERR "*** UNKNOWN THREAD EXCEPTION %d ***\n",
862 subcode);
863 break;
864 }
796 die_if_kernel("MIPS MT Thread exception in kernel", regs); 865 die_if_kernel("MIPS MT Thread exception in kernel", regs);
797 866
798 force_sig(SIGILL, current); 867 force_sig(SIGILL, current);
@@ -928,7 +997,15 @@ void ejtag_exception_handler(struct pt_regs *regs)
928 */ 997 */
929void nmi_exception_handler(struct pt_regs *regs) 998void nmi_exception_handler(struct pt_regs *regs)
930{ 999{
1000#ifdef CONFIG_MIPS_MT_SMTC
1001 unsigned long dvpret = dvpe();
1002 bust_spinlocks(1);
1003 printk("NMI taken!!!!\n");
1004 mips_mt_regdump(dvpret);
1005#else
1006 bust_spinlocks(1);
931 printk("NMI taken!!!!\n"); 1007 printk("NMI taken!!!!\n");
1008#endif /* CONFIG_MIPS_MT_SMTC */
932 die("NMI", regs); 1009 die("NMI", regs);
933 while(1) ; 1010 while(1) ;
934} 1011}
@@ -960,27 +1037,29 @@ void *set_except_vector(int n, void *addr)
960 1037
961#ifdef CONFIG_CPU_MIPSR2 1038#ifdef CONFIG_CPU_MIPSR2
962/* 1039/*
963 * Shadow register allocation 1040 * MIPSR2 shadow register set allocation
964 * FIXME: SMP... 1041 * FIXME: SMP...
965 */ 1042 */
966 1043
967/* MIPSR2 shadow register sets */ 1044static struct shadow_registers {
968struct shadow_registers { 1045 /*
969 spinlock_t sr_lock; /* */ 1046 * Number of shadow register sets supported
970 int sr_supported; /* Number of shadow register sets supported */ 1047 */
971 int sr_allocated; /* Bitmap of allocated shadow registers */ 1048 unsigned long sr_supported;
1049 /*
1050 * Bitmap of allocated shadow registers
1051 */
1052 unsigned long sr_allocated;
972} shadow_registers; 1053} shadow_registers;
973 1054
974void mips_srs_init(void) 1055static void mips_srs_init(void)
975{ 1056{
976#ifdef CONFIG_CPU_MIPSR2_SRS 1057#ifdef CONFIG_CPU_MIPSR2_SRS
977 shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1; 1058 shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
978 printk ("%d MIPSR2 register sets available\n", shadow_registers.sr_supported); 1059 printk(KERN_INFO "%d MIPSR2 register sets available\n",
979#else 1060 shadow_registers.sr_supported);
980 shadow_registers.sr_supported = 1;
981#endif 1061#endif
982 shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */ 1062 shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */
983 spin_lock_init(&shadow_registers.sr_lock);
984} 1063}
985 1064
986int mips_srs_max(void) 1065int mips_srs_max(void)
@@ -988,38 +1067,30 @@ int mips_srs_max(void)
988 return shadow_registers.sr_supported; 1067 return shadow_registers.sr_supported;
989} 1068}
990 1069
991int mips_srs_alloc (void) 1070int mips_srs_alloc(void)
992{ 1071{
993 struct shadow_registers *sr = &shadow_registers; 1072 struct shadow_registers *sr = &shadow_registers;
994 unsigned long flags;
995 int set; 1073 int set;
996 1074
997 spin_lock_irqsave(&sr->sr_lock, flags); 1075again:
1076 set = find_first_zero_bit(&sr->sr_allocated, sr->sr_supported);
1077 if (set >= sr->sr_supported)
1078 return -1;
998 1079
999 for (set = 0; set < sr->sr_supported; set++) { 1080 if (test_and_set_bit(set, &sr->sr_allocated))
1000 if ((sr->sr_allocated & (1 << set)) == 0) { 1081 goto again;
1001 sr->sr_allocated |= 1 << set;
1002 spin_unlock_irqrestore(&sr->sr_lock, flags);
1003 return set;
1004 }
1005 }
1006 1082
1007 /* None available */ 1083 return set;
1008 spin_unlock_irqrestore(&sr->sr_lock, flags);
1009 return -1;
1010} 1084}
1011 1085
1012void mips_srs_free (int set) 1086void mips_srs_free(int set)
1013{ 1087{
1014 struct shadow_registers *sr = &shadow_registers; 1088 struct shadow_registers *sr = &shadow_registers;
1015 unsigned long flags;
1016 1089
1017 spin_lock_irqsave(&sr->sr_lock, flags); 1090 clear_bit(set, &sr->sr_allocated);
1018 sr->sr_allocated &= ~(1 << set);
1019 spin_unlock_irqrestore(&sr->sr_lock, flags);
1020} 1091}
1021 1092
1022void *set_vi_srs_handler (int n, void *addr, int srs) 1093static void *set_vi_srs_handler(int n, void *addr, int srs)
1023{ 1094{
1024 unsigned long handler; 1095 unsigned long handler;
1025 unsigned long old_handler = vi_handlers[n]; 1096 unsigned long old_handler = vi_handlers[n];
@@ -1032,8 +1103,7 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
1032 if (addr == NULL) { 1103 if (addr == NULL) {
1033 handler = (unsigned long) do_default_vi; 1104 handler = (unsigned long) do_default_vi;
1034 srs = 0; 1105 srs = 0;
1035 } 1106 } else
1036 else
1037 handler = (unsigned long) addr; 1107 handler = (unsigned long) addr;
1038 vi_handlers[n] = (unsigned long) addr; 1108 vi_handlers[n] = (unsigned long) addr;
1039 1109
@@ -1045,8 +1115,7 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
1045 if (cpu_has_veic) { 1115 if (cpu_has_veic) {
1046 if (board_bind_eic_interrupt) 1116 if (board_bind_eic_interrupt)
1047 board_bind_eic_interrupt (n, srs); 1117 board_bind_eic_interrupt (n, srs);
1048 } 1118 } else if (cpu_has_vint) {
1049 else if (cpu_has_vint) {
1050 /* SRSMap is only defined if shadow sets are implemented */ 1119 /* SRSMap is only defined if shadow sets are implemented */
1051 if (mips_srs_max() > 1) 1120 if (mips_srs_max() > 1)
1052 change_c0_srsmap (0xf << n*4, srs << n*4); 1121 change_c0_srsmap (0xf << n*4, srs << n*4);
@@ -1060,6 +1129,15 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
1060 1129
1061 extern char except_vec_vi, except_vec_vi_lui; 1130 extern char except_vec_vi, except_vec_vi_lui;
1062 extern char except_vec_vi_ori, except_vec_vi_end; 1131 extern char except_vec_vi_ori, except_vec_vi_end;
1132#ifdef CONFIG_MIPS_MT_SMTC
1133 /*
1134 * We need to provide the SMTC vectored interrupt handler
1135 * not only with the address of the handler, but with the
1136 * Status.IM bit to be masked before going there.
1137 */
1138 extern char except_vec_vi_mori;
1139 const int mori_offset = &except_vec_vi_mori - &except_vec_vi;
1140#endif /* CONFIG_MIPS_MT_SMTC */
1063 const int handler_len = &except_vec_vi_end - &except_vec_vi; 1141 const int handler_len = &except_vec_vi_end - &except_vec_vi;
1064 const int lui_offset = &except_vec_vi_lui - &except_vec_vi; 1142 const int lui_offset = &except_vec_vi_lui - &except_vec_vi;
1065 const int ori_offset = &except_vec_vi_ori - &except_vec_vi; 1143 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)
1073 } 1151 }
1074 1152
1075 memcpy (b, &except_vec_vi, handler_len); 1153 memcpy (b, &except_vec_vi, handler_len);
1154#ifdef CONFIG_MIPS_MT_SMTC
1155 if (n > 7)
1156 printk("Vector index %d exceeds SMTC maximum\n", n);
1157 w = (u32 *)(b + mori_offset);
1158 *w = (*w & 0xffff0000) | (0x100 << n);
1159#endif /* CONFIG_MIPS_MT_SMTC */
1076 w = (u32 *)(b + lui_offset); 1160 w = (u32 *)(b + lui_offset);
1077 *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff); 1161 *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff);
1078 w = (u32 *)(b + ori_offset); 1162 w = (u32 *)(b + ori_offset);
@@ -1095,9 +1179,9 @@ void *set_vi_srs_handler (int n, void *addr, int srs)
1095 return (void *)old_handler; 1179 return (void *)old_handler;
1096} 1180}
1097 1181
1098void *set_vi_handler (int n, void *addr) 1182void *set_vi_handler(int n, void *addr)
1099{ 1183{
1100 return set_vi_srs_handler (n, addr, 0); 1184 return set_vi_srs_handler(n, addr, 0);
1101} 1185}
1102#endif 1186#endif
1103 1187
@@ -1113,8 +1197,29 @@ extern asmlinkage int _restore_fp_context(struct sigcontext *sc);
1113extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc); 1197extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc);
1114extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc); 1198extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc);
1115 1199
1200#ifdef CONFIG_SMP
1201static int smp_save_fp_context(struct sigcontext *sc)
1202{
1203 return cpu_has_fpu
1204 ? _save_fp_context(sc)
1205 : fpu_emulator_save_context(sc);
1206}
1207
1208static int smp_restore_fp_context(struct sigcontext *sc)
1209{
1210 return cpu_has_fpu
1211 ? _restore_fp_context(sc)
1212 : fpu_emulator_restore_context(sc);
1213}
1214#endif
1215
1116static inline void signal_init(void) 1216static inline void signal_init(void)
1117{ 1217{
1218#ifdef CONFIG_SMP
1219 /* For now just do the cpu_has_fpu check when the functions are invoked */
1220 save_fp_context = smp_save_fp_context;
1221 restore_fp_context = smp_restore_fp_context;
1222#else
1118 if (cpu_has_fpu) { 1223 if (cpu_has_fpu) {
1119 save_fp_context = _save_fp_context; 1224 save_fp_context = _save_fp_context;
1120 restore_fp_context = _restore_fp_context; 1225 restore_fp_context = _restore_fp_context;
@@ -1122,6 +1227,7 @@ static inline void signal_init(void)
1122 save_fp_context = fpu_emulator_save_context; 1227 save_fp_context = fpu_emulator_save_context;
1123 restore_fp_context = fpu_emulator_restore_context; 1228 restore_fp_context = fpu_emulator_restore_context;
1124 } 1229 }
1230#endif
1125} 1231}
1126 1232
1127#ifdef CONFIG_MIPS32_COMPAT 1233#ifdef CONFIG_MIPS32_COMPAT
@@ -1158,6 +1264,20 @@ void __init per_cpu_trap_init(void)
1158{ 1264{
1159 unsigned int cpu = smp_processor_id(); 1265 unsigned int cpu = smp_processor_id();
1160 unsigned int status_set = ST0_CU0; 1266 unsigned int status_set = ST0_CU0;
1267#ifdef CONFIG_MIPS_MT_SMTC
1268 int secondaryTC = 0;
1269 int bootTC = (cpu == 0);
1270
1271 /*
1272 * Only do per_cpu_trap_init() for first TC of Each VPE.
1273 * Note that this hack assumes that the SMTC init code
1274 * assigns TCs consecutively and in ascending order.
1275 */
1276
1277 if (((read_c0_tcbind() & TCBIND_CURTC) != 0) &&
1278 ((read_c0_tcbind() & TCBIND_CURVPE) == cpu_data[cpu - 1].vpe_id))
1279 secondaryTC = 1;
1280#endif /* CONFIG_MIPS_MT_SMTC */
1161 1281
1162 /* 1282 /*
1163 * Disable coprocessors and select 32-bit or 64-bit addressing 1283 * Disable coprocessors and select 32-bit or 64-bit addressing
@@ -1180,6 +1300,10 @@ void __init per_cpu_trap_init(void)
1180 write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */ 1300 write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */
1181#endif 1301#endif
1182 1302
1303#ifdef CONFIG_MIPS_MT_SMTC
1304 if (!secondaryTC) {
1305#endif /* CONFIG_MIPS_MT_SMTC */
1306
1183 /* 1307 /*
1184 * Interrupt handling. 1308 * Interrupt handling.
1185 */ 1309 */
@@ -1196,6 +1320,9 @@ void __init per_cpu_trap_init(void)
1196 } else 1320 } else
1197 set_c0_cause(CAUSEF_IV); 1321 set_c0_cause(CAUSEF_IV);
1198 } 1322 }
1323#ifdef CONFIG_MIPS_MT_SMTC
1324 }
1325#endif /* CONFIG_MIPS_MT_SMTC */
1199 1326
1200 cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; 1327 cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
1201 TLBMISS_HANDLER_SETUP(); 1328 TLBMISS_HANDLER_SETUP();
@@ -1205,8 +1332,14 @@ void __init per_cpu_trap_init(void)
1205 BUG_ON(current->mm); 1332 BUG_ON(current->mm);
1206 enter_lazy_tlb(&init_mm, current); 1333 enter_lazy_tlb(&init_mm, current);
1207 1334
1208 cpu_cache_init(); 1335#ifdef CONFIG_MIPS_MT_SMTC
1209 tlb_init(); 1336 if (bootTC) {
1337#endif /* CONFIG_MIPS_MT_SMTC */
1338 cpu_cache_init();
1339 tlb_init();
1340#ifdef CONFIG_MIPS_MT_SMTC
1341 }
1342#endif /* CONFIG_MIPS_MT_SMTC */
1210} 1343}
1211 1344
1212/* Install CPU exception handler */ 1345/* Install CPU exception handler */
@@ -1278,7 +1411,7 @@ void __init trap_init(void)
1278 if (cpu_has_veic || cpu_has_vint) { 1411 if (cpu_has_veic || cpu_has_vint) {
1279 int nvec = cpu_has_veic ? 64 : 8; 1412 int nvec = cpu_has_veic ? 64 : 8;
1280 for (i = 0; i < nvec; i++) 1413 for (i = 0; i < nvec; i++)
1281 set_vi_handler (i, NULL); 1414 set_vi_handler(i, NULL);
1282 } 1415 }
1283 else if (cpu_has_divec) 1416 else if (cpu_has_divec)
1284 set_handler(0x200, &except_vec4, 0x8); 1417 set_handler(0x200, &except_vec4, 0x8);
@@ -1297,6 +1430,7 @@ void __init trap_init(void)
1297 if (board_be_init) 1430 if (board_be_init)
1298 board_be_init(); 1431 board_be_init();
1299 1432
1433 set_except_vector(0, handle_int);
1300 set_except_vector(1, handle_tlbm); 1434 set_except_vector(1, handle_tlbm);
1301 set_except_vector(2, handle_tlbl); 1435 set_except_vector(2, handle_tlbl);
1302 set_except_vector(3, handle_tlbs); 1436 set_except_vector(3, handle_tlbs);
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 2ad0cedf29fe..14fa00e3cdfa 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -2,7 +2,7 @@
2#include <asm/asm-offsets.h> 2#include <asm/asm-offsets.h>
3#include <asm-generic/vmlinux.lds.h> 3#include <asm-generic/vmlinux.lds.h>
4 4
5#undef mips /* CPP really sucks for this job */ 5#undef mips
6#define mips mips 6#define mips mips
7OUTPUT_ARCH(mips) 7OUTPUT_ARCH(mips)
8ENTRY(kernel_entry) 8ENTRY(kernel_entry)
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index ae83b755cf4a..80ffaa6d50ad 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -13,7 +13,6 @@
13 * You should have received a copy of the GNU General Public License along 13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc., 14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 15 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
16 *
17 */ 16 */
18 17
19/* 18/*
@@ -27,11 +26,8 @@
27 * 26 *
28 * To load and run, simply cat a SP 'program file' to /dev/vpe1. 27 * To load and run, simply cat a SP 'program file' to /dev/vpe1.
29 * i.e cat spapp >/dev/vpe1. 28 * i.e cat spapp >/dev/vpe1.
30 *
31 * You'll need to have the following device files.
32 * mknod /dev/vpe0 c 63 0
33 * mknod /dev/vpe1 c 63 1
34 */ 29 */
30
35#include <linux/config.h> 31#include <linux/config.h>
36#include <linux/kernel.h> 32#include <linux/kernel.h>
37#include <linux/module.h> 33#include <linux/module.h>
@@ -55,6 +51,8 @@
55#include <asm/cpu.h> 51#include <asm/cpu.h>
56#include <asm/processor.h> 52#include <asm/processor.h>
57#include <asm/system.h> 53#include <asm/system.h>
54#include <asm/vpe.h>
55#include <asm/kspd.h>
58 56
59typedef void *vpe_handle; 57typedef void *vpe_handle;
60 58
@@ -68,6 +66,11 @@ typedef void *vpe_handle;
68static char module_name[] = "vpe"; 66static char module_name[] = "vpe";
69static int major; 67static int major;
70 68
69#ifdef CONFIG_MIPS_APSP_KSPD
70 static struct kspd_notifications kspd_events;
71static int kspd_events_reqd = 0;
72#endif
73
71/* grab the likely amount of memory we will need. */ 74/* grab the likely amount of memory we will need. */
72#ifdef CONFIG_MIPS_VPE_LOADER_TOM 75#ifdef CONFIG_MIPS_VPE_LOADER_TOM
73#define P_SIZE (2 * 1024 * 1024) 76#define P_SIZE (2 * 1024 * 1024)
@@ -76,7 +79,10 @@ static int major;
76#define P_SIZE (256 * 1024) 79#define P_SIZE (256 * 1024)
77#endif 80#endif
78 81
82extern unsigned long physical_memsize;
83
79#define MAX_VPES 16 84#define MAX_VPES 16
85#define VPE_PATH_MAX 256
80 86
81enum vpe_state { 87enum vpe_state {
82 VPE_STATE_UNUSED = 0, 88 VPE_STATE_UNUSED = 0,
@@ -102,6 +108,8 @@ struct vpe {
102 unsigned long len; 108 unsigned long len;
103 char *pbuffer; 109 char *pbuffer;
104 unsigned long plen; 110 unsigned long plen;
111 unsigned int uid, gid;
112 char cwd[VPE_PATH_MAX];
105 113
106 unsigned long __start; 114 unsigned long __start;
107 115
@@ -113,6 +121,9 @@ struct vpe {
113 121
114 /* shared symbol address */ 122 /* shared symbol address */
115 void *shared_ptr; 123 void *shared_ptr;
124
125 /* the list of who wants to know when something major happens */
126 struct list_head notify;
116}; 127};
117 128
118struct tc { 129struct tc {
@@ -138,7 +149,7 @@ struct vpecontrol_ {
138} vpecontrol; 149} vpecontrol;
139 150
140static void release_progmem(void *ptr); 151static void release_progmem(void *ptr);
141static void dump_vpe(struct vpe * v); 152/* static __attribute_used__ void dump_vpe(struct vpe * v); */
142extern void save_gp_address(unsigned int secbase, unsigned int rel); 153extern void save_gp_address(unsigned int secbase, unsigned int rel);
143 154
144/* get the vpe associated with this minor */ 155/* get the vpe associated with this minor */
@@ -146,12 +157,14 @@ struct vpe *get_vpe(int minor)
146{ 157{
147 struct vpe *v; 158 struct vpe *v;
148 159
160 if (!cpu_has_mipsmt)
161 return NULL;
162
149 list_for_each_entry(v, &vpecontrol.vpe_list, list) { 163 list_for_each_entry(v, &vpecontrol.vpe_list, list) {
150 if (v->minor == minor) 164 if (v->minor == minor)
151 return v; 165 return v;
152 } 166 }
153 167
154 printk(KERN_DEBUG "VPE: get_vpe minor %d not found\n", minor);
155 return NULL; 168 return NULL;
156} 169}
157 170
@@ -165,8 +178,6 @@ struct tc *get_tc(int index)
165 return t; 178 return t;
166 } 179 }
167 180
168 printk(KERN_DEBUG "VPE: get_tc index %d not found\n", index);
169
170 return NULL; 181 return NULL;
171} 182}
172 183
@@ -179,8 +190,6 @@ struct tc *get_tc_unused(void)
179 return t; 190 return t;
180 } 191 }
181 192
182 printk(KERN_DEBUG "VPE: All TC's are in use\n");
183
184 return NULL; 193 return NULL;
185} 194}
186 195
@@ -190,13 +199,13 @@ struct vpe *alloc_vpe(int minor)
190 struct vpe *v; 199 struct vpe *v;
191 200
192 if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) { 201 if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) {
193 printk(KERN_WARNING "VPE: alloc_vpe no mem\n");
194 return NULL; 202 return NULL;
195 } 203 }
196 204
197 INIT_LIST_HEAD(&v->tc); 205 INIT_LIST_HEAD(&v->tc);
198 list_add_tail(&v->list, &vpecontrol.vpe_list); 206 list_add_tail(&v->list, &vpecontrol.vpe_list);
199 207
208 INIT_LIST_HEAD(&v->notify);
200 v->minor = minor; 209 v->minor = minor;
201 return v; 210 return v;
202} 211}
@@ -207,7 +216,6 @@ struct tc *alloc_tc(int index)
207 struct tc *t; 216 struct tc *t;
208 217
209 if ((t = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) { 218 if ((t = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) {
210 printk(KERN_WARNING "VPE: alloc_tc no mem\n");
211 return NULL; 219 return NULL;
212 } 220 }
213 221
@@ -236,20 +244,16 @@ void dump_mtregs(void)
236 printk("config3 0x%lx MT %ld\n", val, 244 printk("config3 0x%lx MT %ld\n", val,
237 (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT); 245 (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT);
238 246
239 val = read_c0_mvpconf0();
240 printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
241 (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
242 val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
243
244 val = read_c0_mvpcontrol(); 247 val = read_c0_mvpcontrol();
245 printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val, 248 printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val,
246 (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT, 249 (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT,
247 (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT, 250 (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT,
248 (val & MVPCONTROL_EVP)); 251 (val & MVPCONTROL_EVP));
249 252
250 val = read_c0_vpeconf0(); 253 val = read_c0_mvpconf0();
251 printk("VPEConf0 0x%lx MVP %ld\n", val, 254 printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
252 (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT); 255 (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
256 val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
253} 257}
254 258
255/* Find some VPE program space */ 259/* Find some VPE program space */
@@ -354,9 +358,9 @@ static int apply_r_mips_gprel16(struct module *me, uint32_t *location,
354 } 358 }
355 359
356 if( (rel > 32768) || (rel < -32768) ) { 360 if( (rel > 32768) || (rel < -32768) ) {
357 printk(KERN_ERR 361 printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: "
358 "apply_r_mips_gprel16: relative address out of range 0x%x %d\n", 362 "relative address 0x%x out of range of gp register\n",
359 rel, rel); 363 rel);
360 return -ENOEXEC; 364 return -ENOEXEC;
361 } 365 }
362 366
@@ -374,8 +378,8 @@ static int apply_r_mips_pc16(struct module *me, uint32_t *location,
374 rel -= 1; // and one instruction less due to the branch delay slot. 378 rel -= 1; // and one instruction less due to the branch delay slot.
375 379
376 if( (rel > 32768) || (rel < -32768) ) { 380 if( (rel > 32768) || (rel < -32768) ) {
377 printk(KERN_ERR 381 printk(KERN_DEBUG "VPE loader: "
378 "apply_r_mips_pc16: relative address out of range 0x%x\n", rel); 382 "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
379 return -ENOEXEC; 383 return -ENOEXEC;
380 } 384 }
381 385
@@ -396,7 +400,8 @@ static int apply_r_mips_26(struct module *me, uint32_t *location,
396 Elf32_Addr v) 400 Elf32_Addr v)
397{ 401{
398 if (v % 4) { 402 if (v % 4) {
399 printk(KERN_ERR "module %s: dangerous relocation mod4\n", me->name); 403 printk(KERN_DEBUG "VPE loader: apply_r_mips_26 "
404 " unaligned relocation\n");
400 return -ENOEXEC; 405 return -ENOEXEC;
401 } 406 }
402 407
@@ -459,12 +464,13 @@ static int apply_r_mips_lo16(struct module *me, uint32_t *location,
459 /* 464 /*
460 * The value for the HI16 had best be the same. 465 * The value for the HI16 had best be the same.
461 */ 466 */
462 if (v != l->value) { 467 if (v != l->value) {
463 printk("%d != %d\n", v, l->value); 468 printk(KERN_DEBUG "VPE loader: "
464 goto out_danger; 469 "apply_r_mips_lo16/hi16: "
470 "inconsistent value information\n");
471 return -ENOEXEC;
465 } 472 }
466 473
467
468 /* 474 /*
469 * Do the HI16 relocation. Note that we actually don't 475 * Do the HI16 relocation. Note that we actually don't
470 * need to know anything about the LO16 itself, except 476 * 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,
500 *location = insnlo; 506 *location = insnlo;
501 507
502 return 0; 508 return 0;
503
504out_danger:
505 printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name);
506
507 return -ENOEXEC;
508} 509}
509 510
510static int (*reloc_handlers[]) (struct module *me, uint32_t *location, 511static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
@@ -518,6 +519,15 @@ static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
518 [R_MIPS_PC16] = apply_r_mips_pc16 519 [R_MIPS_PC16] = apply_r_mips_pc16
519}; 520};
520 521
522static char *rstrs[] = {
523 [R_MIPS_NONE] = "MIPS_NONE",
524 [R_MIPS_32] = "MIPS_32",
525 [R_MIPS_26] = "MIPS_26",
526 [R_MIPS_HI16] = "MIPS_HI16",
527 [R_MIPS_LO16] = "MIPS_LO16",
528 [R_MIPS_GPREL16] = "MIPS_GPREL16",
529 [R_MIPS_PC16] = "MIPS_PC16"
530};
521 531
522int apply_relocations(Elf32_Shdr *sechdrs, 532int apply_relocations(Elf32_Shdr *sechdrs,
523 const char *strtab, 533 const char *strtab,
@@ -552,15 +562,13 @@ int apply_relocations(Elf32_Shdr *sechdrs,
552 562
553 res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v); 563 res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
554 if( res ) { 564 if( res ) {
555 printk(KERN_DEBUG 565 char *r = rstrs[ELF32_R_TYPE(r_info)];
556 "relocation error 0x%x sym refer <%s> value 0x%x " 566 printk(KERN_WARNING "VPE loader: .text+0x%x "
557 "type 0x%x r_info 0x%x\n", 567 "relocation type %s for symbol \"%s\" failed\n",
558 (unsigned int)location, strtab + sym->st_name, v, 568 rel[i].r_offset, r ? r : "UNKNOWN",
559 r_info, ELF32_R_TYPE(r_info)); 569 strtab + sym->st_name);
560 }
561
562 if (res)
563 return res; 570 return res;
571 }
564 } 572 }
565 573
566 return 0; 574 return 0;
@@ -576,7 +584,7 @@ void save_gp_address(unsigned int secbase, unsigned int rel)
576 584
577 585
578/* Change all symbols so that sh_value encodes the pointer directly. */ 586/* Change all symbols so that sh_value encodes the pointer directly. */
579static int simplify_symbols(Elf_Shdr * sechdrs, 587static void simplify_symbols(Elf_Shdr * sechdrs,
580 unsigned int symindex, 588 unsigned int symindex,
581 const char *strtab, 589 const char *strtab,
582 const char *secstrings, 590 const char *secstrings,
@@ -585,18 +593,21 @@ static int simplify_symbols(Elf_Shdr * sechdrs,
585 Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; 593 Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
586 unsigned long secbase, bssbase = 0; 594 unsigned long secbase, bssbase = 0;
587 unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); 595 unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
588 int ret = 0, size; 596 int size;
589 597
590 /* find the .bss section for COMMON symbols */ 598 /* find the .bss section for COMMON symbols */
591 for (i = 0; i < nsecs; i++) { 599 for (i = 0; i < nsecs; i++) {
592 if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) 600 if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) {
593 bssbase = sechdrs[i].sh_addr; 601 bssbase = sechdrs[i].sh_addr;
602 break;
603 }
594 } 604 }
595 605
596 for (i = 1; i < n; i++) { 606 for (i = 1; i < n; i++) {
597 switch (sym[i].st_shndx) { 607 switch (sym[i].st_shndx) {
598 case SHN_COMMON: 608 case SHN_COMMON:
599 /* Allocate space for the symbol in the .bss section. st_value is currently size. 609 /* Allocate space for the symbol in the .bss section.
610 st_value is currently size.
600 We want it to have the address of the symbol. */ 611 We want it to have the address of the symbol. */
601 612
602 size = sym[i].st_value; 613 size = sym[i].st_value;
@@ -614,11 +625,9 @@ static int simplify_symbols(Elf_Shdr * sechdrs,
614 break; 625 break;
615 626
616 case SHN_MIPS_SCOMMON: 627 case SHN_MIPS_SCOMMON:
617 628 printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON"
618 printk(KERN_DEBUG 629 "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name,
619 "simplify_symbols: ignoring SHN_MIPS_SCOMMON symbol <%s> st_shndx %d\n", 630 sym[i].st_shndx);
620 strtab + sym[i].st_name, sym[i].st_shndx);
621
622 // .sbss section 631 // .sbss section
623 break; 632 break;
624 633
@@ -632,10 +641,7 @@ static int simplify_symbols(Elf_Shdr * sechdrs,
632 sym[i].st_value += secbase; 641 sym[i].st_value += secbase;
633 break; 642 break;
634 } 643 }
635
636 } 644 }
637
638 return ret;
639} 645}
640 646
641#ifdef DEBUG_ELFLOADER 647#ifdef DEBUG_ELFLOADER
@@ -655,9 +661,26 @@ static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
655 661
656static void dump_tc(struct tc *t) 662static void dump_tc(struct tc *t)
657{ 663{
658 printk(KERN_WARNING "VPE: TC index %d TCStatus 0x%lx halt 0x%lx\n", 664 unsigned long val;
659 t->index, read_tc_c0_tcstatus(), read_tc_c0_tchalt()); 665
660 printk(KERN_WARNING "VPE: tcrestart 0x%lx\n", read_tc_c0_tcrestart()); 666 settc(t->index);
667 printk(KERN_DEBUG "VPE loader: TC index %d targtc %ld "
668 "TCStatus 0x%lx halt 0x%lx\n",
669 t->index, read_c0_vpecontrol() & VPECONTROL_TARGTC,
670 read_tc_c0_tcstatus(), read_tc_c0_tchalt());
671
672 printk(KERN_DEBUG " tcrestart 0x%lx\n", read_tc_c0_tcrestart());
673 printk(KERN_DEBUG " tcbind 0x%lx\n", read_tc_c0_tcbind());
674
675 val = read_c0_vpeconf0();
676 printk(KERN_DEBUG " VPEConf0 0x%lx MVP %ld\n", val,
677 (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT);
678
679 printk(KERN_DEBUG " c0 status 0x%lx\n", read_vpe_c0_status());
680 printk(KERN_DEBUG " c0 cause 0x%lx\n", read_vpe_c0_cause());
681
682 printk(KERN_DEBUG " c0 badvaddr 0x%lx\n", read_vpe_c0_badvaddr());
683 printk(KERN_DEBUG " c0 epc 0x%lx\n", read_vpe_c0_epc());
661} 684}
662 685
663static void dump_tclist(void) 686static void dump_tclist(void)
@@ -672,96 +695,108 @@ static void dump_tclist(void)
672/* We are prepared so configure and start the VPE... */ 695/* We are prepared so configure and start the VPE... */
673int vpe_run(struct vpe * v) 696int vpe_run(struct vpe * v)
674{ 697{
675 unsigned long val; 698 struct vpe_notifications *n;
699 unsigned long val, dmt_flag;
676 struct tc *t; 700 struct tc *t;
677 701
678 /* check we are the Master VPE */ 702 /* check we are the Master VPE */
679 val = read_c0_vpeconf0(); 703 val = read_c0_vpeconf0();
680 if (!(val & VPECONF0_MVP)) { 704 if (!(val & VPECONF0_MVP)) {
681 printk(KERN_WARNING 705 printk(KERN_WARNING
682 "VPE: only Master VPE's are allowed to configure MT\n"); 706 "VPE loader: only Master VPE's are allowed to configure MT\n");
683 return -1; 707 return -1;
684 } 708 }
685 709
686 /* disable MT (using dvpe) */ 710 /* disable MT (using dvpe) */
687 dvpe(); 711 dvpe();
688 712
713 if (!list_empty(&v->tc)) {
714 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
715 printk(KERN_WARNING "VPE loader: TC %d is already in use.\n",
716 t->index);
717 return -ENOEXEC;
718 }
719 } else {
720 printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n",
721 v->minor);
722 return -ENOEXEC;
723 }
724
689 /* Put MVPE's into 'configuration state' */ 725 /* Put MVPE's into 'configuration state' */
690 set_c0_mvpcontrol(MVPCONTROL_VPC); 726 set_c0_mvpcontrol(MVPCONTROL_VPC);
691 727
692 if (!list_empty(&v->tc)) {
693 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
694 printk(KERN_WARNING "VPE: TC %d is already in use.\n",
695 t->index);
696 return -ENOEXEC;
697 }
698 } else {
699 printk(KERN_WARNING "VPE: No TC's associated with VPE %d\n",
700 v->minor);
701 return -ENOEXEC;
702 }
703
704 settc(t->index); 728 settc(t->index);
705 729
706 val = read_vpe_c0_vpeconf0();
707
708 /* should check it is halted, and not activated */ 730 /* should check it is halted, and not activated */
709 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { 731 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
710 printk(KERN_WARNING "VPE: TC %d is already doing something!\n", 732 printk(KERN_WARNING "VPE loader: TC %d is already doing something!\n",
711 t->index); 733 t->index);
712
713 dump_tclist(); 734 dump_tclist();
714 return -ENOEXEC; 735 return -ENOEXEC;
715 } 736 }
716 737
738 /*
739 * Disable multi-threaded execution whilst we activate, clear the
740 * halt bit and bound the tc to the other VPE...
741 */
742 dmt_flag = dmt();
743
717 /* Write the address we want it to start running from in the TCPC register. */ 744 /* Write the address we want it to start running from in the TCPC register. */
718 write_tc_c0_tcrestart((unsigned long)v->__start); 745 write_tc_c0_tcrestart((unsigned long)v->__start);
719
720 /* write the sivc_info address to tccontext */
721 write_tc_c0_tccontext((unsigned long)0); 746 write_tc_c0_tccontext((unsigned long)0);
722 747 /*
723 /* Set up the XTC bit in vpeconf0 to point at our tc */ 748 * Mark the TC as activated, not interrupt exempt and not dynamically
724 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (t->index << VPECONF0_XTC_SHIFT)); 749 * allocatable
725 750 */
726 /* mark the TC as activated, not interrupt exempt and not dynamically allocatable */
727 val = read_tc_c0_tcstatus(); 751 val = read_tc_c0_tcstatus();
728 val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A; 752 val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
729 write_tc_c0_tcstatus(val); 753 write_tc_c0_tcstatus(val);
730 754
731 write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); 755 write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
732 756
733 /* set up VPE1 */
734 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); // no multiple TC's
735 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); // enable this VPE
736
737 /* 757 /*
738 * The sde-kit passes 'memsize' to __start in $a3, so set something 758 * The sde-kit passes 'memsize' to __start in $a3, so set something
739 * here... 759 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and
740 * Or set $a3 (register 7) to zero and define DFLT_STACK_SIZE and
741 * DFLT_HEAP_SIZE when you compile your program 760 * DFLT_HEAP_SIZE when you compile your program
742 */ 761 */
762 mttgpr(7, physical_memsize);
763
764
765 /* set up VPE1 */
766 /*
767 * bind the TC to VPE 1 as late as possible so we only have the final
768 * VPE registers to set up, and so an EJTAG probe can trigger on it
769 */
770 write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor);
743 771
744 mttgpr(7, 0); 772 /* Set up the XTC bit in vpeconf0 to point at our tc */
773 write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
774 | (t->index << VPECONF0_XTC_SHIFT));
745 775
746 /* set config to be the same as vpe0, particularly kseg0 coherency alg */ 776 /* enable this VPE */
747 write_vpe_c0_config(read_c0_config()); 777 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
748 778
749 /* clear out any left overs from a previous program */ 779 /* clear out any left overs from a previous program */
780 write_vpe_c0_status(0);
750 write_vpe_c0_cause(0); 781 write_vpe_c0_cause(0);
751 782
752 /* take system out of configuration state */ 783 /* take system out of configuration state */
753 clear_c0_mvpcontrol(MVPCONTROL_VPC); 784 clear_c0_mvpcontrol(MVPCONTROL_VPC);
754 785
755 /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */ 786 /* now safe to re-enable multi-threading */
756 write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE | ST0_EXL)); 787 emt(dmt_flag);
757 788
758 /* set it running */ 789 /* set it running */
759 evpe(EVPE_ENABLE); 790 evpe(EVPE_ENABLE);
760 791
792 list_for_each_entry(n, &v->notify, list) {
793 n->start(v->minor);
794 }
795
761 return 0; 796 return 0;
762} 797}
763 798
764static unsigned long find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, 799static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
765 unsigned int symindex, const char *strtab, 800 unsigned int symindex, const char *strtab,
766 struct module *mod) 801 struct module *mod)
767{ 802{
@@ -778,26 +813,28 @@ static unsigned long find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
778 } 813 }
779 } 814 }
780 815
816 if ( (v->__start == 0) || (v->shared_ptr == NULL))
817 return -1;
818
781 return 0; 819 return 0;
782} 820}
783 821
784/* 822/*
785 * Allocates a VPE with some program code space(the load address), copies 823 * Allocates a VPE with some program code space(the load address), copies the
786 * the contents of the program (p)buffer performing relocatations/etc, 824 * contents of the program (p)buffer performing relocatations/etc, free's it
787 * free's it when finished. 825 * when finished.
788*/ 826 */
789int vpe_elfload(struct vpe * v) 827int vpe_elfload(struct vpe * v)
790{ 828{
791 Elf_Ehdr *hdr; 829 Elf_Ehdr *hdr;
792 Elf_Shdr *sechdrs; 830 Elf_Shdr *sechdrs;
793 long err = 0; 831 long err = 0;
794 char *secstrings, *strtab = NULL; 832 char *secstrings, *strtab = NULL;
795 unsigned int len, i, symindex = 0, strindex = 0; 833 unsigned int len, i, symindex = 0, strindex = 0, relocate = 0;
796
797 struct module mod; // so we can re-use the relocations code 834 struct module mod; // so we can re-use the relocations code
798 835
799 memset(&mod, 0, sizeof(struct module)); 836 memset(&mod, 0, sizeof(struct module));
800 strcpy(mod.name, "VPE dummy prog module"); 837 strcpy(mod.name, "VPE loader");
801 838
802 hdr = (Elf_Ehdr *) v->pbuffer; 839 hdr = (Elf_Ehdr *) v->pbuffer;
803 len = v->plen; 840 len = v->plen;
@@ -805,16 +842,22 @@ int vpe_elfload(struct vpe * v)
805 /* Sanity checks against insmoding binaries or wrong arch, 842 /* Sanity checks against insmoding binaries or wrong arch,
806 weird elf version */ 843 weird elf version */
807 if (memcmp(hdr->e_ident, ELFMAG, 4) != 0 844 if (memcmp(hdr->e_ident, ELFMAG, 4) != 0
808 || hdr->e_type != ET_REL || !elf_check_arch(hdr) 845 || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC)
846 || !elf_check_arch(hdr)
809 || hdr->e_shentsize != sizeof(*sechdrs)) { 847 || hdr->e_shentsize != sizeof(*sechdrs)) {
810 printk(KERN_WARNING 848 printk(KERN_WARNING
811 "VPE program, wrong arch or weird elf version\n"); 849 "VPE loader: program wrong arch or weird elf version\n");
812 850
813 return -ENOEXEC; 851 return -ENOEXEC;
814 } 852 }
815 853
854 if (hdr->e_type == ET_REL)
855 relocate = 1;
856
816 if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) { 857 if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
817 printk(KERN_ERR "VPE program length %u truncated\n", len); 858 printk(KERN_ERR "VPE loader: program length %u truncated\n",
859 len);
860
818 return -ENOEXEC; 861 return -ENOEXEC;
819 } 862 }
820 863
@@ -826,82 +869,126 @@ int vpe_elfload(struct vpe * v)
826 /* And these should exist, but gcc whinges if we don't init them */ 869 /* And these should exist, but gcc whinges if we don't init them */
827 symindex = strindex = 0; 870 symindex = strindex = 0;
828 871
829 for (i = 1; i < hdr->e_shnum; i++) { 872 if (relocate) {
830 873 for (i = 1; i < hdr->e_shnum; i++) {
831 if (sechdrs[i].sh_type != SHT_NOBITS 874 if (sechdrs[i].sh_type != SHT_NOBITS
832 && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) { 875 && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
833 printk(KERN_ERR "VPE program length %u truncated\n", 876 printk(KERN_ERR "VPE program length %u truncated\n",
834 len); 877 len);
835 return -ENOEXEC; 878 return -ENOEXEC;
836 } 879 }
837 880
838 /* Mark all sections sh_addr with their address in the 881 /* Mark all sections sh_addr with their address in the
839 temporary image. */ 882 temporary image. */
840 sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset; 883 sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
841 884
842 /* Internal symbols and strings. */ 885 /* Internal symbols and strings. */
843 if (sechdrs[i].sh_type == SHT_SYMTAB) { 886 if (sechdrs[i].sh_type == SHT_SYMTAB) {
844 symindex = i; 887 symindex = i;
845 strindex = sechdrs[i].sh_link; 888 strindex = sechdrs[i].sh_link;
846 strtab = (char *)hdr + sechdrs[strindex].sh_offset; 889 strtab = (char *)hdr + sechdrs[strindex].sh_offset;
890 }
847 } 891 }
892 layout_sections(&mod, hdr, sechdrs, secstrings);
848 } 893 }
849 894
850 layout_sections(&mod, hdr, sechdrs, secstrings);
851
852 v->load_addr = alloc_progmem(mod.core_size); 895 v->load_addr = alloc_progmem(mod.core_size);
853 memset(v->load_addr, 0, mod.core_size); 896 memset(v->load_addr, 0, mod.core_size);
854 897
855 printk("VPE elf_loader: loading to %p\n", v->load_addr); 898 printk("VPE loader: loading to %p\n", v->load_addr);
856 899
857 for (i = 0; i < hdr->e_shnum; i++) { 900 if (relocate) {
858 void *dest; 901 for (i = 0; i < hdr->e_shnum; i++) {
902 void *dest;
859 903
860 if (!(sechdrs[i].sh_flags & SHF_ALLOC)) 904 if (!(sechdrs[i].sh_flags & SHF_ALLOC))
861 continue; 905 continue;
862 906
863 dest = v->load_addr + sechdrs[i].sh_entsize; 907 dest = v->load_addr + sechdrs[i].sh_entsize;
864 908
865 if (sechdrs[i].sh_type != SHT_NOBITS) 909 if (sechdrs[i].sh_type != SHT_NOBITS)
866 memcpy(dest, (void *)sechdrs[i].sh_addr, 910 memcpy(dest, (void *)sechdrs[i].sh_addr,
867 sechdrs[i].sh_size); 911 sechdrs[i].sh_size);
868 /* Update sh_addr to point to copy in image. */ 912 /* Update sh_addr to point to copy in image. */
869 sechdrs[i].sh_addr = (unsigned long)dest; 913 sechdrs[i].sh_addr = (unsigned long)dest;
870 }
871 914
872 /* Fix up syms, so that st_value is a pointer to location. */ 915 printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n",
873 err = 916 secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
874 simplify_symbols(sechdrs, symindex, strtab, secstrings, 917 }
875 hdr->e_shnum, &mod);
876 if (err < 0) {
877 printk(KERN_WARNING "VPE: unable to simplify symbols\n");
878 goto cleanup;
879 }
880 918
881 /* Now do relocations. */ 919 /* Fix up syms, so that st_value is a pointer to location. */
882 for (i = 1; i < hdr->e_shnum; i++) { 920 simplify_symbols(sechdrs, symindex, strtab, secstrings,
883 const char *strtab = (char *)sechdrs[strindex].sh_addr; 921 hdr->e_shnum, &mod);
884 unsigned int info = sechdrs[i].sh_info; 922
885 923 /* Now do relocations. */
886 /* Not a valid relocation section? */ 924 for (i = 1; i < hdr->e_shnum; i++) {
887 if (info >= hdr->e_shnum) 925 const char *strtab = (char *)sechdrs[strindex].sh_addr;
888 continue; 926 unsigned int info = sechdrs[i].sh_info;
889 927
890 /* Don't bother with non-allocated sections */ 928 /* Not a valid relocation section? */
891 if (!(sechdrs[info].sh_flags & SHF_ALLOC)) 929 if (info >= hdr->e_shnum)
892 continue; 930 continue;
893 931
894 if (sechdrs[i].sh_type == SHT_REL) 932 /* Don't bother with non-allocated sections */
895 err = 933 if (!(sechdrs[info].sh_flags & SHF_ALLOC))
896 apply_relocations(sechdrs, strtab, symindex, i, &mod); 934 continue;
897 else if (sechdrs[i].sh_type == SHT_RELA) 935
898 err = apply_relocate_add(sechdrs, strtab, symindex, i, 936 if (sechdrs[i].sh_type == SHT_REL)
899 &mod); 937 err = apply_relocations(sechdrs, strtab, symindex, i,
900 if (err < 0) { 938 &mod);
901 printk(KERN_WARNING 939 else if (sechdrs[i].sh_type == SHT_RELA)
902 "vpe_elfload: error in relocations err %ld\n", 940 err = apply_relocate_add(sechdrs, strtab, symindex, i,
903 err); 941 &mod);
904 goto cleanup; 942 if (err < 0)
943 return err;
944
945 }
946 } else {
947 for (i = 0; i < hdr->e_shnum; i++) {
948
949 /* Internal symbols and strings. */
950 if (sechdrs[i].sh_type == SHT_SYMTAB) {
951 symindex = i;
952 strindex = sechdrs[i].sh_link;
953 strtab = (char *)hdr + sechdrs[strindex].sh_offset;
954
955 /* mark the symtab's address for when we try to find the
956 magic symbols */
957 sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
958 }
959
960 /* filter sections we dont want in the final image */
961 if (!(sechdrs[i].sh_flags & SHF_ALLOC) ||
962 (sechdrs[i].sh_type == SHT_MIPS_REGINFO)) {
963 printk( KERN_DEBUG " ignoring section, "
964 "name %s type %x address 0x%x \n",
965 secstrings + sechdrs[i].sh_name,
966 sechdrs[i].sh_type, sechdrs[i].sh_addr);
967 continue;
968 }
969
970 if (sechdrs[i].sh_addr < (unsigned int)v->load_addr) {
971 printk( KERN_WARNING "VPE loader: "
972 "fully linked image has invalid section, "
973 "name %s type %x address 0x%x, before load "
974 "address of 0x%x\n",
975 secstrings + sechdrs[i].sh_name,
976 sechdrs[i].sh_type, sechdrs[i].sh_addr,
977 (unsigned int)v->load_addr);
978 return -ENOEXEC;
979 }
980
981 printk(KERN_DEBUG " copying section sh_name %s, sh_addr 0x%x "
982 "size 0x%x0 from x%p\n",
983 secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr,
984 sechdrs[i].sh_size, hdr + sechdrs[i].sh_offset);
985
986 if (sechdrs[i].sh_type != SHT_NOBITS)
987 memcpy((void *)sechdrs[i].sh_addr,
988 (char *)hdr + sechdrs[i].sh_offset,
989 sechdrs[i].sh_size);
990 else
991 memset((void *)sechdrs[i].sh_addr, 0, sechdrs[i].sh_size);
905 } 992 }
906 } 993 }
907 994
@@ -910,71 +997,104 @@ int vpe_elfload(struct vpe * v)
910 (unsigned long)v->load_addr + v->len); 997 (unsigned long)v->load_addr + v->len);
911 998
912 if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { 999 if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
1000 if (v->__start == 0) {
1001 printk(KERN_WARNING "VPE loader: program does not contain "
1002 "a __start symbol\n");
1003 return -ENOEXEC;
1004 }
913 1005
914 printk(KERN_WARNING 1006 if (v->shared_ptr == NULL)
915 "VPE: program doesn't contain __start or vpe_shared symbols\n"); 1007 printk(KERN_WARNING "VPE loader: "
916 err = -ENOEXEC; 1008 "program does not contain vpe_shared symbol.\n"
1009 " Unable to use AMVP (AP/SP) facilities.\n");
917 } 1010 }
918 1011
919 printk(" elf loaded\n"); 1012 printk(" elf loaded\n");
920 1013 return 0;
921cleanup:
922 return err;
923} 1014}
924 1015
925static void dump_vpe(struct vpe * v) 1016__attribute_used__ void dump_vpe(struct vpe * v)
926{ 1017{
927 struct tc *t; 1018 struct tc *t;
928 1019
1020 settc(v->minor);
1021
929 printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol()); 1022 printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol());
930 printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0()); 1023 printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0());
931 1024
932 list_for_each_entry(t, &vpecontrol.tc_list, list) { 1025 list_for_each_entry(t, &vpecontrol.tc_list, list)
933 dump_tc(t); 1026 dump_tc(t);
934 }
935} 1027}
936 1028
937/* checks for VPE is unused and gets ready to load program */ 1029static void cleanup_tc(struct tc *tc)
1030{
1031 int tmp;
1032
1033 /* Put MVPE's into 'configuration state' */
1034 set_c0_mvpcontrol(MVPCONTROL_VPC);
1035
1036 settc(tc->index);
1037 tmp = read_tc_c0_tcstatus();
1038
1039 /* mark not allocated and not dynamically allocatable */
1040 tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1041 tmp |= TCSTATUS_IXMT; /* interrupt exempt */
1042 write_tc_c0_tcstatus(tmp);
1043
1044 write_tc_c0_tchalt(TCHALT_H);
1045
1046 /* bind it to anything other than VPE1 */
1047 write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
1048
1049 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1050}
1051
1052static int getcwd(char *buff, int size)
1053{
1054 mm_segment_t old_fs;
1055 int ret;
1056
1057 old_fs = get_fs();
1058 set_fs(KERNEL_DS);
1059
1060 ret = sys_getcwd(buff,size);
1061
1062 set_fs(old_fs);
1063
1064 return ret;
1065}
1066
1067/* checks VPE is unused and gets ready to load program */
938static int vpe_open(struct inode *inode, struct file *filp) 1068static int vpe_open(struct inode *inode, struct file *filp)
939{ 1069{
940 int minor; 1070 int minor, ret;
941 struct vpe *v; 1071 struct vpe *v;
1072 struct vpe_notifications *not;
942 1073
943 /* assume only 1 device at the mo. */ 1074 /* assume only 1 device at the mo. */
944 if ((minor = MINOR(inode->i_rdev)) != 1) { 1075 if ((minor = MINOR(inode->i_rdev)) != 1) {
945 printk(KERN_WARNING "VPE: only vpe1 is supported\n"); 1076 printk(KERN_WARNING "VPE loader: only vpe1 is supported\n");
946 return -ENODEV; 1077 return -ENODEV;
947 } 1078 }
948 1079
949 if ((v = get_vpe(minor)) == NULL) { 1080 if ((v = get_vpe(minor)) == NULL) {
950 printk(KERN_WARNING "VPE: unable to get vpe\n"); 1081 printk(KERN_WARNING "VPE loader: unable to get vpe\n");
951 return -ENODEV; 1082 return -ENODEV;
952 } 1083 }
953 1084
954 if (v->state != VPE_STATE_UNUSED) { 1085 if (v->state != VPE_STATE_UNUSED) {
955 unsigned long tmp;
956 struct tc *t;
957
958 printk(KERN_WARNING "VPE: device %d already in use\n", minor);
959
960 dvpe(); 1086 dvpe();
961 dump_vpe(v);
962
963 printk(KERN_WARNING "VPE: re-initialising %d\n", minor);
964
965 release_progmem(v->load_addr);
966 1087
967 t = get_tc(minor); 1088 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
968 settc(minor);
969 tmp = read_tc_c0_tcstatus();
970 1089
971 /* mark not allocated and not dynamically allocatable */ 1090 dump_tc(get_tc(minor));
972 tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
973 tmp |= TCSTATUS_IXMT; /* interrupt exempt */
974 write_tc_c0_tcstatus(tmp);
975 1091
976 write_tc_c0_tchalt(TCHALT_H); 1092 list_for_each_entry(not, &v->notify, list) {
1093 not->stop(minor);
1094 }
977 1095
1096 release_progmem(v->load_addr);
1097 cleanup_tc(get_tc(minor));
978 } 1098 }
979 1099
980 // allocate it so when we get write ops we know it's expected. 1100 // 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)
986 v->load_addr = NULL; 1106 v->load_addr = NULL;
987 v->len = 0; 1107 v->len = 0;
988 1108
1109 v->uid = filp->f_uid;
1110 v->gid = filp->f_gid;
1111
1112#ifdef CONFIG_MIPS_APSP_KSPD
1113 /* get kspd to tell us when a syscall_exit happens */
1114 if (!kspd_events_reqd) {
1115 kspd_notify(&kspd_events);
1116 kspd_events_reqd++;
1117 }
1118#endif
1119
1120 v->cwd[0] = 0;
1121 ret = getcwd(v->cwd, VPE_PATH_MAX);
1122 if (ret < 0)
1123 printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret);
1124
1125 v->shared_ptr = NULL;
1126 v->__start = 0;
989 return 0; 1127 return 0;
990} 1128}
991 1129
@@ -1006,14 +1144,22 @@ static int vpe_release(struct inode *inode, struct file *filp)
1006 if (vpe_elfload(v) >= 0) 1144 if (vpe_elfload(v) >= 0)
1007 vpe_run(v); 1145 vpe_run(v);
1008 else { 1146 else {
1009 printk(KERN_WARNING "VPE: ELF load failed.\n"); 1147 printk(KERN_WARNING "VPE loader: ELF load failed.\n");
1010 ret = -ENOEXEC; 1148 ret = -ENOEXEC;
1011 } 1149 }
1012 } else { 1150 } else {
1013 printk(KERN_WARNING "VPE: only elf files are supported\n"); 1151 printk(KERN_WARNING "VPE loader: only elf files are supported\n");
1014 ret = -ENOEXEC; 1152 ret = -ENOEXEC;
1015 } 1153 }
1016 1154
1155 /* It's good to be able to run the SP and if it chokes have a look at
1156 the /dev/rt?. But if we reset the pointer to the shared struct we
1157 loose what has happened. So perhaps if garbage is sent to the vpe
1158 device, use it as a trigger for the reset. Hopefully a nice
1159 executable will be along shortly. */
1160 if (ret < 0)
1161 v->shared_ptr = NULL;
1162
1017 // cleanup any temp buffers 1163 // cleanup any temp buffers
1018 if (v->pbuffer) 1164 if (v->pbuffer)
1019 vfree(v->pbuffer); 1165 vfree(v->pbuffer);
@@ -1033,21 +1179,19 @@ static ssize_t vpe_write(struct file *file, const char __user * buffer,
1033 return -ENODEV; 1179 return -ENODEV;
1034 1180
1035 if (v->pbuffer == NULL) { 1181 if (v->pbuffer == NULL) {
1036 printk(KERN_ERR "vpe_write: no pbuffer\n"); 1182 printk(KERN_ERR "VPE loader: no buffer for program\n");
1037 return -ENOMEM; 1183 return -ENOMEM;
1038 } 1184 }
1039 1185
1040 if ((count + v->len) > v->plen) { 1186 if ((count + v->len) > v->plen) {
1041 printk(KERN_WARNING 1187 printk(KERN_WARNING
1042 "VPE Loader: elf size too big. Perhaps strip uneeded symbols\n"); 1188 "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
1043 return -ENOMEM; 1189 return -ENOMEM;
1044 } 1190 }
1045 1191
1046 count -= copy_from_user(v->pbuffer + v->len, buffer, count); 1192 count -= copy_from_user(v->pbuffer + v->len, buffer, count);
1047 if (!count) { 1193 if (!count)
1048 printk("vpe_write: copy_to_user failed\n");
1049 return -EFAULT; 1194 return -EFAULT;
1050 }
1051 1195
1052 v->len += count; 1196 v->len += count;
1053 return ret; 1197 return ret;
@@ -1149,16 +1293,70 @@ void *vpe_get_shared(int index)
1149{ 1293{
1150 struct vpe *v; 1294 struct vpe *v;
1151 1295
1152 if ((v = get_vpe(index)) == NULL) { 1296 if ((v = get_vpe(index)) == NULL)
1153 printk(KERN_WARNING "vpe: invalid vpe index %d\n", index);
1154 return NULL; 1297 return NULL;
1155 }
1156 1298
1157 return v->shared_ptr; 1299 return v->shared_ptr;
1158} 1300}
1159 1301
1160EXPORT_SYMBOL(vpe_get_shared); 1302EXPORT_SYMBOL(vpe_get_shared);
1161 1303
1304int vpe_getuid(int index)
1305{
1306 struct vpe *v;
1307
1308 if ((v = get_vpe(index)) == NULL)
1309 return -1;
1310
1311 return v->uid;
1312}
1313
1314EXPORT_SYMBOL(vpe_getuid);
1315
1316int vpe_getgid(int index)
1317{
1318 struct vpe *v;
1319
1320 if ((v = get_vpe(index)) == NULL)
1321 return -1;
1322
1323 return v->gid;
1324}
1325
1326EXPORT_SYMBOL(vpe_getgid);
1327
1328int vpe_notify(int index, struct vpe_notifications *notify)
1329{
1330 struct vpe *v;
1331
1332 if ((v = get_vpe(index)) == NULL)
1333 return -1;
1334
1335 list_add(&notify->list, &v->notify);
1336 return 0;
1337}
1338
1339EXPORT_SYMBOL(vpe_notify);
1340
1341char *vpe_getcwd(int index)
1342{
1343 struct vpe *v;
1344
1345 if ((v = get_vpe(index)) == NULL)
1346 return NULL;
1347
1348 return v->cwd;
1349}
1350
1351EXPORT_SYMBOL(vpe_getcwd);
1352
1353#ifdef CONFIG_MIPS_APSP_KSPD
1354static void kspd_sp_exit( int sp_id)
1355{
1356 cleanup_tc(get_tc(sp_id));
1357}
1358#endif
1359
1162static int __init vpe_module_init(void) 1360static int __init vpe_module_init(void)
1163{ 1361{
1164 struct vpe *v = NULL; 1362 struct vpe *v = NULL;
@@ -1201,7 +1399,8 @@ static int __init vpe_module_init(void)
1201 return -ENODEV; 1399 return -ENODEV;
1202 } 1400 }
1203 1401
1204 list_add(&t->tc, &v->tc); /* add the tc to the list of this vpe's tc's. */ 1402 /* add the tc to the list of this vpe's tc's. */
1403 list_add(&t->tc, &v->tc);
1205 1404
1206 /* deactivate all but vpe0 */ 1405 /* deactivate all but vpe0 */
1207 if (i != 0) { 1406 if (i != 0) {
@@ -1222,10 +1421,12 @@ static int __init vpe_module_init(void)
1222 ~(ST0_IM | ST0_IE | ST0_KSU)) 1421 ~(ST0_IM | ST0_IE | ST0_KSU))
1223 | ST0_CU0); 1422 | ST0_CU0);
1224 1423
1225 /* set config to be the same as vpe0, particularly kseg0 coherency alg */ 1424 /*
1425 * Set config to be the same as vpe0,
1426 * particularly kseg0 coherency alg
1427 */
1226 write_vpe_c0_config(read_c0_config()); 1428 write_vpe_c0_config(read_c0_config());
1227 } 1429 }
1228
1229 } 1430 }
1230 1431
1231 /* TC's */ 1432 /* TC's */
@@ -1234,23 +1435,28 @@ static int __init vpe_module_init(void)
1234 if (i != 0) { 1435 if (i != 0) {
1235 unsigned long tmp; 1436 unsigned long tmp;
1236 1437
1237 /* tc 0 will of course be running.... */
1238 if (i == 0)
1239 t->state = TC_STATE_RUNNING;
1240
1241 settc(i); 1438 settc(i);
1242 1439
1243 /* bind a TC to each VPE, May as well put all excess TC's 1440 /* Any TC that is bound to VPE0 gets left as is - in case
1244 on the last VPE */ 1441 we are running SMTC on VPE0. A TC that is bound to any
1245 if (i >= (((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1)) 1442 other VPE gets bound to VPE0, ideally I'd like to make
1246 write_tc_c0_tcbind(read_tc_c0_tcbind() | 1443 it homeless but it doesn't appear to let me bind a TC
1247 ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)); 1444 to a non-existent VPE. Which is perfectly reasonable.
1248 else 1445
1249 write_tc_c0_tcbind(read_tc_c0_tcbind() | i); 1446 The (un)bound state is visible to an EJTAG probe so may
1447 notify GDB...
1448 */
1449
1450 if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {
1451 /* tc is bound >vpe0 */
1452 write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
1453
1454 t->pvpe = get_vpe(0); /* set the parent vpe */
1455 }
1250 1456
1251 tmp = read_tc_c0_tcstatus(); 1457 tmp = read_tc_c0_tcstatus();
1252 1458
1253 /* mark not allocated and not dynamically allocatable */ 1459 /* mark not activated and not dynamically allocatable */
1254 tmp &= ~(TCSTATUS_A | TCSTATUS_DA); 1460 tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1255 tmp |= TCSTATUS_IXMT; /* interrupt exempt */ 1461 tmp |= TCSTATUS_IXMT; /* interrupt exempt */
1256 write_tc_c0_tcstatus(tmp); 1462 write_tc_c0_tcstatus(tmp);
@@ -1262,6 +1468,9 @@ static int __init vpe_module_init(void)
1262 /* release config state */ 1468 /* release config state */
1263 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1469 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1264 1470
1471#ifdef CONFIG_MIPS_APSP_KSPD
1472 kspd_events.kspd_sp_exit = kspd_sp_exit;
1473#endif
1265 return 0; 1474 return 0;
1266} 1475}
1267 1476
@@ -1281,5 +1490,5 @@ static void __exit vpe_module_exit(void)
1281module_init(vpe_module_init); 1490module_init(vpe_module_init);
1282module_exit(vpe_module_exit); 1491module_exit(vpe_module_exit);
1283MODULE_DESCRIPTION("MIPS VPE Loader"); 1492MODULE_DESCRIPTION("MIPS VPE Loader");
1284MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc"); 1493MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
1285MODULE_LICENSE("GPL"); 1494MODULE_LICENSE("GPL");
diff --git a/arch/mips/lasat/Makefile b/arch/mips/lasat/Makefile
index 0d5aec436725..99f5046fdf49 100644
--- a/arch/mips/lasat/Makefile
+++ b/arch/mips/lasat/Makefile
@@ -3,7 +3,7 @@
3# 3#
4 4
5obj-y += reset.o setup.o prom.o lasat_board.o \ 5obj-y += reset.o setup.o prom.o lasat_board.o \
6 at93c.o interrupt.o lasatIRQ.o 6 at93c.o interrupt.o
7 7
8obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o 8obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o
9obj-$(CONFIG_DS1603) += ds1603.o 9obj-$(CONFIG_DS1603) += ds1603.o
diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c
index 852a41901a5e..2d3472b21ebb 100644
--- a/arch/mips/lasat/interrupt.c
+++ b/arch/mips/lasat/interrupt.c
@@ -27,14 +27,13 @@
27#include <asm/bootinfo.h> 27#include <asm/bootinfo.h>
28#include <asm/irq.h> 28#include <asm/irq.h>
29#include <asm/lasat/lasatint.h> 29#include <asm/lasat/lasatint.h>
30#include <asm/time.h>
30#include <asm/gdb-stub.h> 31#include <asm/gdb-stub.h>
31 32
32static volatile int *lasat_int_status = NULL; 33static volatile int *lasat_int_status = NULL;
33static volatile int *lasat_int_mask = NULL; 34static volatile int *lasat_int_mask = NULL;
34static volatile int lasat_int_mask_shift; 35static volatile int lasat_int_mask_shift;
35 36
36extern asmlinkage void lasatIRQ(void);
37
38void disable_lasat_irq(unsigned int irq_nr) 37void disable_lasat_irq(unsigned int irq_nr)
39{ 38{
40 unsigned long flags; 39 unsigned long flags;
@@ -109,11 +108,17 @@ static unsigned long get_int_status_200(void)
109 return int_status; 108 return int_status;
110} 109}
111 110
112void lasat_hw0_irqdispatch(struct pt_regs *regs) 111asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
113{ 112{
114 unsigned long int_status; 113 unsigned long int_status;
114 unsigned int cause = read_c0_cause();
115 int irq; 115 int irq;
116 116
117 if (cause & CAUSEF_IP7) { /* R4000 count / compare IRQ */
118 ll_timer_interrupt(7, regs);
119 return;
120 }
121
117 int_status = get_int_status(); 122 int_status = get_int_status();
118 123
119 /* if int_status == 0, then the interrupt has already been cleared */ 124 /* if int_status == 0, then the interrupt has already been cleared */
@@ -147,9 +152,6 @@ void __init arch_init_irq(void)
147 panic("arch_init_irq: mips_machtype incorrect"); 152 panic("arch_init_irq: mips_machtype incorrect");
148 } 153 }
149 154
150 /* Now safe to set the exception vector. */
151 set_except_vector(0, lasatIRQ);
152
153 for (i = 0; i <= LASATINT_END; i++) { 155 for (i = 0; i <= LASATINT_END; i++) {
154 irq_desc[i].status = IRQ_DISABLED; 156 irq_desc[i].status = IRQ_DISABLED;
155 irq_desc[i].action = 0; 157 irq_desc[i].action = 0;
diff --git a/arch/mips/lasat/lasatIRQ.S b/arch/mips/lasat/lasatIRQ.S
deleted file mode 100644
index 2a2b0d056561..000000000000
--- a/arch/mips/lasat/lasatIRQ.S
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Interrupt exception dispatch code.
19 */
20#include <asm/asm.h>
21#include <asm/mipsregs.h>
22#include <asm/regdef.h>
23#include <asm/stackframe.h>
24
25 .text
26 .set noreorder
27 .align 5
28 NESTED(lasatIRQ, PT_SIZE, sp)
29 .set noat
30 SAVE_ALL
31 CLI
32 .set at
33 .set noreorder
34
35 mfc0 s0, CP0_CAUSE # get irq mask
36
37 /* First we check for r4k counter/timer IRQ. */
38 andi a0, s0, CAUSEF_IP7
39 beq a0, zero, 1f
40 andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt
41
42 /* Wheee, a timer interrupt. */
43 li a0, 7
44 jal ll_timer_interrupt
45 move a1, sp
46
47 j ret_from_irq
48 nop
49
501:
51 /* Wheee, combined hardware level zero interrupt. */
52 jal lasat_hw0_irqdispatch
53 move a0, sp # delay slot
54
55 j ret_from_irq
56 nop # delay slot
57
581:
59 /*
60 * Here by mistake? This is possible, what can happen is that by the
61 * time we take the exception the IRQ pin goes low, so just leave if
62 * this is the case.
63 */
64 move a1,s0
65 mfc0 a1, CP0_EPC
66
67 j ret_from_irq
68 nop
69 END(lasatIRQ)
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c
index bc0ebc69bfb3..db53950b7cfb 100644
--- a/arch/mips/mips-boards/atlas/atlas_int.c
+++ b/arch/mips/mips-boards/atlas/atlas_int.c
@@ -39,8 +39,6 @@
39 39
40static struct atlas_ictrl_regs *atlas_hw0_icregs; 40static struct atlas_ictrl_regs *atlas_hw0_icregs;
41 41
42extern asmlinkage void mipsIRQ(void);
43
44#if 0 42#if 0
45#define DEBUG_INT(x...) printk(x) 43#define DEBUG_INT(x...) printk(x)
46#else 44#else
@@ -98,7 +96,7 @@ static inline int ls1bit32(unsigned int x)
98 return b; 96 return b;
99} 97}
100 98
101void atlas_hw0_irqdispatch(struct pt_regs *regs) 99static inline void atlas_hw0_irqdispatch(struct pt_regs *regs)
102{ 100{
103 unsigned long int_status; 101 unsigned long int_status;
104 int irq; 102 int irq;
@@ -116,6 +114,91 @@ void atlas_hw0_irqdispatch(struct pt_regs *regs)
116 do_IRQ(irq, regs); 114 do_IRQ(irq, regs);
117} 115}
118 116
117static inline int clz(unsigned long x)
118{
119 __asm__ (
120 " .set push \n"
121 " .set mips32 \n"
122 " clz %0, %1 \n"
123 " .set pop \n"
124 : "=r" (x)
125 : "r" (x));
126
127 return x;
128}
129
130/*
131 * Version of ffs that only looks at bits 12..15.
132 */
133static inline unsigned int irq_ffs(unsigned int pending)
134{
135#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
136 return -clz(pending) + 31 - CAUSEB_IP;
137#else
138 unsigned int a0 = 7;
139 unsigned int t0;
140
141 t0 = s0 & 0xf000;
142 t0 = t0 < 1;
143 t0 = t0 << 2;
144 a0 = a0 - t0;
145 s0 = s0 << t0;
146
147 t0 = s0 & 0xc000;
148 t0 = t0 < 1;
149 t0 = t0 << 1;
150 a0 = a0 - t0;
151 s0 = s0 << t0;
152
153 t0 = s0 & 0x8000;
154 t0 = t0 < 1;
155 //t0 = t0 << 2;
156 a0 = a0 - t0;
157 //s0 = s0 << t0;
158
159 return a0;
160#endif
161}
162
163/*
164 * IRQs on the Atlas board look basically (barring software IRQs which we
165 * don't use at all and all external interrupt sources are combined together
166 * on hardware interrupt 0 (MIPS IRQ 2)) like:
167 *
168 * MIPS IRQ Source
169 * -------- ------
170 * 0 Software (ignored)
171 * 1 Software (ignored)
172 * 2 Combined hardware interrupt (hw0)
173 * 3 Hardware (ignored)
174 * 4 Hardware (ignored)
175 * 5 Hardware (ignored)
176 * 6 Hardware (ignored)
177 * 7 R4k timer (what we use)
178 *
179 * We handle the IRQ according to _our_ priority which is:
180 *
181 * Highest ---- R4k Timer
182 * Lowest ---- Combined hardware interrupt
183 *
184 * then we just return, if multiple IRQs are pending then we will just take
185 * another exception, big deal.
186 */
187asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
188{
189 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
190 int irq;
191
192 irq = irq_ffs(pending);
193
194 if (irq == MIPSCPU_INT_ATLAS)
195 atlas_hw0_irqdispatch(regs);
196 else if (irq > 0)
197 do_IRQ(MIPSCPU_INT_BASE + irq, regs);
198 else
199 spurious_interrupt(regs);
200}
201
119void __init arch_init_irq(void) 202void __init arch_init_irq(void)
120{ 203{
121 int i; 204 int i;
@@ -128,9 +211,6 @@ void __init arch_init_irq(void)
128 */ 211 */
129 atlas_hw0_icregs->intrsten = 0xffffffff; 212 atlas_hw0_icregs->intrsten = 0xffffffff;
130 213
131 /* Now safe to set the exception vector. */
132 set_except_vector(0, mipsIRQ);
133
134 for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) { 214 for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) {
135 irq_desc[i].status = IRQ_DISABLED; 215 irq_desc[i].status = IRQ_DISABLED;
136 irq_desc[i].action = 0; 216 irq_desc[i].action = 0;
diff --git a/arch/mips/mips-boards/generic/Makefile b/arch/mips/mips-boards/generic/Makefile
index b21bc6887fa8..be47c1c2bc80 100644
--- a/arch/mips/mips-boards/generic/Makefile
+++ b/arch/mips/mips-boards/generic/Makefile
@@ -18,8 +18,8 @@
18# Makefile for the MIPS boards generic routines under Linux. 18# Makefile for the MIPS boards generic routines under Linux.
19# 19#
20 20
21obj-y := mipsIRQ.o reset.o display.o init.o memory.o \ 21obj-y := reset.o display.o init.o memory.o printf.o \
22 printf.o cmdline.o time.o 22 cmdline.o time.o
23obj-$(CONFIG_PCI) += pci.o 23obj-$(CONFIG_PCI) += pci.o
24obj-$(CONFIG_KGDB) += gdb_hook.o 24obj-$(CONFIG_KGDB) += gdb_hook.o
25 25
diff --git a/arch/mips/mips-boards/generic/gdb_hook.c b/arch/mips/mips-boards/generic/gdb_hook.c
index 91a2ccbe3730..6a1854de4579 100644
--- a/arch/mips/mips-boards/generic/gdb_hook.c
+++ b/arch/mips/mips-boards/generic/gdb_hook.c
@@ -25,7 +25,7 @@
25#include <asm/serial.h> 25#include <asm/serial.h>
26#include <asm/io.h> 26#include <asm/io.h>
27 27
28static struct serial_state rs_table[RS_TABLE_SIZE] = { 28static struct serial_state rs_table[] = {
29 SERIAL_PORT_DFNS /* Defined in serial.h */ 29 SERIAL_PORT_DFNS /* Defined in serial.h */
30}; 30};
31 31
diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c
index eab5a705e989..17dfe6a8cab9 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)
220 generic_putDebugChar (*s++); 220 generic_putDebugChar (*s++);
221 } 221 }
222 222
223 kgdb_enabled = 1;
224 /* Breakpoint is invoked after interrupts are initialised */ 223 /* Breakpoint is invoked after interrupts are initialised */
225 } 224 }
226} 225}
diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c
index 32c9210373ac..bc4d093685bb 100644
--- a/arch/mips/mips-boards/generic/memory.c
+++ b/arch/mips/mips-boards/generic/memory.c
@@ -22,10 +22,12 @@
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/mm.h> 23#include <linux/mm.h>
24#include <linux/bootmem.h> 24#include <linux/bootmem.h>
25#include <linux/pfn.h>
25#include <linux/string.h> 26#include <linux/string.h>
26 27
27#include <asm/bootinfo.h> 28#include <asm/bootinfo.h>
28#include <asm/page.h> 29#include <asm/page.h>
30#include <asm/sections.h>
29 31
30#include <asm/mips-boards/prom.h> 32#include <asm/mips-boards/prom.h>
31 33
@@ -46,9 +48,6 @@ static char *mtypes[3] = {
46}; 48};
47#endif 49#endif
48 50
49/* References to section boundaries */
50extern char _end;
51
52struct prom_pmemblock * __init prom_getmdesc(void) 51struct prom_pmemblock * __init prom_getmdesc(void)
53{ 52{
54 char *memsize_str; 53 char *memsize_str;
@@ -106,10 +105,10 @@ struct prom_pmemblock * __init prom_getmdesc(void)
106 105
107 mdesc[3].type = yamon_dontuse; 106 mdesc[3].type = yamon_dontuse;
108 mdesc[3].base = 0x00100000; 107 mdesc[3].base = 0x00100000;
109 mdesc[3].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[3].base; 108 mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) - mdesc[3].base;
110 109
111 mdesc[4].type = yamon_free; 110 mdesc[4].type = yamon_free;
112 mdesc[4].base = CPHYSADDR(PAGE_ALIGN(&_end)); 111 mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
113 mdesc[4].size = memsize - mdesc[4].base; 112 mdesc[4].size = memsize - mdesc[4].base;
114 113
115 return &mdesc[0]; 114 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 ddd5c73a2971..000000000000
--- a/arch/mips/mips-boards/generic/mipsIRQ.S
+++ /dev/null
@@ -1,155 +0,0 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * ########################################################################
6 *
7 * This program is free software; you can distribute it and/or modify it
8 * under the terms of the GNU General Public License (Version 2) as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19 *
20 * ########################################################################
21 *
22 * Interrupt exception dispatch code.
23 *
24 */
25#include <linux/config.h>
26
27#include <asm/asm.h>
28#include <asm/mipsregs.h>
29#include <asm/regdef.h>
30#include <asm/stackframe.h>
31
32#ifdef CONFIG_MIPS_ATLAS
33#include <asm/mips-boards/atlasint.h>
34#define CASCADE_IRQ MIPSCPU_INT_ATLAS
35#define CASCADE_DISPATCH atlas_hw0_irqdispatch
36#endif
37#ifdef CONFIG_MIPS_MALTA
38#include <asm/mips-boards/maltaint.h>
39#define CASCADE_IRQ MIPSCPU_INT_I8259A
40#define CASCADE_DISPATCH malta_hw0_irqdispatch
41#endif
42#ifdef CONFIG_MIPS_SEAD
43#include <asm/mips-boards/seadint.h>
44#endif
45
46/* A lot of complication here is taken away because:
47 *
48 * 1) We handle one interrupt and return, sitting in a loop and moving across
49 * all the pending IRQ bits in the cause register is _NOT_ the answer, the
50 * common case is one pending IRQ so optimize in that direction.
51 *
52 * 2) We need not check against bits in the status register IRQ mask, that
53 * would make this routine slow as hell.
54 *
55 * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
56 * between like BSD spl() brain-damage.
57 *
58 * Furthermore, the IRQs on the MIPS board look basically (barring software
59 * IRQs which we don't use at all and all external interrupt sources are
60 * combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
61 *
62 * MIPS IRQ Source
63 * -------- ------
64 * 0 Software (ignored)
65 * 1 Software (ignored)
66 * 2 Combined hardware interrupt (hw0)
67 * 3 Hardware (ignored)
68 * 4 Hardware (ignored)
69 * 5 Hardware (ignored)
70 * 6 Hardware (ignored)
71 * 7 R4k timer (what we use)
72 *
73 * Note: On the SEAD board thing are a little bit different.
74 * Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
75 * wired to UART1.
76 *
77 * We handle the IRQ according to _our_ priority which is:
78 *
79 * Highest ---- R4k Timer
80 * Lowest ---- Combined hardware interrupt
81 *
82 * then we just return, if multiple IRQs are pending then we will just take
83 * another exception, big deal.
84 */
85
86 .text
87 .set noreorder
88 .set noat
89 .align 5
90 NESTED(mipsIRQ, PT_SIZE, sp)
91 SAVE_ALL
92 CLI
93 .set at
94
95 mfc0 s0, CP0_CAUSE # get irq bits
96 mfc0 s1, CP0_STATUS # get irq mask
97 andi s0, ST0_IM # CAUSE.CE may be non-zero!
98 and s0, s1
99
100#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
101 .set mips32
102 clz a0, s0
103 .set mips0
104 negu a0
105 addu a0, 31-CAUSEB_IP
106 bltz a0, spurious
107#else
108 beqz s0, spurious
109 li a0, 7
110
111 and t0, s0, 0xf000
112 sltiu t0, t0, 1
113 sll t0, 2
114 subu a0, t0
115 sll s0, t0
116
117 and t0, s0, 0xc000
118 sltiu t0, t0, 1
119 sll t0, 1
120 subu a0, t0
121 sll s0, t0
122
123 and t0, s0, 0x8000
124 sltiu t0, t0, 1
125 # sll t0, 0
126 subu a0, t0
127 # sll s0, t0
128#endif
129
130#ifdef CASCADE_IRQ
131 li a1, CASCADE_IRQ
132 bne a0, a1, 1f
133 addu a0, MIPSCPU_INT_BASE
134
135 jal CASCADE_DISPATCH
136 move a0, sp
137
138 j ret_from_irq
139 nop
1401:
141#else
142 addu a0, MIPSCPU_INT_BASE
143#endif
144
145 jal do_IRQ
146 move a1, sp
147
148 j ret_from_irq
149 nop
150
151
152spurious:
153 j spurious_interrupt
154 nop
155 END(mipsIRQ)
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 93f3bf2c2b22..a9f6124b3a22 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -30,6 +30,7 @@
30#include <linux/mc146818rtc.h> 30#include <linux/mc146818rtc.h>
31 31
32#include <asm/mipsregs.h> 32#include <asm/mipsregs.h>
33#include <asm/mipsmtregs.h>
33#include <asm/ptrace.h> 34#include <asm/ptrace.h>
34#include <asm/hardirq.h> 35#include <asm/hardirq.h>
35#include <asm/irq.h> 36#include <asm/irq.h>
@@ -50,16 +51,23 @@ unsigned long cpu_khz;
50static char display_string[] = " LINUX ON ATLAS "; 51static char display_string[] = " LINUX ON ATLAS ";
51#endif 52#endif
52#if defined(CONFIG_MIPS_MALTA) 53#if defined(CONFIG_MIPS_MALTA)
54#if defined(CONFIG_MIPS_MT_SMTC)
55static char display_string[] = " SMTC LINUX ON MALTA ";
56#else
53static char display_string[] = " LINUX ON MALTA "; 57static char display_string[] = " LINUX ON MALTA ";
58#endif /* CONFIG_MIPS_MT_SMTC */
54#endif 59#endif
55#if defined(CONFIG_MIPS_SEAD) 60#if defined(CONFIG_MIPS_SEAD)
56static char display_string[] = " LINUX ON SEAD "; 61static char display_string[] = " LINUX ON SEAD ";
57#endif 62#endif
58static unsigned int display_count = 0; 63static unsigned int display_count;
59#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) 64#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8)
60 65
61static unsigned int timer_tick_count=0; 66#define CPUCTR_IMASKBIT (0x100 << MIPSCPU_INT_CPUCTR)
67
68static unsigned int timer_tick_count;
62static int mips_cpu_timer_irq; 69static int mips_cpu_timer_irq;
70extern void smtc_timer_broadcast(int);
63 71
64static inline void scroll_display_message(void) 72static inline void scroll_display_message(void)
65{ 73{
@@ -75,15 +83,55 @@ static void mips_timer_dispatch (struct pt_regs *regs)
75 do_IRQ (mips_cpu_timer_irq, regs); 83 do_IRQ (mips_cpu_timer_irq, regs);
76} 84}
77 85
86/*
87 * Redeclare until I get around mopping the timer code insanity on MIPS.
88 */
78extern int null_perf_irq(struct pt_regs *regs); 89extern int null_perf_irq(struct pt_regs *regs);
79 90
80extern int (*perf_irq)(struct pt_regs *regs); 91extern int (*perf_irq)(struct pt_regs *regs);
81 92
82irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 93irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
83{ 94{
84 int r2 = cpu_has_mips_r2;
85 int cpu = smp_processor_id(); 95 int cpu = smp_processor_id();
96 int r2 = cpu_has_mips_r2;
97
98#ifdef CONFIG_MIPS_MT_SMTC
99 /*
100 * In an SMTC system, one Count/Compare set exists per VPE.
101 * Which TC within a VPE gets the interrupt is essentially
102 * random - we only know that it shouldn't be one with
103 * IXMT set. Whichever TC gets the interrupt needs to
104 * send special interprocessor interrupts to the other
105 * TCs to make sure that they schedule, etc.
106 *
107 * That code is specific to the SMTC kernel, not to
108 * the a particular platform, so it's invoked from
109 * the general MIPS timer_interrupt routine.
110 */
111
112 /*
113 * DVPE is necessary so long as cross-VPE interrupts
114 * are done via read-modify-write of Cause register.
115 */
116 int vpflags = dvpe();
117 write_c0_compare (read_c0_count() - 1);
118 clear_c0_cause(CPUCTR_IMASKBIT);
119 evpe(vpflags);
120
121 if (cpu_data[cpu].vpe_id == 0) {
122 timer_interrupt(irq, dev_id, regs);
123 scroll_display_message();
124 } else
125 write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
126 smtc_timer_broadcast(cpu_data[cpu].vpe_id);
86 127
128 if (cpu != 0)
129 /*
130 * Other CPUs should do profiling and process accounting
131 */
132 local_timer_interrupt(irq, dev_id, regs);
133
134#else /* CONFIG_MIPS_MT_SMTC */
87 if (cpu == 0) { 135 if (cpu == 0) {
88 /* 136 /*
89 * CPU 0 handles the global timer interrupt job and process 137 * 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)
107 * More support needs to be added to kernel/time for 155 * More support needs to be added to kernel/time for
108 * counter/timer interrupts on multiple CPU's 156 * counter/timer interrupts on multiple CPU's
109 */ 157 */
110 write_c0_compare (read_c0_count() + (mips_hpt_frequency/HZ)); 158 write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
159
111 /* 160 /*
112 * other CPUs should do profiling and process accounting 161 * Other CPUs should do profiling and process accounting
113 */ 162 */
114 local_timer_interrupt (irq, dev_id, regs); 163 local_timer_interrupt(irq, dev_id, regs);
115 } 164 }
165#endif /* CONFIG_MIPS_MT_SMTC */
116 166
117out: 167out:
118 return IRQ_HANDLED; 168 return IRQ_HANDLED;
@@ -126,7 +176,7 @@ static unsigned int __init estimate_cpu_frequency(void)
126 unsigned int prid = read_c0_prid() & 0xffff00; 176 unsigned int prid = read_c0_prid() & 0xffff00;
127 unsigned int count; 177 unsigned int count;
128 178
129#ifdef CONFIG_MIPS_SEAD 179#if defined(CONFIG_MIPS_SEAD) || defined(CONFIG_MIPS_SIM)
130 /* 180 /*
131 * The SEAD board doesn't have a real time clock, so we can't 181 * The SEAD board doesn't have a real time clock, so we can't
132 * really calculate the timer frequency 182 * really calculate the timer frequency
@@ -211,7 +261,11 @@ void __init mips_timer_setup(struct irqaction *irq)
211 261
212 /* we are using the cpu counter for timer interrupts */ 262 /* we are using the cpu counter for timer interrupts */
213 irq->handler = mips_timer_interrupt; /* we use our own handler */ 263 irq->handler = mips_timer_interrupt; /* we use our own handler */
264#ifdef CONFIG_MIPS_MT_SMTC
265 setup_irq_smtc(mips_cpu_timer_irq, irq, CPUCTR_IMASKBIT);
266#else
214 setup_irq(mips_cpu_timer_irq, irq); 267 setup_irq(mips_cpu_timer_irq, irq);
268#endif /* CONFIG_MIPS_MT_SMTC */
215 269
216#ifdef CONFIG_SMP 270#ifdef CONFIG_SMP
217 /* irq_desc(riptor) is a global resource, when the interrupt overlaps 271 /* 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 fd4c143c0e2f..77ee5c6d33c1 100644
--- a/arch/mips/mips-boards/malta/Makefile
+++ b/arch/mips/mips-boards/malta/Makefile
@@ -20,3 +20,4 @@
20# 20#
21 21
22obj-y := malta_int.o malta_setup.o 22obj-y := malta_int.o malta_setup.o
23obj-$(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 d06dc5ad6c9e..64db07d4dbe5 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -40,7 +40,6 @@
40#include <asm/mips-boards/msc01_pci.h> 40#include <asm/mips-boards/msc01_pci.h>
41#include <asm/msc01_ic.h> 41#include <asm/msc01_ic.h>
42 42
43extern asmlinkage void mipsIRQ(void);
44extern void mips_timer_interrupt(void); 43extern void mips_timer_interrupt(void);
45 44
46static DEFINE_SPINLOCK(mips_irq_lock); 45static DEFINE_SPINLOCK(mips_irq_lock);
@@ -114,13 +113,14 @@ static inline int get_int(void)
114 return irq; 113 return irq;
115} 114}
116 115
117void malta_hw0_irqdispatch(struct pt_regs *regs) 116static void malta_hw0_irqdispatch(struct pt_regs *regs)
118{ 117{
119 int irq; 118 int irq;
120 119
121 irq = get_int(); 120 irq = get_int();
122 if (irq < 0) 121 if (irq < 0) {
123 return; /* interrupt has already been cleared */ 122 return; /* interrupt has already been cleared */
123 }
124 124
125 do_IRQ(MALTA_INT_BASE+irq, regs); 125 do_IRQ(MALTA_INT_BASE+irq, regs);
126} 126}
@@ -182,6 +182,92 @@ void corehi_irqdispatch(struct pt_regs *regs)
182 die("CoreHi interrupt", regs); 182 die("CoreHi interrupt", regs);
183} 183}
184 184
185static inline int clz(unsigned long x)
186{
187 __asm__ (
188 " .set push \n"
189 " .set mips32 \n"
190 " clz %0, %1 \n"
191 " .set pop \n"
192 : "=r" (x)
193 : "r" (x));
194
195 return x;
196}
197
198/*
199 * Version of ffs that only looks at bits 12..15.
200 */
201static inline unsigned int irq_ffs(unsigned int pending)
202{
203#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
204 return -clz(pending) + 31 - CAUSEB_IP;
205#else
206 unsigned int a0 = 7;
207 unsigned int t0;
208
209 t0 = s0 & 0xf000;
210 t0 = t0 < 1;
211 t0 = t0 << 2;
212 a0 = a0 - t0;
213 s0 = s0 << t0;
214
215 t0 = s0 & 0xc000;
216 t0 = t0 < 1;
217 t0 = t0 << 1;
218 a0 = a0 - t0;
219 s0 = s0 << t0;
220
221 t0 = s0 & 0x8000;
222 t0 = t0 < 1;
223 //t0 = t0 << 2;
224 a0 = a0 - t0;
225 //s0 = s0 << t0;
226
227 return a0;
228#endif
229}
230
231/*
232 * IRQs on the Malta board look basically (barring software IRQs which we
233 * don't use at all and all external interrupt sources are combined together
234 * on hardware interrupt 0 (MIPS IRQ 2)) like:
235 *
236 * MIPS IRQ Source
237 * -------- ------
238 * 0 Software (ignored)
239 * 1 Software (ignored)
240 * 2 Combined hardware interrupt (hw0)
241 * 3 Hardware (ignored)
242 * 4 Hardware (ignored)
243 * 5 Hardware (ignored)
244 * 6 Hardware (ignored)
245 * 7 R4k timer (what we use)
246 *
247 * We handle the IRQ according to _our_ priority which is:
248 *
249 * Highest ---- R4k Timer
250 * Lowest ---- Combined hardware interrupt
251 *
252 * then we just return, if multiple IRQs are pending then we will just take
253 * another exception, big deal.
254 */
255
256asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
257{
258 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
259 int irq;
260
261 irq = irq_ffs(pending);
262
263 if (irq == MIPSCPU_INT_I8259A)
264 malta_hw0_irqdispatch(regs);
265 else if (irq > 0)
266 do_IRQ(MIPSCPU_INT_BASE + irq, regs);
267 else
268 spurious_interrupt(regs);
269}
270
185static struct irqaction i8259irq = { 271static struct irqaction i8259irq = {
186 .handler = no_action, 272 .handler = no_action,
187 .name = "XT-PIC cascade" 273 .name = "XT-PIC cascade"
@@ -214,7 +300,6 @@ int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t);
214 300
215void __init arch_init_irq(void) 301void __init arch_init_irq(void)
216{ 302{
217 set_except_vector(0, mipsIRQ);
218 init_i8259_irqs(); 303 init_i8259_irqs();
219 304
220 if (!cpu_has_veic) 305 if (!cpu_has_veic)
@@ -240,12 +325,17 @@ void __init arch_init_irq(void)
240 else if (cpu_has_vint) { 325 else if (cpu_has_vint) {
241 set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); 326 set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
242 set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch); 327 set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch);
243 328#ifdef CONFIG_MIPS_MT_SMTC
329 setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq,
330 (0x100 << MIPSCPU_INT_I8259A));
331 setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI,
332 &corehi_irqaction, (0x100 << MIPSCPU_INT_COREHI));
333#else /* Not SMTC */
244 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq); 334 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
245 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); 335 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
336#endif /* CONFIG_MIPS_MT_SMTC */
246 } 337 }
247 else { 338 else {
248 set_except_vector(0, mipsIRQ);
249 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq); 339 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
250 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); 340 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
251 } 341 }
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 000000000000..6c6c8eeedbce
--- /dev/null
+++ b/arch/mips/mips-boards/malta/malta_smp.c
@@ -0,0 +1,128 @@
1/*
2 * Malta Platform-specific hooks for SMP operation
3 */
4
5#include <linux/kernel.h>
6#include <linux/sched.h>
7#include <linux/cpumask.h>
8#include <linux/interrupt.h>
9
10#include <asm/atomic.h>
11#include <asm/cpu.h>
12#include <asm/processor.h>
13#include <asm/system.h>
14#include <asm/hardirq.h>
15#include <asm/mmu_context.h>
16#include <asm/smp.h>
17#ifdef CONFIG_MIPS_MT_SMTC
18#include <asm/smtc_ipi.h>
19#endif /* CONFIG_MIPS_MT_SMTC */
20
21/* VPE/SMP Prototype implements platform interfaces directly */
22#if !defined(CONFIG_MIPS_MT_SMP)
23
24/*
25 * Cause the specified action to be performed on a targeted "CPU"
26 */
27
28void core_send_ipi(int cpu, unsigned int action)
29{
30/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
31#ifdef CONFIG_MIPS_MT_SMTC
32 smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
33#endif /* CONFIG_MIPS_MT_SMTC */
34}
35
36/*
37 * Detect available CPUs/VPEs/TCs and populate phys_cpu_present_map
38 */
39
40void __init prom_build_cpu_map(void)
41{
42 int nextslot;
43
44 /*
45 * As of November, 2004, MIPSsim only simulates one core
46 * at a time. However, that core may be a MIPS MT core
47 * with multiple virtual processors and thread contexts.
48 */
49
50 if (read_c0_config3() & (1<<2)) {
51 nextslot = mipsmt_build_cpu_map(1);
52 }
53}
54
55/*
56 * Platform "CPU" startup hook
57 */
58
59void prom_boot_secondary(int cpu, struct task_struct *idle)
60{
61#ifdef CONFIG_MIPS_MT_SMTC
62 smtc_boot_secondary(cpu, idle);
63#endif /* CONFIG_MIPS_MT_SMTC */
64}
65
66/*
67 * Post-config but pre-boot cleanup entry point
68 */
69
70void prom_init_secondary(void)
71{
72#ifdef CONFIG_MIPS_MT_SMTC
73 void smtc_init_secondary(void);
74 int myvpe;
75
76 /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
77 myvpe = read_c0_tcbind() & TCBIND_CURVPE;
78 if (myvpe != 0) {
79 /* Ideally, this should be done only once per VPE, but... */
80 clear_c0_status(STATUSF_IP2);
81 set_c0_status(STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP3
82 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6
83 | STATUSF_IP7);
84 }
85
86 smtc_init_secondary();
87#endif /* CONFIG_MIPS_MT_SMTC */
88}
89
90/*
91 * Platform SMP pre-initialization
92 *
93 * As noted above, we can assume a single CPU for now
94 * but it may be multithreaded.
95 */
96
97void plat_smp_setup(void)
98{
99 if (read_c0_config3() & (1<<2))
100 mipsmt_build_cpu_map(0);
101}
102
103void __init plat_prepare_cpus(unsigned int max_cpus)
104{
105 if (read_c0_config3() & (1<<2))
106 mipsmt_prepare_cpus();
107}
108
109/*
110 * SMP initialization finalization entry point
111 */
112
113void prom_smp_finish(void)
114{
115#ifdef CONFIG_MIPS_MT_SMTC
116 smtc_smp_finish();
117#endif /* CONFIG_MIPS_MT_SMTC */
118}
119
120/*
121 * Hook for after all CPUs are online
122 */
123
124void prom_cpus_done(void)
125{
126}
127
128#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 90fda0d9915f..9168d934c661 100644
--- a/arch/mips/mips-boards/sead/sead_int.c
+++ b/arch/mips/mips-boards/sead/sead_int.c
@@ -24,16 +24,94 @@
24#include <linux/irq.h> 24#include <linux/irq.h>
25 25
26#include <asm/irq_cpu.h> 26#include <asm/irq_cpu.h>
27#include <asm/mipsregs.h>
27#include <asm/system.h> 28#include <asm/system.h>
28 29
29#include <asm/mips-boards/seadint.h> 30#include <asm/mips-boards/seadint.h>
30 31
31extern asmlinkage void mipsIRQ(void); 32static inline int clz(unsigned long x)
33{
34 __asm__ (
35 " .set push \n"
36 " .set mips32 \n"
37 " clz %0, %1 \n"
38 " .set pop \n"
39 : "=r" (x)
40 : "r" (x));
41
42 return x;
43}
44
45/*
46 * Version of ffs that only looks at bits 12..15.
47 */
48static inline unsigned int irq_ffs(unsigned int pending)
49{
50#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
51 return -clz(pending) + 31 - CAUSEB_IP;
52#else
53 unsigned int a0 = 7;
54 unsigned int t0;
55
56 t0 = s0 & 0xf000;
57 t0 = t0 < 1;
58 t0 = t0 << 2;
59 a0 = a0 - t0;
60 s0 = s0 << t0;
61
62 t0 = s0 & 0xc000;
63 t0 = t0 < 1;
64 t0 = t0 << 1;
65 a0 = a0 - t0;
66 s0 = s0 << t0;
67
68 t0 = s0 & 0x8000;
69 t0 = t0 < 1;
70 //t0 = t0 << 2;
71 a0 = a0 - t0;
72 //s0 = s0 << t0;
73
74 return a0;
75#endif
76}
77
78/*
79 * IRQs on the SEAD board look basically are combined together on hardware
80 * interrupt 0 (MIPS IRQ 2)) like:
81 *
82 * MIPS IRQ Source
83 * -------- ------
84 * 0 Software (ignored)
85 * 1 Software (ignored)
86 * 2 UART0 (hw0)
87 * 3 UART1 (hw1)
88 * 4 Hardware (ignored)
89 * 5 Hardware (ignored)
90 * 6 Hardware (ignored)
91 * 7 R4k timer (what we use)
92 *
93 * We handle the IRQ according to _our_ priority which is:
94 *
95 * Highest ---- R4k Timer
96 * Lowest ---- Combined hardware interrupt
97 *
98 * then we just return, if multiple IRQs are pending then we will just take
99 * another exception, big deal.
100 */
101asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
102{
103 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
104 int irq;
105
106 irq = irq_ffs(pending);
107
108 if (irq >= 0)
109 do_IRQ(MIPSCPU_INT_BASE + irq, regs);
110 else
111 spurious_interrupt(regs);
112}
32 113
33void __init arch_init_irq(void) 114void __init arch_init_irq(void)
34{ 115{
35 mips_cpu_irq_init(MIPSCPU_INT_BASE); 116 mips_cpu_irq_init(MIPSCPU_INT_BASE);
36
37 /* Now safe to set the exception vector. */
38 set_except_vector(0, mipsIRQ);
39} 117}
diff --git a/arch/mips/mips-boards/sim/cmdline.c b/arch/mips/mips-boards/sim/cmdline.c
deleted file mode 100644
index fef9fbd8e710..000000000000
--- a/arch/mips/mips-boards/sim/cmdline.c
+++ /dev/null
@@ -1,59 +0,0 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Kernel command line creation using the prom monitor (YAMON) argc/argv.
19 */
20#include <linux/init.h>
21#include <linux/string.h>
22
23#include <asm/bootinfo.h>
24
25extern int prom_argc;
26extern int *_prom_argv;
27
28/*
29 * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
30 * This macro take care of sign extension.
31 */
32#define prom_argv(index) ((char *)(((int *)(int)_prom_argv)[(index)]))
33
34char arcs_cmdline[CL_SIZE];
35
36char * __init prom_getcmdline(void)
37{
38 return &(arcs_cmdline[0]);
39}
40
41
42void __init prom_init_cmdline(void)
43{
44 char *cp;
45 int actr;
46
47 actr = 1; /* Always ignore argv[0] */
48
49 cp = &(arcs_cmdline[0]);
50 while(actr < prom_argc) {
51 strcpy(cp, prom_argv(actr));
52 cp += strlen(prom_argv(actr));
53 *cp++ = ' ';
54 actr++;
55 }
56 if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
57 --cp;
58 *cp = '\0';
59}
diff --git a/arch/mips/mips-boards/sim/sim_cmdline.c b/arch/mips/mips-boards/sim/sim_cmdline.c
index 9df37c6fca36..c63021a5dc6c 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)
26 return arcs_cmdline; 26 return arcs_cmdline;
27} 27}
28 28
29
30void __init prom_init_cmdline(void) 29void __init prom_init_cmdline(void)
31{ 30{
32 /* nothing to do */ 31 char *cp;
32 cp = arcs_cmdline;
33 /* Get boot line from environment? */
34 *cp = '\0';
33} 35}
diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c
index a4d0a2c05031..2c15c8efec4e 100644
--- a/arch/mips/mips-boards/sim/sim_int.c
+++ b/arch/mips/mips-boards/sim/sim_int.c
@@ -25,17 +25,71 @@
25 25
26extern void mips_cpu_irq_init(int); 26extern void mips_cpu_irq_init(int);
27 27
28extern asmlinkage void simIRQ(void); 28static inline int clz(unsigned long x)
29{
30 __asm__ (
31 " .set push \n"
32 " .set mips32 \n"
33 " clz %0, %1 \n"
34 " .set pop \n"
35 : "=r" (x)
36 : "r" (x));
37
38 return x;
39}
40
41/*
42 * Version of ffs that only looks at bits 12..15.
43 */
44static inline unsigned int irq_ffs(unsigned int pending)
45{
46#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
47 return -clz(pending) + 31 - CAUSEB_IP;
48#else
49 unsigned int a0 = 7;
50 unsigned int t0;
51
52 t0 = s0 & 0xf000;
53 t0 = t0 < 1;
54 t0 = t0 << 2;
55 a0 = a0 - t0;
56 s0 = s0 << t0;
57
58 t0 = s0 & 0xc000;
59 t0 = t0 < 1;
60 t0 = t0 << 1;
61 a0 = a0 - t0;
62 s0 = s0 << t0;
29 63
30asmlinkage void sim_hw0_irqdispatch(struct pt_regs *regs) 64 t0 = s0 & 0x8000;
65 t0 = t0 < 1;
66 //t0 = t0 << 2;
67 a0 = a0 - t0;
68 //s0 = s0 << t0;
69
70 return a0;
71#endif
72}
73
74static inline void sim_hw0_irqdispatch(struct pt_regs *regs)
31{ 75{
32 do_IRQ(2, regs); 76 do_IRQ(2, regs);
33} 77}
34 78
35void __init arch_init_irq(void) 79asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
36{ 80{
37 /* Now safe to set the exception vector. */ 81 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
38 set_except_vector(0, simIRQ); 82 int irq;
83
84 irq = irq_ffs(pending);
39 85
86 if (irq > 0)
87 do_IRQ(MIPSCPU_INT_BASE + irq, regs);
88 else
89 spurious_interrupt(regs);
90}
91
92void __init arch_init_irq(void)
93{
40 mips_cpu_irq_init(MIPSCPU_INT_BASE); 94 mips_cpu_irq_init(MIPSCPU_INT_BASE);
41} 95}
diff --git a/arch/mips/mips-boards/sim/sim_irq.S b/arch/mips/mips-boards/sim/sim_irq.S
index da52297a2216..d16cf3822076 100644
--- a/arch/mips/mips-boards/sim/sim_irq.S
+++ b/arch/mips/mips-boards/sim/sim_irq.S
@@ -94,6 +94,8 @@
94 94
95 95
96spurious: 96spurious:
97 j spurious_interrupt 97 jal spurious_interrupt
98 nop
99 j ret_from_irq
98 nop 100 nop
99 END(simIRQ) 101 END(simIRQ)
diff --git a/arch/mips/mips-boards/sim/sim_mem.c b/arch/mips/mips-boards/sim/sim_mem.c
index e57f737bab10..f7ce76983328 100644
--- a/arch/mips/mips-boards/sim/sim_mem.c
+++ b/arch/mips/mips-boards/sim/sim_mem.c
@@ -18,9 +18,11 @@
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/mm.h> 19#include <linux/mm.h>
20#include <linux/bootmem.h> 20#include <linux/bootmem.h>
21#include <linux/pfn.h>
21 22
22#include <asm/bootinfo.h> 23#include <asm/bootinfo.h>
23#include <asm/page.h> 24#include <asm/page.h>
25#include <asm/sections.h>
24 26
25#include <asm/mips-boards/prom.h> 27#include <asm/mips-boards/prom.h>
26 28
@@ -39,9 +41,6 @@ static char *mtypes[3] = {
39}; 41};
40#endif 42#endif
41 43
42/* References to section boundaries */
43extern char _end;
44
45struct prom_pmemblock * __init prom_getmdesc(void) 44struct prom_pmemblock * __init prom_getmdesc(void)
46{ 45{
47 unsigned int memsize; 46 unsigned int memsize;
@@ -61,10 +60,10 @@ struct prom_pmemblock * __init prom_getmdesc(void)
61 60
62 mdesc[2].type = simmem_reserved; 61 mdesc[2].type = simmem_reserved;
63 mdesc[2].base = 0x00100000; 62 mdesc[2].base = 0x00100000;
64 mdesc[2].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[2].base; 63 mdesc[2].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[2].base;
65 64
66 mdesc[3].type = simmem_free; 65 mdesc[3].type = simmem_free;
67 mdesc[3].base = CPHYSADDR(PAGE_ALIGN(&_end)); 66 mdesc[3].base = CPHYSADDR(PFN_ALIGN(&_end));
68 mdesc[3].size = memsize - mdesc[3].base; 67 mdesc[3].size = memsize - mdesc[3].base;
69 68
70 return &mdesc[0]; 69 return &mdesc[0];
diff --git a/arch/mips/mips-boards/sim/sim_smp.c b/arch/mips/mips-boards/sim/sim_smp.c
index a9f0c2bfe4ad..b7084e7c4bf9 100644
--- a/arch/mips/mips-boards/sim/sim_smp.c
+++ b/arch/mips/mips-boards/sim/sim_smp.c
@@ -44,8 +44,6 @@
44void core_send_ipi(int cpu, unsigned int action) 44void core_send_ipi(int cpu, unsigned int action)
45{ 45{
46#ifdef CONFIG_MIPS_MT_SMTC 46#ifdef CONFIG_MIPS_MT_SMTC
47 void smtc_send_ipi(int, int, unsigned int);
48
49 smtc_send_ipi(cpu, LINUX_SMP_IPI, action); 47 smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
50#endif /* CONFIG_MIPS_MT_SMTC */ 48#endif /* CONFIG_MIPS_MT_SMTC */
51/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */ 49/* "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)
59void __init prom_build_cpu_map(void) 57void __init prom_build_cpu_map(void)
60{ 58{
61#ifdef CONFIG_MIPS_MT_SMTC 59#ifdef CONFIG_MIPS_MT_SMTC
62 extern int mipsmt_build_cpu_map(int startslot);
63 int nextslot; 60 int nextslot;
64 61
65 cpus_clear(phys_cpu_present_map);
66
67 /* Register the boot CPU */
68
69 smp_prepare_boot_cpu();
70
71 /* 62 /*
72 * As of November, 2004, MIPSsim only simulates one core 63 * As of November, 2004, MIPSsim only simulates one core
73 * at a time. However, that core may be a MIPS MT core 64 * at a time. However, that core may be a MIPS MT core
@@ -87,8 +78,6 @@ void __init prom_build_cpu_map(void)
87void prom_boot_secondary(int cpu, struct task_struct *idle) 78void prom_boot_secondary(int cpu, struct task_struct *idle)
88{ 79{
89#ifdef CONFIG_MIPS_MT_SMTC 80#ifdef CONFIG_MIPS_MT_SMTC
90 extern void smtc_boot_secondary(int cpu, struct task_struct *t);
91
92 smtc_boot_secondary(cpu, idle); 81 smtc_boot_secondary(cpu, idle);
93#endif /* CONFIG_MIPS_MT_SMTC */ 82#endif /* CONFIG_MIPS_MT_SMTC */
94} 83}
@@ -113,7 +102,6 @@ void prom_init_secondary(void)
113void prom_prepare_cpus(unsigned int max_cpus) 102void prom_prepare_cpus(unsigned int max_cpus)
114{ 103{
115#ifdef CONFIG_MIPS_MT_SMTC 104#ifdef CONFIG_MIPS_MT_SMTC
116 void mipsmt_prepare_cpus(int c);
117 /* 105 /*
118 * As noted above, we can assume a single CPU for now 106 * As noted above, we can assume a single CPU for now
119 * but it may be multithreaded. 107 * but it may be multithreaded.
@@ -132,8 +120,6 @@ void prom_prepare_cpus(unsigned int max_cpus)
132void prom_smp_finish(void) 120void prom_smp_finish(void)
133{ 121{
134#ifdef CONFIG_MIPS_MT_SMTC 122#ifdef CONFIG_MIPS_MT_SMTC
135 void smtc_smp_finish(void);
136
137 smtc_smp_finish(); 123 smtc_smp_finish();
138#endif /* CONFIG_MIPS_MT_SMTC */ 124#endif /* CONFIG_MIPS_MT_SMTC */
139} 125}
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c
index 9dd1352d5748..bb041a22f20a 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,
260{ 260{
261} 261}
262 262
263static void local_r3k_flush_data_cache_page(unsigned long addr)
264{
265}
266
263static void r3k_flush_data_cache_page(unsigned long addr) 267static void r3k_flush_data_cache_page(unsigned long addr)
264{ 268{
265} 269}
@@ -335,6 +339,7 @@ void __init r3k_cache_init(void)
335 flush_icache_range = r3k_flush_icache_range; 339 flush_icache_range = r3k_flush_icache_range;
336 340
337 flush_cache_sigtramp = r3k_flush_cache_sigtramp; 341 flush_cache_sigtramp = r3k_flush_cache_sigtramp;
342 local_flush_data_cache_page = local_r3k_flush_data_cache_page;
338 flush_data_cache_page = r3k_flush_data_cache_page; 343 flush_data_cache_page = r3k_flush_data_cache_page;
339 344
340 _dma_cache_wback_inv = r3k_dma_cache_wback_inv; 345 _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 32b7f6aeb983..4182e1176fae 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)
154 154
155static inline void tx49_blast_icache32_page_indexed(unsigned long page) 155static inline void tx49_blast_icache32_page_indexed(unsigned long page)
156{ 156{
157 unsigned long start = page; 157 unsigned long indexmask = current_cpu_data.icache.waysize - 1;
158 unsigned long start = INDEX_BASE + (page & indexmask);
158 unsigned long end = start + PAGE_SIZE; 159 unsigned long end = start + PAGE_SIZE;
159 unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; 160 unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit;
160 unsigned long ws_end = current_cpu_data.icache.ways << 161 unsigned long ws_end = current_cpu_data.icache.ways <<
@@ -749,12 +750,12 @@ static void __init probe_pcache(void)
749 icache_size = 1 << (12 + ((config & CONF_IC) >> 9)); 750 icache_size = 1 << (12 + ((config & CONF_IC) >> 9));
750 c->icache.linesz = 16 << ((config & CONF_IB) >> 5); 751 c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
751 c->icache.ways = 2; 752 c->icache.ways = 2;
752 c->icache.waybit = ffs(icache_size/2) - 1; 753 c->icache.waybit = __ffs(icache_size/2);
753 754
754 dcache_size = 1 << (12 + ((config & CONF_DC) >> 6)); 755 dcache_size = 1 << (12 + ((config & CONF_DC) >> 6));
755 c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); 756 c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
756 c->dcache.ways = 2; 757 c->dcache.ways = 2;
757 c->dcache.waybit= ffs(dcache_size/2) - 1; 758 c->dcache.waybit= __ffs(dcache_size/2);
758 759
759 c->options |= MIPS_CPU_CACHE_CDEX_P; 760 c->options |= MIPS_CPU_CACHE_CDEX_P;
760 break; 761 break;
@@ -837,12 +838,12 @@ static void __init probe_pcache(void)
837 icache_size = 1 << (10 + ((config & CONF_IC) >> 9)); 838 icache_size = 1 << (10 + ((config & CONF_IC) >> 9));
838 c->icache.linesz = 16 << ((config & CONF_IB) >> 5); 839 c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
839 c->icache.ways = 2; 840 c->icache.ways = 2;
840 c->icache.waybit = ffs(icache_size/2) - 1; 841 c->icache.waybit = __ffs(icache_size/2);
841 842
842 dcache_size = 1 << (10 + ((config & CONF_DC) >> 6)); 843 dcache_size = 1 << (10 + ((config & CONF_DC) >> 6));
843 c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); 844 c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
844 c->dcache.ways = 2; 845 c->dcache.ways = 2;
845 c->dcache.waybit = ffs(dcache_size/2) - 1; 846 c->dcache.waybit = __ffs(dcache_size/2);
846 847
847 c->options |= MIPS_CPU_CACHE_CDEX_P; 848 c->options |= MIPS_CPU_CACHE_CDEX_P;
848 break; 849 break;
@@ -873,12 +874,12 @@ static void __init probe_pcache(void)
873 icache_size = 1 << (12 + ((config & CONF_IC) >> 9)); 874 icache_size = 1 << (12 + ((config & CONF_IC) >> 9));
874 c->icache.linesz = 16 << ((config & CONF_IB) >> 5); 875 c->icache.linesz = 16 << ((config & CONF_IB) >> 5);
875 c->icache.ways = 4; 876 c->icache.ways = 4;
876 c->icache.waybit = ffs(icache_size / c->icache.ways) - 1; 877 c->icache.waybit = __ffs(icache_size / c->icache.ways);
877 878
878 dcache_size = 1 << (12 + ((config & CONF_DC) >> 6)); 879 dcache_size = 1 << (12 + ((config & CONF_DC) >> 6));
879 c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); 880 c->dcache.linesz = 16 << ((config & CONF_DB) >> 4);
880 c->dcache.ways = 4; 881 c->dcache.ways = 4;
881 c->dcache.waybit = ffs(dcache_size / c->dcache.ways) - 1; 882 c->dcache.waybit = __ffs(dcache_size / c->dcache.ways);
882 883
883#if !defined(CONFIG_SMP) || !defined(RM9000_CDEX_SMP_WAR) 884#if !defined(CONFIG_SMP) || !defined(RM9000_CDEX_SMP_WAR)
884 c->options |= MIPS_CPU_CACHE_CDEX_P; 885 c->options |= MIPS_CPU_CACHE_CDEX_P;
@@ -906,7 +907,7 @@ static void __init probe_pcache(void)
906 icache_size = c->icache.sets * 907 icache_size = c->icache.sets *
907 c->icache.ways * 908 c->icache.ways *
908 c->icache.linesz; 909 c->icache.linesz;
909 c->icache.waybit = ffs(icache_size/c->icache.ways) - 1; 910 c->icache.waybit = __ffs(icache_size/c->icache.ways);
910 911
911 if (config & 0x8) /* VI bit */ 912 if (config & 0x8) /* VI bit */
912 c->icache.flags |= MIPS_CACHE_VTAG; 913 c->icache.flags |= MIPS_CACHE_VTAG;
@@ -926,7 +927,7 @@ static void __init probe_pcache(void)
926 dcache_size = c->dcache.sets * 927 dcache_size = c->dcache.sets *
927 c->dcache.ways * 928 c->dcache.ways *
928 c->dcache.linesz; 929 c->dcache.linesz;
929 c->dcache.waybit = ffs(dcache_size/c->dcache.ways) - 1; 930 c->dcache.waybit = __ffs(dcache_size/c->dcache.ways);
930 931
931 c->options |= MIPS_CPU_PREFETCH; 932 c->options |= MIPS_CPU_PREFETCH;
932 break; 933 break;
@@ -1198,6 +1199,7 @@ void __init r4k_cache_init(void)
1198 1199
1199 flush_cache_sigtramp = r4k_flush_cache_sigtramp; 1200 flush_cache_sigtramp = r4k_flush_cache_sigtramp;
1200 flush_icache_all = r4k_flush_icache_all; 1201 flush_icache_all = r4k_flush_icache_all;
1202 local_flush_data_cache_page = local_r4k_flush_data_cache_page;
1201 flush_data_cache_page = r4k_flush_data_cache_page; 1203 flush_data_cache_page = r4k_flush_data_cache_page;
1202 flush_icache_range = r4k_flush_icache_range; 1204 flush_icache_range = r4k_flush_icache_range;
1203 1205
diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c
index 2f08b535f20e..f9b129491b1e 100644
--- a/arch/mips/mm/c-sb1.c
+++ b/arch/mips/mm/c-sb1.c
@@ -528,6 +528,7 @@ void sb1_cache_init(void)
528 flush_cache_page = sb1_flush_cache_page; 528 flush_cache_page = sb1_flush_cache_page;
529 529
530 flush_cache_sigtramp = sb1_flush_cache_sigtramp; 530 flush_cache_sigtramp = sb1_flush_cache_sigtramp;
531 local_flush_data_cache_page = (void *) sb1_nop;
531 flush_data_cache_page = (void *) sb1_nop; 532 flush_data_cache_page = (void *) sb1_nop;
532 533
533 /* Full flush */ 534 /* Full flush */
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c
index fe232e3988e3..5dfc9b1901f6 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
216 tx39_blast_icache_page_indexed(page); 216 tx39_blast_icache_page_indexed(page);
217} 217}
218 218
219static void local_tx39_flush_data_cache_page(void * addr)
220{
221 tx39_blast_dcache_page(addr);
222}
223
219static void tx39_flush_data_cache_page(unsigned long addr) 224static void tx39_flush_data_cache_page(unsigned long addr)
220{ 225{
221 tx39_blast_dcache_page(addr); 226 tx39_blast_dcache_page(addr);
@@ -381,6 +386,7 @@ void __init tx39_cache_init(void)
381 flush_icache_range = (void *) tx39h_flush_icache_all; 386 flush_icache_range = (void *) tx39h_flush_icache_all;
382 387
383 flush_cache_sigtramp = (void *) tx39h_flush_icache_all; 388 flush_cache_sigtramp = (void *) tx39h_flush_icache_all;
389 local_flush_data_cache_page = (void *) tx39h_flush_icache_all;
384 flush_data_cache_page = (void *) tx39h_flush_icache_all; 390 flush_data_cache_page = (void *) tx39h_flush_icache_all;
385 391
386 _dma_cache_wback_inv = tx39h_dma_cache_wback_inv; 392 _dma_cache_wback_inv = tx39h_dma_cache_wback_inv;
@@ -406,6 +412,7 @@ void __init tx39_cache_init(void)
406 flush_icache_range = tx39_flush_icache_range; 412 flush_icache_range = tx39_flush_icache_range;
407 413
408 flush_cache_sigtramp = tx39_flush_cache_sigtramp; 414 flush_cache_sigtramp = tx39_flush_cache_sigtramp;
415 local_flush_data_cache_page = local_tx39_flush_data_cache_page;
409 flush_data_cache_page = tx39_flush_data_cache_page; 416 flush_data_cache_page = tx39_flush_data_cache_page;
410 417
411 _dma_cache_wback_inv = tx39_dma_cache_wback_inv; 418 _dma_cache_wback_inv = tx39_dma_cache_wback_inv;
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 591c22b080e4..83a56296be86 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);
30 30
31/* MIPS specific cache operations */ 31/* MIPS specific cache operations */
32void (*flush_cache_sigtramp)(unsigned long addr); 32void (*flush_cache_sigtramp)(unsigned long addr);
33void (*local_flush_data_cache_page)(void * addr);
33void (*flush_data_cache_page)(unsigned long addr); 34void (*flush_data_cache_page)(unsigned long addr);
34void (*flush_icache_all)(void); 35void (*flush_icache_all)(void);
35 36
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 2d9624fd10ec..e3a617224868 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -157,7 +157,6 @@ no_context:
157 * Oops. The kernel tried to access some bad page. We'll have to 157 * Oops. The kernel tried to access some bad page. We'll have to
158 * terminate things with extreme prejudice. 158 * terminate things with extreme prejudice.
159 */ 159 */
160
161 bust_spinlocks(1); 160 bust_spinlocks(1);
162 161
163 printk(KERN_ALERT "CPU %d Unable to handle kernel paging request at " 162 printk(KERN_ALERT "CPU %d Unable to handle kernel paging request at "
@@ -188,11 +187,20 @@ do_sigbus:
188 /* Kernel mode? Handle exceptions or die */ 187 /* Kernel mode? Handle exceptions or die */
189 if (!user_mode(regs)) 188 if (!user_mode(regs))
190 goto no_context; 189 goto no_context;
191 190 else
192 /* 191 /*
193 * Send a sigbus, regardless of whether we were in kernel 192 * Send a sigbus, regardless of whether we were in kernel
194 * or user mode. 193 * or user mode.
195 */ 194 */
195#if 0
196 printk("do_page_fault() #3: sending SIGBUS to %s for "
197 "invalid %s\n%0*lx (epc == %0*lx, ra == %0*lx)\n",
198 tsk->comm,
199 write ? "write access to" : "read access from",
200 field, address,
201 field, (unsigned long) regs->cp0_epc,
202 field, (unsigned long) regs->regs[31]);
203#endif
196 tsk->thread.cp0_badvaddr = address; 204 tsk->thread.cp0_badvaddr = address;
197 info.si_signo = SIGBUS; 205 info.si_signo = SIGBUS;
198 info.si_errno = 0; 206 info.si_errno = 0;
@@ -201,7 +209,6 @@ do_sigbus:
201 force_sig_info(SIGBUS, &info, tsk); 209 force_sig_info(SIGBUS, &info, tsk);
202 210
203 return; 211 return;
204
205vmalloc_fault: 212vmalloc_fault:
206 { 213 {
207 /* 214 /*
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
index 1f7b37b38f5c..0c544375b856 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)
83 preempt_check_resched(); 83 preempt_check_resched();
84} 84}
85 85
86#ifndef CONFIG_LIMITED_DMA
86/* 87/*
87 * This is the same as kmap_atomic() but can map memory that doesn't 88 * This is the same as kmap_atomic() but can map memory that doesn't
88 * have a struct page associated with it. 89 * have a struct page associated with it.
@@ -101,6 +102,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
101 102
102 return (void*) vaddr; 103 return (void*) vaddr;
103} 104}
105#endif /* CONFIG_LIMITED_DMA */
104 106
105struct page *__kmap_atomic_to_page(void *ptr) 107struct page *__kmap_atomic_to_page(void *ptr)
106{ 108{
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index ad89c442f299..c22308b93ff0 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -276,6 +276,20 @@ void __init mem_init(void)
276} 276}
277#endif /* !CONFIG_NEED_MULTIPLE_NODES */ 277#endif /* !CONFIG_NEED_MULTIPLE_NODES */
278 278
279void free_init_pages(char *what, unsigned long begin, unsigned long end)
280{
281 unsigned long addr;
282
283 for (addr = begin; addr < end; addr += PAGE_SIZE) {
284 ClearPageReserved(virt_to_page(addr));
285 init_page_count(virt_to_page(addr));
286 memset((void *)addr, 0xcc, PAGE_SIZE);
287 free_page(addr);
288 totalram_pages++;
289 }
290 printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
291}
292
279#ifdef CONFIG_BLK_DEV_INITRD 293#ifdef CONFIG_BLK_DEV_INITRD
280void free_initrd_mem(unsigned long start, unsigned long end) 294void free_initrd_mem(unsigned long start, unsigned long end)
281{ 295{
@@ -284,16 +298,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
284 start = (unsigned long)phys_to_virt(CPHYSADDR(start)); 298 start = (unsigned long)phys_to_virt(CPHYSADDR(start));
285 end = (unsigned long)phys_to_virt(CPHYSADDR(end)); 299 end = (unsigned long)phys_to_virt(CPHYSADDR(end));
286#endif 300#endif
287 if (start < end) 301 free_init_pages("initrd memory", start, end);
288 printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
289 (end - start) >> 10);
290
291 for (; start < end; start += PAGE_SIZE) {
292 ClearPageReserved(virt_to_page(start));
293 init_page_count(virt_to_page(start));
294 free_page(start);
295 totalram_pages++;
296 }
297} 302}
298#endif 303#endif
299 304
@@ -301,24 +306,17 @@ extern unsigned long prom_free_prom_memory(void);
301 306
302void free_initmem(void) 307void free_initmem(void)
303{ 308{
304 unsigned long addr, page, freed; 309 unsigned long start, end, freed;
305 310
306 freed = prom_free_prom_memory(); 311 freed = prom_free_prom_memory();
312 if (freed)
313 printk(KERN_INFO "Freeing firmware memory: %ldk freed\n",freed);
307 314
308 addr = (unsigned long) &__init_begin; 315 start = (unsigned long)(&__init_begin);
309 while (addr < (unsigned long) &__init_end) { 316 end = (unsigned long)(&__init_end);
310#ifdef CONFIG_64BIT 317#ifdef CONFIG_64BIT
311 page = PAGE_OFFSET | CPHYSADDR(addr); 318 start = PAGE_OFFSET | CPHYSADDR(start);
312#else 319 end = PAGE_OFFSET | CPHYSADDR(end);
313 page = addr;
314#endif 320#endif
315 ClearPageReserved(virt_to_page(page)); 321 free_init_pages("unused kernel memory", start, end);
316 init_page_count(virt_to_page(page));
317 free_page(page);
318 totalram_pages++;
319 freed += PAGE_SIZE;
320 addr += PAGE_SIZE;
321 }
322 printk(KERN_INFO "Freeing unused kernel memory: %ldk freed\n",
323 freed >> 10);
324} 322}
diff --git a/arch/mips/mm/sc-rm7k.c b/arch/mips/mm/sc-rm7k.c
index 3b6cc9ba1b05..31ec73052423 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)
138 138
139 c->scache.linesz = sc_lsize; 139 c->scache.linesz = sc_lsize;
140 c->scache.ways = 4; 140 c->scache.ways = 4;
141 c->scache.waybit= ffs(scache_size / c->scache.ways) - 1; 141 c->scache.waybit= __ffs(scache_size / c->scache.ways);
142 c->scache.waysize = scache_size / c->scache.ways; 142 c->scache.waysize = scache_size / c->scache.ways;
143 c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways); 143 c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways);
144 printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n", 144 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 a865f2394cb0..9dca099ba16b 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);
32 "nop; nop; nop; nop; nop; nop;\n\t" \ 32 "nop; nop; nop; nop; nop; nop;\n\t" \
33 ".set reorder\n\t") 33 ".set reorder\n\t")
34 34
35/* Atomicity and interruptability */
36#ifdef CONFIG_MIPS_MT_SMTC
37
38#include <asm/smtc.h>
39#include <asm/mipsmtregs.h>
40
41#define ENTER_CRITICAL(flags) \
42 { \
43 unsigned int mvpflags; \
44 local_irq_save(flags);\
45 mvpflags = dvpe()
46#define EXIT_CRITICAL(flags) \
47 evpe(mvpflags); \
48 local_irq_restore(flags); \
49 }
50#else
51
52#define ENTER_CRITICAL(flags) local_irq_save(flags)
53#define EXIT_CRITICAL(flags) local_irq_restore(flags)
54
55#endif /* CONFIG_MIPS_MT_SMTC */
56
35void local_flush_tlb_all(void) 57void local_flush_tlb_all(void)
36{ 58{
37 unsigned long flags; 59 unsigned long flags;
38 unsigned long old_ctx; 60 unsigned long old_ctx;
39 int entry; 61 int entry;
40 62
41 local_irq_save(flags); 63 ENTER_CRITICAL(flags);
42 /* Save old context and create impossible VPN2 value */ 64 /* Save old context and create impossible VPN2 value */
43 old_ctx = read_c0_entryhi(); 65 old_ctx = read_c0_entryhi();
44 write_c0_entrylo0(0); 66 write_c0_entrylo0(0);
@@ -57,7 +79,7 @@ void local_flush_tlb_all(void)
57 } 79 }
58 tlbw_use_hazard(); 80 tlbw_use_hazard();
59 write_c0_entryhi(old_ctx); 81 write_c0_entryhi(old_ctx);
60 local_irq_restore(flags); 82 EXIT_CRITICAL(flags);
61} 83}
62 84
63/* All entries common to a mm share an asid. To effectively flush 85/* 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,
87 unsigned long flags; 109 unsigned long flags;
88 int size; 110 int size;
89 111
112 ENTER_CRITICAL(flags);
90 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; 113 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
91 size = (size + 1) >> 1; 114 size = (size + 1) >> 1;
92 local_irq_save(flags); 115 local_irq_save(flags);
@@ -120,7 +143,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
120 } else { 143 } else {
121 drop_mmu_context(mm, cpu); 144 drop_mmu_context(mm, cpu);
122 } 145 }
123 local_irq_restore(flags); 146 EXIT_CRITICAL(flags);
124 } 147 }
125} 148}
126 149
@@ -129,9 +152,9 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
129 unsigned long flags; 152 unsigned long flags;
130 int size; 153 int size;
131 154
155 ENTER_CRITICAL(flags);
132 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; 156 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
133 size = (size + 1) >> 1; 157 size = (size + 1) >> 1;
134 local_irq_save(flags);
135 if (size <= current_cpu_data.tlbsize / 2) { 158 if (size <= current_cpu_data.tlbsize / 2) {
136 int pid = read_c0_entryhi(); 159 int pid = read_c0_entryhi();
137 160
@@ -162,7 +185,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
162 } else { 185 } else {
163 local_flush_tlb_all(); 186 local_flush_tlb_all();
164 } 187 }
165 local_irq_restore(flags); 188 EXIT_CRITICAL(flags);
166} 189}
167 190
168void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) 191void 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)
175 198
176 newpid = cpu_asid(cpu, vma->vm_mm); 199 newpid = cpu_asid(cpu, vma->vm_mm);
177 page &= (PAGE_MASK << 1); 200 page &= (PAGE_MASK << 1);
178 local_irq_save(flags); 201 ENTER_CRITICAL(flags);
179 oldpid = read_c0_entryhi(); 202 oldpid = read_c0_entryhi();
180 write_c0_entryhi(page | newpid); 203 write_c0_entryhi(page | newpid);
181 mtc0_tlbw_hazard(); 204 mtc0_tlbw_hazard();
@@ -194,7 +217,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
194 217
195 finish: 218 finish:
196 write_c0_entryhi(oldpid); 219 write_c0_entryhi(oldpid);
197 local_irq_restore(flags); 220 EXIT_CRITICAL(flags);
198 } 221 }
199} 222}
200 223
@@ -207,7 +230,7 @@ void local_flush_tlb_one(unsigned long page)
207 unsigned long flags; 230 unsigned long flags;
208 int oldpid, idx; 231 int oldpid, idx;
209 232
210 local_irq_save(flags); 233 ENTER_CRITICAL(flags);
211 oldpid = read_c0_entryhi(); 234 oldpid = read_c0_entryhi();
212 page &= (PAGE_MASK << 1); 235 page &= (PAGE_MASK << 1);
213 write_c0_entryhi(page); 236 write_c0_entryhi(page);
@@ -226,7 +249,7 @@ void local_flush_tlb_one(unsigned long page)
226 } 249 }
227 write_c0_entryhi(oldpid); 250 write_c0_entryhi(oldpid);
228 251
229 local_irq_restore(flags); 252 EXIT_CRITICAL(flags);
230} 253}
231 254
232/* 255/*
@@ -249,7 +272,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
249 if (current->active_mm != vma->vm_mm) 272 if (current->active_mm != vma->vm_mm)
250 return; 273 return;
251 274
252 local_irq_save(flags); 275 ENTER_CRITICAL(flags);
253 276
254 pid = read_c0_entryhi() & ASID_MASK; 277 pid = read_c0_entryhi() & ASID_MASK;
255 address &= (PAGE_MASK << 1); 278 address &= (PAGE_MASK << 1);
@@ -277,7 +300,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
277 else 300 else
278 tlb_write_indexed(); 301 tlb_write_indexed();
279 tlbw_use_hazard(); 302 tlbw_use_hazard();
280 local_irq_restore(flags); 303 EXIT_CRITICAL(flags);
281} 304}
282 305
283#if 0 306#if 0
@@ -291,7 +314,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma,
291 pte_t *ptep; 314 pte_t *ptep;
292 int idx; 315 int idx;
293 316
294 local_irq_save(flags); 317 ENTER_CRITICAL(flags);
295 address &= (PAGE_MASK << 1); 318 address &= (PAGE_MASK << 1);
296 asid = read_c0_entryhi() & ASID_MASK; 319 asid = read_c0_entryhi() & ASID_MASK;
297 write_c0_entryhi(address | asid); 320 write_c0_entryhi(address | asid);
@@ -310,7 +333,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma,
310 else 333 else
311 tlb_write_indexed(); 334 tlb_write_indexed();
312 tlbw_use_hazard(); 335 tlbw_use_hazard();
313 local_irq_restore(flags); 336 EXIT_CRITICAL(flags);
314} 337}
315#endif 338#endif
316 339
@@ -322,7 +345,7 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
322 unsigned long old_pagemask; 345 unsigned long old_pagemask;
323 unsigned long old_ctx; 346 unsigned long old_ctx;
324 347
325 local_irq_save(flags); 348 ENTER_CRITICAL(flags);
326 /* Save old context and create impossible VPN2 value */ 349 /* Save old context and create impossible VPN2 value */
327 old_ctx = read_c0_entryhi(); 350 old_ctx = read_c0_entryhi();
328 old_pagemask = read_c0_pagemask(); 351 old_pagemask = read_c0_pagemask();
@@ -342,7 +365,7 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
342 BARRIER; 365 BARRIER;
343 write_c0_pagemask(old_pagemask); 366 write_c0_pagemask(old_pagemask);
344 local_flush_tlb_all(); 367 local_flush_tlb_all();
345 local_irq_restore(flags); 368 EXIT_CRITICAL(flags);
346} 369}
347 370
348/* 371/*
@@ -362,7 +385,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
362 unsigned long old_pagemask; 385 unsigned long old_pagemask;
363 unsigned long old_ctx; 386 unsigned long old_ctx;
364 387
365 local_irq_save(flags); 388 ENTER_CRITICAL(flags);
366 /* Save old context and create impossible VPN2 value */ 389 /* Save old context and create impossible VPN2 value */
367 old_ctx = read_c0_entryhi(); 390 old_ctx = read_c0_entryhi();
368 old_pagemask = read_c0_pagemask(); 391 old_pagemask = read_c0_pagemask();
@@ -386,10 +409,11 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
386 write_c0_entryhi(old_ctx); 409 write_c0_entryhi(old_ctx);
387 write_c0_pagemask(old_pagemask); 410 write_c0_pagemask(old_pagemask);
388out: 411out:
389 local_irq_restore(flags); 412 EXIT_CRITICAL(flags);
390 return ret; 413 return ret;
391} 414}
392 415
416extern void __init sanitize_tlb_entries(void);
393static void __init probe_tlb(unsigned long config) 417static void __init probe_tlb(unsigned long config)
394{ 418{
395 struct cpuinfo_mips *c = &current_cpu_data; 419 struct cpuinfo_mips *c = &current_cpu_data;
@@ -402,6 +426,14 @@ static void __init probe_tlb(unsigned long config)
402 */ 426 */
403 if ((c->processor_id & 0xff0000) == PRID_COMP_LEGACY) 427 if ((c->processor_id & 0xff0000) == PRID_COMP_LEGACY)
404 return; 428 return;
429#ifdef CONFIG_MIPS_MT_SMTC
430 /*
431 * If TLB is shared in SMTC system, total size already
432 * has been calculated and written into cpu_data tlbsize
433 */
434 if((smtc_status & SMTC_TLB_SHARED) == SMTC_TLB_SHARED)
435 return;
436#endif /* CONFIG_MIPS_MT_SMTC */
405 437
406 reg = read_c0_config1(); 438 reg = read_c0_config1();
407 if (!((config >> 7) & 3)) 439 if (!((config >> 7) & 3))
@@ -410,6 +442,15 @@ static void __init probe_tlb(unsigned long config)
410 c->tlbsize = ((reg >> 25) & 0x3f) + 1; 442 c->tlbsize = ((reg >> 25) & 0x3f) + 1;
411} 443}
412 444
445static int __initdata ntlb = 0;
446static int __init set_ntlb(char *str)
447{
448 get_option(&str, &ntlb);
449 return 1;
450}
451
452__setup("ntlb=", set_ntlb);
453
413void __init tlb_init(void) 454void __init tlb_init(void)
414{ 455{
415 unsigned int config = read_c0_config(); 456 unsigned int config = read_c0_config();
@@ -432,5 +473,15 @@ void __init tlb_init(void)
432 473
433 /* Did I tell you that ARC SUCKS? */ 474 /* Did I tell you that ARC SUCKS? */
434 475
476 if (ntlb) {
477 if (ntlb > 1 && ntlb <= current_cpu_data.tlbsize) {
478 int wired = current_cpu_data.tlbsize - ntlb;
479 write_c0_wired(wired);
480 write_c0_index(wired-1);
481 printk ("Restricting TLB to %d entries\n", ntlb);
482 } else
483 printk("Ignoring invalid argument ntlb=%d\n", ntlb);
484 }
485
435 build_tlb_refill_handler(); 486 build_tlb_refill_handler();
436} 487}
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 599b3c297186..053dbacac56b 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -7,6 +7,16 @@
7 * 7 *
8 * Copyright (C) 2004,2005 by Thiemo Seufer 8 * Copyright (C) 2004,2005 by Thiemo Seufer
9 * Copyright (C) 2005 Maciej W. Rozycki 9 * Copyright (C) 2005 Maciej W. Rozycki
10 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
11 *
12 * ... and the days got worse and worse and now you see
13 * I've gone completly out of my mind.
14 *
15 * They're coming to take me a away haha
16 * they're coming to take me a away hoho hihi haha
17 * to the funny farm where code is beautiful all the time ...
18 *
19 * (Condolences to Napoleon XIV)
10 */ 20 */
11 21
12#include <stdarg.h> 22#include <stdarg.h>
@@ -68,6 +78,7 @@ enum fields
68 BIMM = 0x040, 78 BIMM = 0x040,
69 JIMM = 0x080, 79 JIMM = 0x080,
70 FUNC = 0x100, 80 FUNC = 0x100,
81 SET = 0x200
71}; 82};
72 83
73#define OP_MASK 0x2f 84#define OP_MASK 0x2f
@@ -86,6 +97,8 @@ enum fields
86#define JIMM_SH 0 97#define JIMM_SH 0
87#define FUNC_MASK 0x2f 98#define FUNC_MASK 0x2f
88#define FUNC_SH 0 99#define FUNC_SH 0
100#define SET_MASK 0x7
101#define SET_SH 0
89 102
90enum opcode { 103enum opcode {
91 insn_invalid, 104 insn_invalid,
@@ -129,8 +142,8 @@ static __initdata struct insn insn_table[] = {
129 { insn_bne, M(bne_op,0,0,0,0,0), RS | RT | BIMM }, 142 { insn_bne, M(bne_op,0,0,0,0,0), RS | RT | BIMM },
130 { insn_daddiu, M(daddiu_op,0,0,0,0,0), RS | RT | SIMM }, 143 { insn_daddiu, M(daddiu_op,0,0,0,0,0), RS | RT | SIMM },
131 { insn_daddu, M(spec_op,0,0,0,0,daddu_op), RS | RT | RD }, 144 { insn_daddu, M(spec_op,0,0,0,0,daddu_op), RS | RT | RD },
132 { insn_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD }, 145 { insn_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD | SET},
133 { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD }, 146 { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD | SET},
134 { insn_dsll, M(spec_op,0,0,0,0,dsll_op), RT | RD | RE }, 147 { insn_dsll, M(spec_op,0,0,0,0,dsll_op), RT | RD | RE },
135 { insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE }, 148 { insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE },
136 { insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE }, 149 { insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE },
@@ -145,8 +158,8 @@ static __initdata struct insn insn_table[] = {
145 { insn_lld, M(lld_op,0,0,0,0,0), RS | RT | SIMM }, 158 { insn_lld, M(lld_op,0,0,0,0,0), RS | RT | SIMM },
146 { insn_lui, M(lui_op,0,0,0,0,0), RT | SIMM }, 159 { insn_lui, M(lui_op,0,0,0,0,0), RT | SIMM },
147 { insn_lw, M(lw_op,0,0,0,0,0), RS | RT | SIMM }, 160 { insn_lw, M(lw_op,0,0,0,0,0), RS | RT | SIMM },
148 { insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD }, 161 { insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD | SET},
149 { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD }, 162 { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD | SET},
150 { insn_ori, M(ori_op,0,0,0,0,0), RS | RT | UIMM }, 163 { insn_ori, M(ori_op,0,0,0,0,0), RS | RT | UIMM },
151 { insn_rfe, M(cop0_op,cop_op,0,0,0,rfe_op), 0 }, 164 { insn_rfe, M(cop0_op,cop_op,0,0,0,rfe_op), 0 },
152 { insn_sc, M(sc_op,0,0,0,0,0), RS | RT | SIMM }, 165 { insn_sc, M(sc_op,0,0,0,0,0), RS | RT | SIMM },
@@ -242,6 +255,14 @@ static __init u32 build_func(u32 arg)
242 return arg & FUNC_MASK; 255 return arg & FUNC_MASK;
243} 256}
244 257
258static __init u32 build_set(u32 arg)
259{
260 if (arg & ~SET_MASK)
261 printk(KERN_WARNING "TLB synthesizer field overflow\n");
262
263 return arg & SET_MASK;
264}
265
245/* 266/*
246 * The order of opcode arguments is implicitly left to right, 267 * The order of opcode arguments is implicitly left to right,
247 * starting with RS and ending with FUNC or IMM. 268 * starting with RS and ending with FUNC or IMM.
@@ -273,6 +294,7 @@ static void __init build_insn(u32 **buf, enum opcode opc, ...)
273 if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32)); 294 if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32));
274 if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32)); 295 if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32));
275 if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32)); 296 if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32));
297 if (ip->fields & SET) op |= build_set(va_arg(ap, u32));
276 va_end(ap); 298 va_end(ap);
277 299
278 **buf = op; 300 **buf = op;
@@ -358,8 +380,8 @@ I_u1s2(_bgezl);
358I_u1s2(_bltz); 380I_u1s2(_bltz);
359I_u1s2(_bltzl); 381I_u1s2(_bltzl);
360I_u1u2s3(_bne); 382I_u1u2s3(_bne);
361I_u1u2(_dmfc0); 383I_u1u2u3(_dmfc0);
362I_u1u2(_dmtc0); 384I_u1u2u3(_dmtc0);
363I_u2u1s3(_daddiu); 385I_u2u1s3(_daddiu);
364I_u3u1u2(_daddu); 386I_u3u1u2(_daddu);
365I_u2u1u3(_dsll); 387I_u2u1u3(_dsll);
@@ -376,8 +398,8 @@ I_u2s3u1(_ll);
376I_u2s3u1(_lld); 398I_u2s3u1(_lld);
377I_u1s2(_lui); 399I_u1s2(_lui);
378I_u2s3u1(_lw); 400I_u2s3u1(_lw);
379I_u1u2(_mfc0); 401I_u1u2u3(_mfc0);
380I_u1u2(_mtc0); 402I_u1u2u3(_mtc0);
381I_u2u1u3(_ori); 403I_u2u1u3(_ori);
382I_0(_rfe); 404I_0(_rfe);
383I_u2s3u1(_sc); 405I_u2s3u1(_sc);
@@ -451,8 +473,8 @@ L_LA(_r3000_write_probe_fail)
451# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh) 473# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
452# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh) 474# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh)
453# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh) 475# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh)
454# define i_MFC0(buf, rt, rd) i_dmfc0(buf, rt, rd) 476# define i_MFC0(buf, rt, rd...) i_dmfc0(buf, rt, rd)
455# define i_MTC0(buf, rt, rd) i_dmtc0(buf, rt, rd) 477# define i_MTC0(buf, rt, rd...) i_dmtc0(buf, rt, rd)
456# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val) 478# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val)
457# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd) 479# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd)
458# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd) 480# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd)
@@ -464,8 +486,8 @@ L_LA(_r3000_write_probe_fail)
464# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh) 486# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh)
465# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh) 487# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh)
466# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh) 488# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh)
467# define i_MFC0(buf, rt, rd) i_mfc0(buf, rt, rd) 489# define i_MFC0(buf, rt, rd...) i_mfc0(buf, rt, rd)
468# define i_MTC0(buf, rt, rd) i_mtc0(buf, rt, rd) 490# define i_MTC0(buf, rt, rd...) i_mtc0(buf, rt, rd)
469# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val) 491# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val)
470# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd) 492# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd)
471# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd) 493# 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,
670#define K1 27 692#define K1 27
671 693
672/* Some CP0 registers */ 694/* Some CP0 registers */
673#define C0_INDEX 0 695#define C0_INDEX 0, 0
674#define C0_ENTRYLO0 2 696#define C0_ENTRYLO0 2, 0
675#define C0_ENTRYLO1 3 697#define C0_TCBIND 2, 2
676#define C0_CONTEXT 4 698#define C0_ENTRYLO1 3, 0
677#define C0_BADVADDR 8 699#define C0_CONTEXT 4, 0
678#define C0_ENTRYHI 10 700#define C0_BADVADDR 8, 0
679#define C0_EPC 14 701#define C0_ENTRYHI 10, 0
680#define C0_XCONTEXT 20 702#define C0_EPC 14, 0
703#define C0_XCONTEXT 20, 0
681 704
682#ifdef CONFIG_64BIT 705#ifdef CONFIG_64BIT
683# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT) 706# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
@@ -742,7 +765,7 @@ static void __init build_r3000_tlb_refill_handler(void)
742 } 765 }
743#endif 766#endif
744 767
745 memcpy((void *)CAC_BASE, tlb_handler, 0x80); 768 memcpy((void *)ebase, tlb_handler, 0x80);
746} 769}
747 770
748/* 771/*
@@ -951,12 +974,20 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
951 /* No i_nop needed here, since the next insn doesn't touch TMP. */ 974 /* No i_nop needed here, since the next insn doesn't touch TMP. */
952 975
953#ifdef CONFIG_SMP 976#ifdef CONFIG_SMP
977# ifdef CONFIG_MIPS_MT_SMTC
978 /*
979 * SMTC uses TCBind value as "CPU" index
980 */
981 i_mfc0(p, ptr, C0_TCBIND);
982 i_dsrl(p, ptr, ptr, 19);
983# else
954 /* 984 /*
955 * 64 bit SMP running in XKPHYS has smp_processor_id() << 3 985 * 64 bit SMP running in XKPHYS has smp_processor_id() << 3
956 * stored in CONTEXT. 986 * stored in CONTEXT.
957 */ 987 */
958 i_dmfc0(p, ptr, C0_CONTEXT); 988 i_dmfc0(p, ptr, C0_CONTEXT);
959 i_dsrl(p, ptr, ptr, 23); 989 i_dsrl(p, ptr, ptr, 23);
990#endif
960 i_LA_mostly(p, tmp, pgdc); 991 i_LA_mostly(p, tmp, pgdc);
961 i_daddu(p, ptr, ptr, tmp); 992 i_daddu(p, ptr, ptr, tmp);
962 i_dmfc0(p, tmp, C0_BADVADDR); 993 i_dmfc0(p, tmp, C0_BADVADDR);
@@ -1014,9 +1045,21 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
1014 1045
1015 /* 32 bit SMP has smp_processor_id() stored in CONTEXT. */ 1046 /* 32 bit SMP has smp_processor_id() stored in CONTEXT. */
1016#ifdef CONFIG_SMP 1047#ifdef CONFIG_SMP
1048#ifdef CONFIG_MIPS_MT_SMTC
1049 /*
1050 * SMTC uses TCBind value as "CPU" index
1051 */
1052 i_mfc0(p, ptr, C0_TCBIND);
1053 i_LA_mostly(p, tmp, pgdc);
1054 i_srl(p, ptr, ptr, 19);
1055#else
1056 /*
1057 * smp_processor_id() << 3 is stored in CONTEXT.
1058 */
1017 i_mfc0(p, ptr, C0_CONTEXT); 1059 i_mfc0(p, ptr, C0_CONTEXT);
1018 i_LA_mostly(p, tmp, pgdc); 1060 i_LA_mostly(p, tmp, pgdc);
1019 i_srl(p, ptr, ptr, 23); 1061 i_srl(p, ptr, ptr, 23);
1062#endif
1020 i_addu(p, ptr, tmp, ptr); 1063 i_addu(p, ptr, tmp, ptr);
1021#else 1064#else
1022 i_LA_mostly(p, ptr, pgdc); 1065 i_LA_mostly(p, ptr, pgdc);
@@ -1247,7 +1290,7 @@ static void __init build_r4000_tlb_refill_handler(void)
1247 } 1290 }
1248#endif 1291#endif
1249 1292
1250 memcpy((void *)CAC_BASE, final_handler, 0x100); 1293 memcpy((void *)ebase, final_handler, 0x100);
1251} 1294}
1252 1295
1253/* 1296/*
diff --git a/arch/mips/momentum/jaguar_atx/Makefile b/arch/mips/momentum/jaguar_atx/Makefile
index 20bbd3ea44a8..67372f3f9654 100644
--- a/arch/mips/momentum/jaguar_atx/Makefile
+++ b/arch/mips/momentum/jaguar_atx/Makefile
@@ -6,7 +6,7 @@
6# unless it's something special (ie not a .c file). 6# unless it's something special (ie not a .c file).
7# 7#
8 8
9obj-y += int-handler.o irq.o prom.o reset.o setup.o 9obj-y += irq.o prom.o reset.o setup.o
10 10
11obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o 11obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o
12obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o 12obj-$(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 55bc789733f2..000000000000
--- a/arch/mips/momentum/jaguar_atx/int-handler.S
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 * Copyright 2002 Momentum Computer Inc.
3 * Author: Matthew Dharm <mdharm@momenco.com>
4 *
5 * Based on work:
6 * Copyright 2001 MontaVista Software Inc.
7 * Author: jsun@mvista.com or jsun@junsun.net
8 *
9 * First-level interrupt dispatcher for Jaguar-ATX board.
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16#include <asm/asm.h>
17#include <asm/mipsregs.h>
18#include <asm/addrspace.h>
19#include <asm/regdef.h>
20#include <asm/stackframe.h>
21
22/*
23 * First level interrupt dispatcher for Ocelot-CS board
24 */
25 .align 5
26 NESTED(jaguar_handle_int, PT_SIZE, sp)
27 SAVE_ALL
28 CLI
29 .set at
30 mfc0 t0, CP0_CAUSE
31 mfc0 t2, CP0_STATUS
32
33 and t0, t2
34
35 andi t1, t0, STATUSF_IP0 /* sw0 software interrupt */
36 bnez t1, ll_sw0_irq
37 andi t1, t0, STATUSF_IP1 /* sw1 software interrupt */
38 bnez t1, ll_sw1_irq
39 andi t1, t0, STATUSF_IP2 /* int0 hardware line */
40 bnez t1, ll_pcixa_irq
41 andi t1, t0, STATUSF_IP3 /* int1 hardware line */
42 bnez t1, ll_pcixb_irq
43 andi t1, t0, STATUSF_IP4 /* int2 hardware line */
44 bnez t1, ll_pcia_irq
45 andi t1, t0, STATUSF_IP5 /* int3 hardware line */
46 bnez t1, ll_pcib_irq
47 andi t1, t0, STATUSF_IP6 /* int4 hardware line */
48 bnez t1, ll_uart_irq
49 andi t1, t0, STATUSF_IP7 /* cpu timer */
50 bnez t1, ll_cputimer_irq
51
52 nop
53 nop
54
55 /* now look at extended interrupts */
56 mfc0 t0, CP0_CAUSE
57 cfc0 t1, CP0_S1_INTCONTROL
58
59 /* shift the mask 8 bits left to line up the bits */
60 sll t2, t1, 8
61
62 and t0, t2
63 srl t0, t0, 16
64
65 andi t1, t0, STATUSF_IP8 /* int6 hardware line */
66 bnez t1, ll_mv64340_decode_irq
67
68 nop
69 nop
70
71 .set reorder
72
73 /* wrong alarm or masked ... */
74 j spurious_interrupt
75 nop
76 END(jaguar_handle_int)
77
78 .align 5
79ll_sw0_irq:
80 li a0, 0
81 move a1, sp
82 jal do_IRQ
83 j ret_from_irq
84ll_sw1_irq:
85 li a0, 1
86 move a1, sp
87 jal do_IRQ
88 j ret_from_irq
89ll_pcixa_irq:
90 li a0, 2
91 move a1, sp
92 jal do_IRQ
93 j ret_from_irq
94
95ll_pcixb_irq:
96 li a0, 3
97 move a1, sp
98 jal do_IRQ
99 j ret_from_irq
100
101ll_pcia_irq:
102 li a0, 4
103 move a1, sp
104 jal do_IRQ
105 j ret_from_irq
106
107ll_pcib_irq:
108 li a0, 5
109 move a1, sp
110 jal do_IRQ
111 j ret_from_irq
112
113ll_uart_irq:
114 li a0, 6
115 move a1, sp
116 jal do_IRQ
117 j ret_from_irq
118
119ll_cputimer_irq:
120 li a0, 7
121 move a1, sp
122 jal ll_timer_interrupt
123 j ret_from_irq
124
125ll_mv64340_decode_irq:
126 move a0, sp
127 jal ll_mv64340_irq
128 j ret_from_irq
diff --git a/arch/mips/momentum/jaguar_atx/irq.c b/arch/mips/momentum/jaguar_atx/irq.c
index 15588f91ace2..ec4032b38f19 100644
--- a/arch/mips/momentum/jaguar_atx/irq.c
+++ b/arch/mips/momentum/jaguar_atx/irq.c
@@ -10,7 +10,7 @@
10 * Copyright 2001 MontaVista Software Inc. 10 * Copyright 2001 MontaVista Software Inc.
11 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 11 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
12 * 12 *
13 * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org) 13 * Copyright (C) 2000, 01, 06 Ralf Baechle (ralf@linux-mips.org)
14 * 14 *
15 * This program is free software; you can redistribute it and/or modify it 15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the 16 * under the terms of the GNU General Public License as published by the
@@ -38,8 +38,37 @@
38#include <linux/types.h> 38#include <linux/types.h>
39#include <asm/irq_cpu.h> 39#include <asm/irq_cpu.h>
40#include <asm/mipsregs.h> 40#include <asm/mipsregs.h>
41#include <asm/time.h>
41 42
42extern asmlinkage void jaguar_handle_int(void); 43asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
44{
45 unsigned int pending = read_c0_cause() & read_c0_status();
46
47 if (pending & STATUSF_IP0)
48 do_IRQ(0, regs);
49 else if (pending & STATUSF_IP1)
50 do_IRQ(1, regs);
51 else if (pending & STATUSF_IP2)
52 do_IRQ(2, regs);
53 else if (pending & STATUSF_IP3)
54 do_IRQ(3, regs);
55 else if (pending & STATUSF_IP4)
56 do_IRQ(4, regs);
57 else if (pending & STATUSF_IP5)
58 do_IRQ(5, regs);
59 else if (pending & STATUSF_IP6)
60 do_IRQ(6, regs);
61 else if (pending & STATUSF_IP7)
62 ll_timer_interrupt(7, regs);
63 else {
64 /*
65 * Now look at the extended interrupts
66 */
67 pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
68 if (pending & STATUSF_IP8)
69 ll_mv64340_irq(regs);
70 }
71}
43 72
44static struct irqaction cascade_mv64340 = { 73static struct irqaction cascade_mv64340 = {
45 no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL 74 no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL
@@ -53,8 +82,6 @@ void __init arch_init_irq(void)
53 */ 82 */
54 clear_c0_status(ST0_IM); 83 clear_c0_status(ST0_IM);
55 84
56 /* Sets the first-level interrupt dispatcher. */
57 set_except_vector(0, jaguar_handle_int);
58 mips_cpu_irq_init(0); 85 mips_cpu_irq_init(0);
59 rm7k_cpu_irq_init(8); 86 rm7k_cpu_irq_init(8);
60 87
diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c
index 91d9637143d7..1379c76845dc 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)
381 * shut down ethernet ports, just to be sure our memory doesn't get 381 * shut down ethernet ports, just to be sure our memory doesn't get
382 * corrupted by random ethernet traffic. 382 * corrupted by random ethernet traffic.
383 */ 383 */
384 MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8); 384 MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8);
385 MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8); 385 MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8);
386 MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(2), 0xff << 8); 386 MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(2), 0xff << 8);
387 MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8); 387 MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8);
388 MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8); 388 MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8);
389 MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(2), 0xff << 8); 389 MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(2), 0xff << 8);
390 while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff); 390 while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff);
391 while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff); 391 while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff);
392 while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(2)) & 0xff); 392 while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(2)) & 0xff);
393 while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff); 393 while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff);
394 while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff); 394 while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff);
395 while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(2)) & 0xff); 395 while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(2)) & 0xff);
396 MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0), 396 MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0),
397 MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1); 397 MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1);
398 MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1), 398 MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1),
399 MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1); 399 MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1);
400 MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(2), 400 MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(2),
401 MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(2)) & ~1); 401 MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(2)) & ~1);
402 402
403 /* Turn off the Bit-Error LED */ 403 /* Turn off the Bit-Error LED */
404 JAGUAR_FPGA_WRITE(0x80, CLR); 404 JAGUAR_FPGA_WRITE(0x80, CLR);
diff --git a/arch/mips/momentum/ocelot_3/Makefile b/arch/mips/momentum/ocelot_3/Makefile
index aab8fd89f830..8bcea64dd27b 100644
--- a/arch/mips/momentum/ocelot_3/Makefile
+++ b/arch/mips/momentum/ocelot_3/Makefile
@@ -5,4 +5,4 @@
5# removes any old dependencies. DON'T put your own dependencies here 5# removes any old dependencies. DON'T put your own dependencies here
6# unless it's something special (ie not a .c file). 6# unless it's something special (ie not a .c file).
7# 7#
8obj-y += int-handler.o irq.o prom.o reset.o setup.o 8obj-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 4522f09ed769..000000000000
--- a/arch/mips/momentum/ocelot_3/int-handler.S
+++ /dev/null
@@ -1,137 +0,0 @@
1/*
2 * Copyright 2002 Momentum Computer Inc.
3 * Author: Matthew Dharm <mdharm@momenco.com>
4 *
5 * Copyright 2001 MontaVista Software Inc.
6 * Author: jsun@mvista.com or jsun@junsun.net
7 *
8 * Copyright 2004 PMC-Sierra
9 * Author: Manish Lachwani (lachwani@pmc-sierra.com)
10 *
11 * Copyright (C) 2004 MontaVista Software Inc.
12 * Author: Manish Lachwani, mlachwani@mvista.com
13 *
14 * First-level interrupt dispatcher for Ocelot-3 board.
15 *
16 * This program is free software; you can redistribute it and/or modify it
17 * under the terms of the GNU General Public License as published by the
18 * Free Software Foundation; either version 2 of the License, or (at your
19 * option) any later version.
20 */
21#include <asm/asm.h>
22#include <asm/mipsregs.h>
23#include <asm/addrspace.h>
24#include <asm/regdef.h>
25#include <asm/stackframe.h>
26
27/*
28 * First level interrupt dispatcher for Ocelot-3 board
29 */
30 .align 5
31 NESTED(ocelot3_handle_int, PT_SIZE, sp)
32 SAVE_ALL
33 CLI
34 .set at
35
36 mfc0 t0, CP0_CAUSE
37 mfc0 t2, CP0_STATUS
38
39 and t0, t2
40
41 andi t1, t0, STATUSF_IP0 /* sw0 software interrupt (IRQ0) */
42 bnez t1, ll_sw0_irq
43
44 andi t1, t0, STATUSF_IP1 /* sw1 software interrupt (IRQ1) */
45 bnez t1, ll_sw1_irq
46
47 andi t1, t0, STATUSF_IP2 /* int0 hardware line (IRQ2) */
48 bnez t1, ll_pci0slot1_irq
49
50 andi t1, t0, STATUSF_IP3 /* int1 hardware line (IRQ3) */
51 bnez t1, ll_pci0slot2_irq
52
53 andi t1, t0, STATUSF_IP4 /* int2 hardware line (IRQ4) */
54 bnez t1, ll_pci1slot1_irq
55
56 andi t1, t0, STATUSF_IP5 /* int3 hardware line (IRQ5) */
57 bnez t1, ll_pci1slot2_irq
58
59 andi t1, t0, STATUSF_IP6 /* int4 hardware line (IRQ6) */
60 bnez t1, ll_uart_irq
61
62 andi t1, t0, STATUSF_IP7 /* cpu timer (IRQ7) */
63 bnez t1, ll_cputimer_irq
64
65 /* now look at extended interrupts */
66 mfc0 t0, CP0_CAUSE
67 cfc0 t1, CP0_S1_INTCONTROL
68
69 /* shift the mask 8 bits left to line up the bits */
70 sll t2, t1, 8
71
72 and t0, t2
73 srl t0, t0, 16
74
75 andi t1, t0, STATUSF_IP8 /* int6 hardware line (IRQ9) */
76 bnez t1, ll_mv64340_decode_irq
77
78 .set reorder
79
80 /* wrong alarm or masked ... */
81 j spurious_interrupt
82 nop
83 END(ocelot3_handle_int)
84
85 .align 5
86ll_sw0_irq:
87 li a0, 0 /* IRQ 1 */
88 move a1, sp
89 jal do_IRQ
90 j ret_from_irq
91ll_sw1_irq:
92 li a0, 1 /* IRQ 2 */
93 move a1, sp
94 jal do_IRQ
95 j ret_from_irq
96
97ll_pci0slot1_irq:
98 li a0, 2 /* IRQ 3 */
99 move a1, sp
100 jal do_IRQ
101 j ret_from_irq
102
103ll_pci0slot2_irq:
104 li a0, 3 /* IRQ 4 */
105 move a1, sp
106 jal do_IRQ
107 j ret_from_irq
108
109ll_pci1slot1_irq:
110 li a0, 4 /* IRQ 5 */
111 move a1, sp
112 jal do_IRQ
113 j ret_from_irq
114
115ll_pci1slot2_irq:
116 li a0, 5 /* IRQ 6 */
117 move a1, sp
118 jal do_IRQ
119 j ret_from_irq
120
121ll_uart_irq:
122 li a0, 6 /* IRQ 7 */
123 move a1, sp
124 jal do_IRQ
125 j ret_from_irq
126
127ll_cputimer_irq:
128 li a0, 7 /* IRQ 8 */
129 move a1, sp
130 jal do_IRQ
131 j ret_from_irq
132
133ll_mv64340_decode_irq:
134 move a0, sp
135 jal ll_mv64340_irq
136 j ret_from_irq
137
diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c
index 42464dbd4ad2..87c63c340ae3 100644
--- a/arch/mips/momentum/ocelot_3/irq.c
+++ b/arch/mips/momentum/ocelot_3/irq.c
@@ -53,8 +53,6 @@
53#include <asm/mipsregs.h> 53#include <asm/mipsregs.h>
54#include <asm/system.h> 54#include <asm/system.h>
55 55
56extern asmlinkage void ocelot3_handle_int(void);
57
58static struct irqaction cascade_mv64340 = { 56static struct irqaction cascade_mv64340 = {
59 no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL 57 no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL
60}; 58};
@@ -67,9 +65,6 @@ void __init arch_init_irq(void)
67 */ 65 */
68 clear_c0_status(ST0_IM | ST0_BEV); 66 clear_c0_status(ST0_IM | ST0_BEV);
69 67
70 /* Sets the first-level interrupt dispatcher. */
71 set_except_vector(0, ocelot3_handle_int);
72 mips_cpu_irq_init(0);
73 rm7k_cpu_irq_init(8); 68 rm7k_cpu_irq_init(8);
74 69
75 /* set up the cascading interrupts */ 70 /* set up the cascading interrupts */
@@ -79,3 +74,36 @@ void __init arch_init_irq(void)
79 set_c0_status(ST0_IM); /* IE in the status register */ 74 set_c0_status(ST0_IM); /* IE in the status register */
80 75
81} 76}
77
78asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
79{
80 unsigned int pending = read_c0_cause() & read_c0_status();
81
82 if (pending & STATUSF_IP0)
83 do_IRQ(0, regs);
84 else if (pending & STATUSF_IP1)
85 do_IRQ(1, regs);
86 else if (pending & STATUSF_IP2)
87 do_IRQ(2, regs);
88 else if (pending & STATUSF_IP3)
89 do_IRQ(3, regs);
90 else if (pending & STATUSF_IP4)
91 do_IRQ(4, regs);
92 else if (pending & STATUSF_IP5)
93 do_IRQ(5, regs);
94 else if (pending & STATUSF_IP6)
95 do_IRQ(6, regs);
96 else if (pending & STATUSF_IP7)
97 do_IRQ(7, regs);
98 else {
99 /*
100 * Now look at the extended interrupts
101 */
102 pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
103
104 if (pending & STATUSF_IP8)
105 ll_mv64340_irq(regs);
106 else
107 spurious_interrupt(regs);
108 }
109}
diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c
index 370e75d0e75c..c69195234309 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)
329 /* shut down ethernet ports, just to be sure our memory doesn't get 329 /* shut down ethernet ports, just to be sure our memory doesn't get
330 * corrupted by random ethernet traffic. 330 * corrupted by random ethernet traffic.
331 */ 331 */
332 MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8); 332 MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8);
333 MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8); 333 MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8);
334 MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8); 334 MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8);
335 MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8); 335 MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8);
336 do {} 336 do {}
337 while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff); 337 while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff);
338 do {} 338 do {}
339 while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff); 339 while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff);
340 do {} 340 do {}
341 while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff); 341 while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff);
342 do {} 342 do {}
343 while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff); 343 while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff);
344 MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0), 344 MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0),
345 MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1); 345 MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1);
346 MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1), 346 MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1),
347 MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1); 347 MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1);
348 348
349 /* Turn off the Bit-Error LED */ 349 /* Turn off the Bit-Error LED */
350 OCELOT_FPGA_WRITE(0x80, CLR); 350 OCELOT_FPGA_WRITE(0x80, CLR);
diff --git a/arch/mips/momentum/ocelot_c/Makefile b/arch/mips/momentum/ocelot_c/Makefile
index 91240777f978..94802b4db472 100644
--- a/arch/mips/momentum/ocelot_c/Makefile
+++ b/arch/mips/momentum/ocelot_c/Makefile
@@ -2,7 +2,7 @@
2# Makefile for Momentum Computer's Ocelot-C and -CS boards. 2# Makefile for Momentum Computer's Ocelot-C and -CS boards.
3# 3#
4 4
5obj-y += cpci-irq.o int-handler.o irq.o prom.o reset.o \ 5obj-y += cpci-irq.o irq.o prom.o reset.o \
6 setup.o uart-irq.o 6 setup.o uart-irq.o
7 7
8obj-$(CONFIG_KGDB) += dbg_io.o 8obj-$(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 52349d9bf1be..000000000000
--- a/arch/mips/momentum/ocelot_c/int-handler.S
+++ /dev/null
@@ -1,102 +0,0 @@
1/*
2 * Copyright 2002 Momentum Computer Inc.
3 * Author: Matthew Dharm <mdharm@momenco.com>
4 *
5 * Copyright 2001 MontaVista Software Inc.
6 * Author: jsun@mvista.com or jsun@junsun.net
7 *
8 * First-level interrupt dispatcher for Ocelot-CS board.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15#include <asm/asm.h>
16#include <asm/mipsregs.h>
17#include <asm/addrspace.h>
18#include <asm/regdef.h>
19#include <asm/stackframe.h>
20#include "ocelot_c_fpga.h"
21
22/*
23 * First level interrupt dispatcher for Ocelot-CS board
24 */
25 .align 5
26 NESTED(ocelot_handle_int, PT_SIZE, sp)
27 SAVE_ALL
28 CLI
29 .set at
30 mfc0 t0, CP0_CAUSE
31 mfc0 t2, CP0_STATUS
32
33 and t0, t2
34
35 andi t1, t0, STATUSF_IP0 /* sw0 software interrupt */
36 bnez t1, ll_sw0_irq
37 andi t1, t0, STATUSF_IP1 /* sw1 software interrupt */
38 bnez t1, ll_sw1_irq
39 andi t1, t0, STATUSF_IP2 /* int0 hardware line */
40 bnez t1, ll_scsi_irq
41 andi t1, t0, STATUSF_IP3 /* int1 hardware line */
42 bnez t1, ll_uart_decode_irq
43 andi t1, t0, STATUSF_IP4 /* int2 hardware line */
44 bnez t1, ll_pmc_irq
45 andi t1, t0, STATUSF_IP5 /* int3 hardware line */
46 bnez t1, ll_cpci_decode_irq
47 andi t1, t0, STATUSF_IP6 /* int4 hardware line */
48 bnez t1, ll_mv64340_decode_irq
49 andi t1, t0, STATUSF_IP7 /* cpu timer */
50 bnez t1, ll_cputimer_irq
51
52 .set reorder
53
54 /* wrong alarm or masked ... */
55 j spurious_interrupt
56 nop
57 END(ocelot_handle_int)
58
59 .align 5
60ll_sw0_irq:
61 li a0, 0
62 move a1, sp
63 jal do_IRQ
64 j ret_from_irq
65ll_sw1_irq:
66 li a0, 1
67 move a1, sp
68 jal do_IRQ
69 j ret_from_irq
70ll_scsi_irq:
71 li a0, 2
72 move a1, sp
73 jal do_IRQ
74 j ret_from_irq
75
76ll_uart_decode_irq:
77 move a0, sp
78 jal ll_uart_irq
79 j ret_from_irq
80
81ll_pmc_irq:
82 li a0, 4
83 move a1, sp
84 jal do_IRQ
85 j ret_from_irq
86
87ll_cpci_decode_irq:
88 move a0, sp
89 jal ll_cpci_irq
90 j ret_from_irq
91
92ll_mv64340_decode_irq:
93 move a0, sp
94 jal ll_mv64340_irq
95 j ret_from_irq
96
97ll_cputimer_irq:
98 li a0, 7
99 move a1, sp
100 jal do_IRQ
101 j ret_from_irq
102
diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c
index a5764bc20e36..86f61ce59e53 100644
--- a/arch/mips/momentum/ocelot_c/irq.c
+++ b/arch/mips/momentum/ocelot_c/irq.c
@@ -48,7 +48,6 @@
48#include <asm/mipsregs.h> 48#include <asm/mipsregs.h>
49#include <asm/system.h> 49#include <asm/system.h>
50 50
51extern asmlinkage void ocelot_handle_int(void);
52extern void uart_irq_init(void); 51extern void uart_irq_init(void);
53extern void cpci_irq_init(void); 52extern void cpci_irq_init(void);
54 53
@@ -60,6 +59,33 @@ static struct irqaction cascade_mv64340 = {
60 no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade via MV64340", NULL, NULL 59 no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade via MV64340", NULL, NULL
61}; 60};
62 61
62extern void ll_uart_irq(struct pt_regs *regs);
63extern void ll_cpci_irq(struct pt_regs *regs);
64
65asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
66{
67 unsigned int pending = read_c0_cause() & read_c0_status();
68
69 if (pending & STATUSF_IP0)
70 do_IRQ(0, regs);
71 else if (pending & STATUSF_IP1)
72 do_IRQ(1, regs);
73 else if (pending & STATUSF_IP2)
74 do_IRQ(2, regs);
75 else if (pending & STATUSF_IP3)
76 ll_uart_irq(regs);
77 else if (pending & STATUSF_IP4)
78 do_IRQ(4, regs);
79 else if (pending & STATUSF_IP5)
80 ll_cpci_irq(regs);
81 else if (pending & STATUSF_IP6)
82 ll_mv64340_irq(regs);
83 else if (pending & STATUSF_IP7)
84 do_IRQ(7, regs);
85 else
86 spurious_interrupt(regs);
87}
88
63void __init arch_init_irq(void) 89void __init arch_init_irq(void)
64{ 90{
65 /* 91 /*
@@ -68,8 +94,6 @@ void __init arch_init_irq(void)
68 */ 94 */
69 clear_c0_status(ST0_IM); 95 clear_c0_status(ST0_IM);
70 96
71 /* Sets the first-level interrupt dispatcher. */
72 set_except_vector(0, ocelot_handle_int);
73 mips_cpu_irq_init(0); 97 mips_cpu_irq_init(0);
74 98
75 /* set up the cascading interrupts */ 99 /* set up the cascading interrupts */
diff --git a/arch/mips/momentum/ocelot_g/Makefile b/arch/mips/momentum/ocelot_g/Makefile
index e5f1cb086973..adb5665d40a9 100644
--- a/arch/mips/momentum/ocelot_g/Makefile
+++ b/arch/mips/momentum/ocelot_g/Makefile
@@ -2,7 +2,7 @@
2# Makefile for Momentum Computer's Ocelot-G board. 2# Makefile for Momentum Computer's Ocelot-G board.
3# 3#
4 4
5obj-y += int-handler.o irq.o gt-irq.o prom.o reset.o setup.o 5obj-y += irq.o gt-irq.o prom.o reset.o setup.o
6obj-$(CONFIG_KGDB) += dbg_io.o 6obj-$(CONFIG_KGDB) += dbg_io.o
7 7
8EXTRA_AFLAGS := $(CFLAGS) 8EXTRA_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 772e8f713176..000000000000
--- a/arch/mips/momentum/ocelot_g/int-handler.S
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 * Copyright 2001 MontaVista Software Inc.
3 * Author: jsun@mvista.com or jsun@junsun.net
4 *
5 * First-level interrupt dispatcher for ocelot board.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12#include <asm/asm.h>
13#include <asm/mipsregs.h>
14#include <asm/addrspace.h>
15#include <asm/regdef.h>
16#include <asm/stackframe.h>
17
18/*
19 * first level interrupt dispatcher for ocelot board -
20 * We check for the timer first, then check PCI ints A and D.
21 * Then check for serial IRQ and fall through.
22 */
23 .align 5
24 NESTED(ocelot_handle_int, PT_SIZE, sp)
25 SAVE_ALL
26 CLI
27 .set at
28 mfc0 t0, CP0_CAUSE
29 mfc0 t2, CP0_STATUS
30
31 and t0, t2
32
33 andi t1, t0, STATUSF_IP2 /* int0 hardware line */
34 bnez t1, ll_pri_enet_irq
35 andi t1, t0, STATUSF_IP3 /* int1 hardware line */
36 bnez t1, ll_sec_enet_irq
37 andi t1, t0, STATUSF_IP4 /* int2 hardware line */
38 bnez t1, ll_uart_irq
39 andi t1, t0, STATUSF_IP5 /* int3 hardware line */
40 bnez t1, ll_cpci_irq
41 andi t1, t0, STATUSF_IP6 /* int4 hardware line */
42 bnez t1, ll_galileo_p0_irq
43 andi t1, t0, STATUSF_IP7 /* cpu timer */
44 bnez t1, ll_cputimer_irq
45
46 /* now look at the extended interrupts */
47 mfc0 t0, CP0_CAUSE
48 cfc0 t1, CP0_S1_INTCONTROL
49
50 /* shift the mask 8 bits left to line up the bits */
51 sll t2, t1, 8
52
53 and t0, t2
54 srl t0, t0, 16
55
56 andi t1, t0, STATUSF_IP8 /* int6 hardware line */
57 bnez t1, ll_galileo_p1_irq
58 andi t1, t0, STATUSF_IP9 /* int7 hardware line */
59 bnez t1, ll_pmc_irq
60 andi t1, t0, STATUSF_IP10 /* int8 hardware line */
61 bnez t1, ll_cpci_abcd_irq
62 andi t1, t0, STATUSF_IP11 /* int9 hardware line */
63 bnez t1, ll_testpoint_irq
64
65 .set reorder
66
67 /* wrong alarm or masked ... */
68 j spurious_interrupt
69 nop
70 END(ocelot_handle_int)
71
72 .align 5
73ll_pri_enet_irq:
74 li a0, 2
75 move a1, sp
76 jal do_IRQ
77 j ret_from_irq
78
79ll_sec_enet_irq:
80 li a0, 3
81 move a1, sp
82 jal do_IRQ
83 j ret_from_irq
84
85ll_uart_irq:
86 li a0, 4
87 move a1, sp
88 jal do_IRQ
89 j ret_from_irq
90
91ll_cpci_irq:
92 li a0, 5
93 move a1, sp
94 jal do_IRQ
95 j ret_from_irq
96
97ll_galileo_p0_irq:
98 li a0, 6
99 move a1, sp
100 jal do_IRQ
101 j ret_from_irq
102
103ll_cputimer_irq:
104 li a0, 7
105 move a1, sp
106 jal do_IRQ
107 j ret_from_irq
108
109ll_galileo_p1_irq:
110 li a0, 8
111 move a1, sp
112 jal do_IRQ
113 j ret_from_irq
114
115ll_pmc_irq:
116 li a0, 9
117 move a1, sp
118 jal do_IRQ
119 j ret_from_irq
120
121ll_cpci_abcd_irq:
122 li a0, 10
123 move a1, sp
124 jal do_IRQ
125 j ret_from_irq
126
127ll_testpoint_irq:
128 li a0, 11
129 move a1, sp
130 jal do_IRQ
131 j ret_from_irq
diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c
index 5eb85b164205..7a4a419804f1 100644
--- a/arch/mips/momentum/ocelot_g/irq.c
+++ b/arch/mips/momentum/ocelot_g/irq.c
@@ -48,7 +48,41 @@
48#include <asm/mipsregs.h> 48#include <asm/mipsregs.h>
49#include <asm/system.h> 49#include <asm/system.h>
50 50
51extern asmlinkage void ocelot_handle_int(void); 51asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
52{
53 unsigned int pending = read_c0_cause() & read_c0_status();
54
55 if (pending & STATUSF_IP2)
56 do_IRQ(2, regs);
57 else if (pending & STATUSF_IP3)
58 do_IRQ(3, regs);
59 else if (pending & STATUSF_IP4)
60 do_IRQ(4, regs);
61 else if (pending & STATUSF_IP5)
62 do_IRQ(5, regs);
63 else if (pending & STATUSF_IP6)
64 do_IRQ(6, regs);
65 else if (pending & STATUSF_IP7)
66 do_IRQ(7, regs);
67 else {
68 /*
69 * Now look at the extended interrupts
70 */
71 pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
72
73 if (pending & STATUSF_IP8)
74 do_IRQ(8, regs);
75 else if (pending & STATUSF_IP9)
76 do_IRQ(9, regs);
77 else if (pending & STATUSF_IP10)
78 do_IRQ(10, regs);
79 else if (pending & STATUSF_IP11)
80 do_IRQ(11, regs);
81 else
82 spurious_interrupt(regs);
83 }
84}
85
52extern void gt64240_irq_init(void); 86extern void gt64240_irq_init(void);
53 87
54void __init arch_init_irq(void) 88void __init arch_init_irq(void)
@@ -60,8 +94,6 @@ void __init arch_init_irq(void)
60 clear_c0_status(ST0_IM); 94 clear_c0_status(ST0_IM);
61 local_irq_disable(); 95 local_irq_disable();
62 96
63 /* Sets the first-level interrupt dispatcher. */
64 set_except_vector(0, ocelot_handle_int);
65 mips_cpu_irq_init(0); 97 mips_cpu_irq_init(0);
66 rm7k_cpu_irq_init(8); 98 rm7k_cpu_irq_init(8);
67 99
diff --git a/arch/mips/philips/pnx8550/common/Makefile b/arch/mips/philips/pnx8550/common/Makefile
index 6e38f3bc443c..b7c638166e9f 100644
--- a/arch/mips/philips/pnx8550/common/Makefile
+++ b/arch/mips/philips/pnx8550/common/Makefile
@@ -22,6 +22,6 @@
22# under Linux. 22# under Linux.
23# 23#
24 24
25obj-y := setup.o prom.o mipsIRQ.o int.o reset.o time.o proc.o platform.o 25obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o
26obj-$(CONFIG_PCI) += pci.o 26obj-$(CONFIG_PCI) += pci.o
27obj-$(CONFIG_KGDB) += gdb_hook.o 27obj-$(CONFIG_KGDB) += gdb_hook.o
diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c
index c500e2d41f2c..39ee6314f627 100644
--- a/arch/mips/philips/pnx8550/common/int.c
+++ b/arch/mips/philips/pnx8550/common/int.c
@@ -38,8 +38,6 @@
38#include <int.h> 38#include <int.h>
39#include <uart.h> 39#include <uart.h>
40 40
41extern asmlinkage void cp0_irqdispatch(void);
42
43static DEFINE_SPINLOCK(irq_lock); 41static DEFINE_SPINLOCK(irq_lock);
44 42
45/* default prio for interrupts */ 43/* default prio for interrupts */
@@ -55,7 +53,7 @@ static char gic_prio[PNX8550_INT_GIC_TOTINT] = {
55 1 // 70 53 1 // 70
56}; 54};
57 55
58void hw0_irqdispatch(int irq, struct pt_regs *regs) 56static void hw0_irqdispatch(int irq, struct pt_regs *regs)
59{ 57{
60 /* find out which interrupt */ 58 /* find out which interrupt */
61 irq = PNX8550_GIC_VECTOR_0 >> 3; 59 irq = PNX8550_GIC_VECTOR_0 >> 3;
@@ -68,7 +66,7 @@ void hw0_irqdispatch(int irq, struct pt_regs *regs)
68} 66}
69 67
70 68
71void timer_irqdispatch(int irq, struct pt_regs *regs) 69static void timer_irqdispatch(int irq, struct pt_regs *regs)
72{ 70{
73 irq = (0x01c0 & read_c0_config7()) >> 6; 71 irq = (0x01c0 & read_c0_config7()) >> 6;
74 72
@@ -88,6 +86,20 @@ void timer_irqdispatch(int irq, struct pt_regs *regs)
88 } 86 }
89} 87}
90 88
89asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
90{
91 unsigned int pending = read_c0_status() & read_c0_cause();
92
93 if (pending & STATUSF_IP2)
94 do_IRQ(2, regs);
95 else if (pending & STATUSF_IP7) {
96 if (read_c0_config7() & 0x01c0)
97 timer_irqdispatch(7, regs);
98 }
99
100 spurious_interrupt(regs);
101}
102
91static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) 103static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
92{ 104{
93 unsigned long status = read_c0_status(); 105 unsigned long status = read_c0_status();
@@ -223,9 +235,6 @@ void __init arch_init_irq(void)
223 int i; 235 int i;
224 int configPR; 236 int configPR;
225 237
226 /* init of cp0 interrupts */
227 set_except_vector(0, cp0_irqdispatch);
228
229 for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) { 238 for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) {
230 irq_desc[i].handler = &level_irq_type; 239 irq_desc[i].handler = &level_irq_type;
231 pnx8550_ack(i); /* mask the irq just in case */ 240 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 338bffda3fab..000000000000
--- a/arch/mips/philips/pnx8550/common/mipsIRQ.S
+++ /dev/null
@@ -1,76 +0,0 @@
1/*
2 * Copyright (c) 2002 Philips, Inc. All rights.
3 * Copyright (c) 2002 Red Hat, Inc. All rights.
4 *
5 * This software may be freely redistributed under the terms of the
6 * GNU General Public License.
7 *
8 * You should have received a copy of the GNU General Public License
9 * along with this program; if not, write to the Free Software
10 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
11 *
12 * Based upon arch/mips/galileo-boards/ev64240/int-handler.S
13 *
14 */
15#include <asm/asm.h>
16#include <asm/mipsregs.h>
17#include <asm/addrspace.h>
18#include <asm/regdef.h>
19#include <asm/stackframe.h>
20
21/*
22 * cp0_irqdispatch
23 *
24 * Code to handle in-core interrupt exception.
25 */
26
27 .align 5
28 .set reorder
29 .set noat
30 NESTED(cp0_irqdispatch, PT_SIZE, sp)
31 SAVE_ALL
32 CLI
33 .set at
34 mfc0 t0,CP0_CAUSE
35 mfc0 t2,CP0_STATUS
36
37 and t0,t2
38
39 andi t1,t0,STATUSF_IP2 /* int0 hardware line */
40 bnez t1,ll_hw0_irq
41 nop
42
43 andi t1,t0,STATUSF_IP7 /* int5 hardware line */
44 bnez t1,ll_timer_irq
45 nop
46
47 /* wrong alarm or masked ... */
48
49 j spurious_interrupt
50 nop
51 END(cp0_irqdispatch)
52
53 .align 5
54 .set reorder
55ll_hw0_irq:
56 li a0,2
57 move a1,sp
58 jal hw0_irqdispatch
59 nop
60 j ret_from_irq
61 nop
62
63 .align 5
64 .set reorder
65ll_timer_irq:
66 mfc0 t3,CP0_CONFIG,7
67 andi t4,t3,0x01c0
68 beqz t4,ll_timer_out
69 nop
70 li a0,7
71 move a1,sp
72 jal timer_irqdispatch
73 nop
74
75ll_timer_out: j ret_from_irq
76 nop
diff --git a/arch/mips/philips/pnx8550/common/platform.c b/arch/mips/philips/pnx8550/common/platform.c
index a592260fd673..5436b4b97455 100644
--- a/arch/mips/philips/pnx8550/common/platform.c
+++ b/arch/mips/philips/pnx8550/common/platform.c
@@ -18,6 +18,7 @@
18#include <linux/resource.h> 18#include <linux/resource.h>
19#include <linux/serial.h> 19#include <linux/serial.h>
20#include <linux/serial_ip3106.h> 20#include <linux/serial_ip3106.h>
21#include <linux/platform_device.h>
21 22
22#include <int.h> 23#include <int.h>
23#include <usb.h> 24#include <usb.h>
diff --git a/arch/mips/pmc-sierra/yosemite/Makefile b/arch/mips/pmc-sierra/yosemite/Makefile
index ae96a71a3089..e931e0d44229 100644
--- a/arch/mips/pmc-sierra/yosemite/Makefile
+++ b/arch/mips/pmc-sierra/yosemite/Makefile
@@ -2,7 +2,7 @@
2# Makefile for the PMC-Sierra Titan 2# Makefile for the PMC-Sierra Titan
3# 3#
4 4
5obj-y += irq-handler.o irq.o i2c-yosemite.o prom.o py-console.o setup.o 5obj-y += irq.o i2c-yosemite.o prom.o py-console.o setup.o
6 6
7obj-$(CONFIG_KGDB) += dbg_io.o 7obj-$(CONFIG_KGDB) += dbg_io.o
8obj-$(CONFIG_SMP) += smp.o 8obj-$(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 33b9c40d4f5c..000000000000
--- a/arch/mips/pmc-sierra/yosemite/irq-handler.S
+++ /dev/null
@@ -1,93 +0,0 @@
1/*
2 * Copyright 2003, 04 PMC-Sierra Inc.
3 * Author: Manish Lachwani (lachwani@pmc-sierra.com
4 * Copyright 2004 Ralf Baechle (ralf@linux-mips.org)
5 *
6 * First-level interrupt router for the PMC-Sierra Titan board
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * Titan supports Hypertransport or PCI but not both. Hence, one interrupt
14 * line is shared between the PCI slot A and Hypertransport. This is the
15 * Processor INTB #0.
16 */
17
18#include <linux/config.h>
19#include <asm/asm.h>
20#include <asm/mipsregs.h>
21#include <asm/addrspace.h>
22#include <asm/regdef.h>
23#include <asm/stackframe.h>
24
25 .align 5
26 NESTED(titan_handle_int, PT_SIZE, sp)
27 SAVE_ALL
28 CLI
29 .set at
30 .set noreorder
31 la ra, ret_from_irq
32 mfc0 t0, CP0_CAUSE
33 mfc0 t2, CP0_STATUS
34
35 and t0, t2
36
37 andi t2, t0, STATUSF_IP7 /* INTB5 hardware line */
38 bnez t2, ll_timer_irq /* Timer */
39 andi t1, t0, STATUSF_IP2 /* INTB0 hardware line */
40 bnez t1, ll_pcia_irq /* 64-bit PCI */
41 andi t2, t0, STATUSF_IP3 /* INTB1 hardware line */
42 bnez t2, ll_pcib_irq /* second 64-bit PCI slot */
43 andi t1, t0, STATUSF_IP4 /* INTB2 hardware line */
44 bnez t1, ll_duart_irq /* UART */
45 andi t2, t0, STATUSF_IP5 /* SMP inter-core interrupts */
46 bnez t2, ll_smp_irq
47 andi t1, t0, STATUSF_IP6
48 bnez t1, ll_ht_irq /* Hypertransport */
49
50 move a0, sp
51 j do_extended_irq
52 END(titan_handle_int)
53
54 .set reorder
55 .align 5
56
57ll_pcia_irq:
58 li a0, 2
59 move a1, sp
60#ifdef CONFIG_HYPERTRANSPORT
61 j ll_ht_smp_irq_handler
62#else
63 j do_IRQ
64#endif
65
66ll_pcib_irq:
67 li a0, 3
68 move a1, sp
69 j do_IRQ
70
71ll_duart_irq:
72 li a0, 4
73 move a1, sp
74 j do_IRQ
75
76ll_smp_irq:
77 li a0, 5
78 move a1, sp
79#ifdef CONFIG_SMP
80 j titan_mailbox_irq
81#else
82 j do_IRQ
83#endif
84
85ll_ht_irq:
86 li a0, 6
87 move a1, sp
88 j ll_ht_smp_irq_handler
89
90ll_timer_irq:
91 li a0, 7
92 move a1, sp
93 j do_IRQ
diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c
index f4e2897d9bf7..a1f524fc4c10 100644
--- a/arch/mips/pmc-sierra/yosemite/irq.c
+++ b/arch/mips/pmc-sierra/yosemite/irq.c
@@ -2,6 +2,8 @@
2 * Copyright (C) 2003 PMC-Sierra Inc. 2 * Copyright (C) 2003 PMC-Sierra Inc.
3 * Author: Manish Lachwani (lachwani@pmc-sierra.com) 3 * Author: Manish Lachwani (lachwani@pmc-sierra.com)
4 * 4 *
5 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
6 *
5 * This program is free software; you can redistribute it and/or modify it 7 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the 8 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your 9 * Free Software Foundation; either version 2 of the License, or (at your
@@ -55,7 +57,6 @@
55#define HYPERTRANSPORT_INTC 0x7a /* INTC# */ 57#define HYPERTRANSPORT_INTC 0x7a /* INTC# */
56#define HYPERTRANSPORT_INTD 0x7b /* INTD# */ 58#define HYPERTRANSPORT_INTD 0x7b /* INTD# */
57 59
58extern asmlinkage void titan_handle_int(void);
59extern void jaguar_mailbox_irq(struct pt_regs *); 60extern void jaguar_mailbox_irq(struct pt_regs *);
60 61
61/* 62/*
@@ -125,6 +126,35 @@ asmlinkage void do_extended_irq(struct pt_regs *regs)
125 126
126} 127}
127 128
129asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
130{
131 unsigned int cause = read_c0_cause();
132 unsigned int status = read_c0_status();
133 unsigned int pending = cause & status;
134
135 if (pending & STATUSF_IP7) {
136 do_IRQ(7, regs);
137 } else if (pending & STATUSF_IP2) {
138#ifdef CONFIG_HYPERTRANSPORT
139 ll_ht_smp_irq_handler(2, regs);
140#else
141 do_IRQ(2, regs);
142#endif
143 } else if (pending & STATUSF_IP3) {
144 do_IRQ(3, regs);
145 } else if (pending & STATUSF_IP4) {
146 do_IRQ(4, regs);
147 } else if (pending & STATUSF_IP5) {
148#ifdef CONFIG_SMP
149 titan_mailbox_irq(regs);
150#else
151 do_IRQ(5, regs);
152#endif
153 } else if (pending & STATUSF_IP6) {
154 do_IRQ(4, regs);
155 }
156}
157
128#ifdef CONFIG_KGDB 158#ifdef CONFIG_KGDB
129extern void init_second_port(void); 159extern void init_second_port(void);
130#endif 160#endif
@@ -136,7 +166,6 @@ void __init arch_init_irq(void)
136{ 166{
137 clear_c0_status(ST0_IM); 167 clear_c0_status(ST0_IM);
138 168
139 set_except_vector(0, titan_handle_int);
140 mips_cpu_irq_init(0); 169 mips_cpu_irq_init(0);
141 rm7k_cpu_irq_init(8); 170 rm7k_cpu_irq_init(8);
142 rm9k_cpu_irq_init(12); 171 rm9k_cpu_irq_init(12);
diff --git a/arch/mips/qemu/Makefile b/arch/mips/qemu/Makefile
index 6a8e8bcef552..730f459f3e99 100644
--- a/arch/mips/qemu/Makefile
+++ b/arch/mips/qemu/Makefile
@@ -2,6 +2,6 @@
2# Makefile for Qemu specific kernel interface routines under Linux. 2# Makefile for Qemu specific kernel interface routines under Linux.
3# 3#
4 4
5obj-y = q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o 5obj-y = q-firmware.o q-irq.o q-mem.o q-setup.o
6 6
7obj-$(CONFIG_SMP) += q-smp.o 7obj-$(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 6e3dfe5eb14b..000000000000
--- a/arch/mips/qemu/q-int.S
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * Qemu interrupt handler code.
3 *
4 * Copyright (C) 2005 by Ralf Baechle
5 */
6#include <asm/asm.h>
7#include <asm/regdef.h>
8#include <asm/stackframe.h>
9
10 .align 5
11 NESTED(qemu_handle_int, PT_SIZE, sp)
12 SAVE_ALL
13 CLI
14 move a0, sp
15 PTR_LA ra, ret_from_irq
16 j do_qemu_int
17 END(qemu_handle_int)
diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c
index 2c4e0704ff10..3352374c4c7d 100644
--- a/arch/mips/qemu/q-irq.c
+++ b/arch/mips/qemu/q-irq.c
@@ -9,7 +9,7 @@
9 9
10extern asmlinkage void qemu_handle_int(void); 10extern asmlinkage void qemu_handle_int(void);
11 11
12asmlinkage void do_qemu_int(struct pt_regs *regs) 12asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
13{ 13{
14 unsigned int pending = read_c0_status() & read_c0_cause(); 14 unsigned int pending = read_c0_status() & read_c0_cause();
15 15
@@ -29,7 +29,6 @@ asmlinkage void do_qemu_int(struct pt_regs *regs)
29 29
30void __init arch_init_irq(void) 30void __init arch_init_irq(void)
31{ 31{
32 set_except_vector(0, qemu_handle_int);
33 mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK; /* 100MHz */ 32 mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK; /* 100MHz */
34 33
35 init_i8259_irqs(); 34 init_i8259_irqs();
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
index eb0820fe50bd..6aa4c0cd169c 100644
--- a/arch/mips/sgi-ip22/Makefile
+++ b/arch/mips/sgi-ip22/Makefile
@@ -3,7 +3,7 @@
3# under Linux. 3# under Linux.
4# 4#
5 5
6obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-irq.o ip22-berr.o \ 6obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-berr.o \
7 ip22-time.o ip22-nvram.o ip22-reset.o ip22-setup.o 7 ip22-time.o ip22-nvram.o ip22-reset.o ip22-setup.o
8 8
9obj-$(CONFIG_EISA) += ip22-eisa.o 9obj-$(CONFIG_EISA) += ip22-eisa.o
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index d16fb43b1a93..fc6a7e2b189c 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];
37static char lc2msk_to_irqnr[256]; 37static char lc2msk_to_irqnr[256];
38static char lc3msk_to_irqnr[256]; 38static char lc3msk_to_irqnr[256];
39 39
40extern asmlinkage void indyIRQ(void);
41extern int ip22_eisa_init(void); 40extern int ip22_eisa_init(void);
42 41
43static void enable_local0_irq(unsigned int irq) 42static void enable_local0_irq(unsigned int irq)
@@ -224,7 +223,7 @@ static struct hw_interrupt_type ip22_local3_irq_type = {
224 .end = end_local3_irq, 223 .end = end_local3_irq,
225}; 224};
226 225
227void indy_local0_irqdispatch(struct pt_regs *regs) 226static void indy_local0_irqdispatch(struct pt_regs *regs)
228{ 227{
229 u8 mask = sgint->istat0 & sgint->imask0; 228 u8 mask = sgint->istat0 & sgint->imask0;
230 u8 mask2; 229 u8 mask2;
@@ -242,7 +241,7 @@ void indy_local0_irqdispatch(struct pt_regs *regs)
242 return; 241 return;
243} 242}
244 243
245void indy_local1_irqdispatch(struct pt_regs *regs) 244static void indy_local1_irqdispatch(struct pt_regs *regs)
246{ 245{
247 u8 mask = sgint->istat1 & sgint->imask1; 246 u8 mask = sgint->istat1 & sgint->imask1;
248 u8 mask2; 247 u8 mask2;
@@ -262,7 +261,7 @@ void indy_local1_irqdispatch(struct pt_regs *regs)
262 261
263extern void ip22_be_interrupt(int irq, struct pt_regs *regs); 262extern void ip22_be_interrupt(int irq, struct pt_regs *regs);
264 263
265void indy_buserror_irq(struct pt_regs *regs) 264static void indy_buserror_irq(struct pt_regs *regs)
266{ 265{
267 int irq = SGI_BUSERR_IRQ; 266 int irq = SGI_BUSERR_IRQ;
268 267
@@ -307,6 +306,56 @@ static struct irqaction map1_cascade = {
307#define SGI_INTERRUPTS SGINT_LOCAL3 306#define SGI_INTERRUPTS SGINT_LOCAL3
308#endif 307#endif
309 308
309extern void indy_r4k_timer_interrupt(struct pt_regs *regs);
310extern void indy_8254timer_irq(struct pt_regs *regs);
311
312/*
313 * IRQs on the INDY look basically (barring software IRQs which we don't use
314 * at all) like:
315 *
316 * MIPS IRQ Source
317 * -------- ------
318 * 0 Software (ignored)
319 * 1 Software (ignored)
320 * 2 Local IRQ level zero
321 * 3 Local IRQ level one
322 * 4 8254 Timer zero
323 * 5 8254 Timer one
324 * 6 Bus Error
325 * 7 R4k timer (what we use)
326 *
327 * We handle the IRQ according to _our_ priority which is:
328 *
329 * Highest ---- R4k Timer
330 * Local IRQ zero
331 * Local IRQ one
332 * Bus Error
333 * 8254 Timer zero
334 * Lowest ---- 8254 Timer one
335 *
336 * then we just return, if multiple IRQs are pending then we will just take
337 * another exception, big deal.
338 */
339
340asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
341{
342 unsigned int pending = read_c0_cause();
343
344 /*
345 * First we check for r4k counter/timer IRQ.
346 */
347 if (pending & CAUSEF_IP7)
348 indy_r4k_timer_interrupt(regs);
349 else if (pending & CAUSEF_IP2)
350 indy_local0_irqdispatch(regs);
351 else if (pending & CAUSEF_IP3)
352 indy_local1_irqdispatch(regs);
353 else if (pending & CAUSEF_IP6)
354 indy_buserror_irq(regs);
355 else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
356 indy_8254timer_irq(regs);
357}
358
310extern void mips_cpu_irq_init(unsigned int irq_base); 359extern void mips_cpu_irq_init(unsigned int irq_base);
311 360
312void __init arch_init_irq(void) 361void __init arch_init_irq(void)
@@ -369,8 +418,6 @@ void __init arch_init_irq(void)
369 sgint->cmeimask0 = 0; 418 sgint->cmeimask0 = 0;
370 sgint->cmeimask1 = 0; 419 sgint->cmeimask1 = 0;
371 420
372 set_except_vector(0, indyIRQ);
373
374 /* init CPU irqs */ 421 /* init CPU irqs */
375 mips_cpu_irq_init(SGINT_CPU); 422 mips_cpu_irq_init(SGINT_CPU);
376 423
diff --git a/arch/mips/sgi-ip22/ip22-irq.S b/arch/mips/sgi-ip22/ip22-irq.S
deleted file mode 100644
index 6ccbd9e1d967..000000000000
--- a/arch/mips/sgi-ip22/ip22-irq.S
+++ /dev/null
@@ -1,118 +0,0 @@
1/*
2 * ip22-irq.S: Interrupt exception dispatch code for FullHouse and
3 * Guiness.
4 *
5 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
6 */
7
8#include <asm/asm.h>
9#include <asm/mipsregs.h>
10#include <asm/regdef.h>
11#include <asm/stackframe.h>
12
13/* A lot of complication here is taken away because:
14 *
15 * 1) We handle one interrupt and return, sitting in a loop and moving across
16 * all the pending IRQ bits in the cause register is _NOT_ the answer, the
17 * common case is one pending IRQ so optimize in that direction.
18 *
19 * 2) We need not check against bits in the status register IRQ mask, that
20 * would make this routine slow as hell.
21 *
22 * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
23 * between like BSD spl() brain-damage.
24 *
25 * Furthermore, the IRQs on the INDY look basically (barring software IRQs
26 * which we don't use at all) like:
27 *
28 * MIPS IRQ Source
29 * -------- ------
30 * 0 Software (ignored)
31 * 1 Software (ignored)
32 * 2 Local IRQ level zero
33 * 3 Local IRQ level one
34 * 4 8254 Timer zero
35 * 5 8254 Timer one
36 * 6 Bus Error
37 * 7 R4k timer (what we use)
38 *
39 * We handle the IRQ according to _our_ priority which is:
40 *
41 * Highest ---- R4k Timer
42 * Local IRQ zero
43 * Local IRQ one
44 * Bus Error
45 * 8254 Timer zero
46 * Lowest ---- 8254 Timer one
47 *
48 * then we just return, if multiple IRQs are pending then we will just take
49 * another exception, big deal.
50 */
51
52 .text
53 .set noreorder
54 .set noat
55 .align 5
56 NESTED(indyIRQ, PT_SIZE, sp)
57 SAVE_ALL
58 CLI
59 .set at
60 mfc0 s0, CP0_CAUSE # get irq mask
61
62 /* First we check for r4k counter/timer IRQ. */
63 andi a0, s0, CAUSEF_IP7
64 beq a0, zero, 1f
65 andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
66
67 /* Wheee, a timer interrupt. */
68 jal indy_r4k_timer_interrupt
69 move a0, sp # delay slot
70 j ret_from_irq
71 nop # delay slot
72
731:
74 beq a0, zero, 1f
75 andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
76
77 /* Wheee, local level zero interrupt. */
78 jal indy_local0_irqdispatch
79 move a0, sp # delay slot
80
81 j ret_from_irq
82 nop # delay slot
83
841:
85 beq a0, zero, 1f
86 andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
87
88 /* Wheee, local level one interrupt. */
89 jal indy_local1_irqdispatch
90 move a0, sp # delay slot
91 j ret_from_irq
92 nop # delay slot
93
941:
95 beq a0, zero, 1f
96 andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) # delay slot
97
98 /* Wheee, an asynchronous bus error... */
99 jal indy_buserror_irq
100 move a0, sp # delay slot
101 j ret_from_irq
102 nop # delay slot
103
1041:
105 /* Here by mistake? It is possible, that by the time we take
106 * the exception the IRQ pin goes low, so just leave if this
107 * is the case.
108 */
109 beq a0, zero, 1f
110 nop # delay slot
111
112 /* Must be one of the 8254 timers... */
113 jal indy_8254timer_irq
114 move a0, sp # delay slot
1151:
116 j ret_from_irq
117 nop # delay slot
118 END(indyIRQ)
diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile
index 4ba340780c35..686ba14e2882 100644
--- a/arch/mips/sgi-ip27/Makefile
+++ b/arch/mips/sgi-ip27/Makefile
@@ -2,7 +2,7 @@
2# Makefile for the IP27 specific kernel interface routines under Linux. 2# Makefile for the IP27 specific kernel interface routines under Linux.
3# 3#
4 4
5obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \ 5obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o \
6 ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o \ 6 ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o \
7 ip27-timer.o ip27-hubio.o ip27-xtalk.o 7 ip27-timer.o ip27-hubio.o ip27-xtalk.o
8 8
diff --git a/arch/mips/sgi-ip27/TODO b/arch/mips/sgi-ip27/TODO
index 32106131b0d0..19f1512c8f2e 100644
--- a/arch/mips/sgi-ip27/TODO
+++ b/arch/mips/sgi-ip27/TODO
@@ -9,10 +9,6 @@ ip27-init.c:find_lbaord_real. DONE
9in irix? 9in irix?
106. Investigate why things do not work without the setup_test() call 106. Investigate why things do not work without the setup_test() call
11being invoked on all nodes in ip27-memory.c. 11being invoked on all nodes in ip27-memory.c.
127. Too many CLIs in the locore handlers :
13For the low level handlers set up by set_except_vector(),
14__tlb_refill_debug_tramp, __xtlb_refill_debug_tramp and cacheerror,
15investigate whether the code should do CLI, STI or KMODE.
168. Too many do_page_faults invoked - investigate. 128. Too many do_page_faults invoked - investigate.
179. start_thread must turn off UX64 ... and define tlb_refill_debug. 139. start_thread must turn off UX64 ... and define tlb_refill_debug.
1810. Need a bad pmd table, bad pte table. __bad_pmd_table/__bad_pagetable 1410. 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 c304df715e0a..000000000000
--- a/arch/mips/sgi-ip27/ip27-irq-glue.S
+++ /dev/null
@@ -1,45 +0,0 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1999 Ralf Baechle
7 * Copyright (C) 1999 Silicon Graphics, Inc.
8 */
9#include <asm/asm.h>
10#include <asm/mipsregs.h>
11#include <asm/regdef.h>
12#include <asm/stackframe.h>
13
14 .text
15 .align 5
16NESTED(ip27_irq, PT_SIZE, sp)
17 SAVE_ALL
18 CLI
19
20 mfc0 s0, CP0_CAUSE
21 mfc0 t0, CP0_STATUS
22 and s0, t0
23 move a0, sp
24 PTR_LA ra, ret_from_irq
25
26 /* First check for RT interrupt. */
27 andi t0, s0, CAUSEF_IP4
28 bnez t0, ip4
29 andi t0, s0, CAUSEF_IP2
30 bnez t0, ip2
31 andi t0, s0, CAUSEF_IP3
32 bnez t0, ip3
33 andi t0, s0, CAUSEF_IP5
34 bnez t0, ip5
35 andi t0, s0, CAUSEF_IP6
36 bnez t0, ip6
37 j ra
38
39ip2: j ip27_do_irq_mask0 # PI_INT_PEND_0 or CC_PEND_{A|B}
40ip3: j ip27_do_irq_mask1 # PI_INT_PEND_1
41ip4: j ip27_rt_timer_interrupt
42ip5: j ip27_prof_timer
43ip6: j ip27_hub_error
44
45 END(ip27_irq)
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 2854ac4c9be1..2e643d2f51cb 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)
130 * Kanoj 05.13.00 130 * Kanoj 05.13.00
131 */ 131 */
132 132
133void ip27_do_irq_mask0(struct pt_regs *regs) 133static void ip27_do_irq_mask0(struct pt_regs *regs)
134{ 134{
135 int irq, swlevel; 135 int irq, swlevel;
136 hubreg_t pend0, mask0; 136 hubreg_t pend0, mask0;
@@ -171,7 +171,7 @@ void ip27_do_irq_mask0(struct pt_regs *regs)
171 LOCAL_HUB_L(PI_INT_PEND0); 171 LOCAL_HUB_L(PI_INT_PEND0);
172} 172}
173 173
174void ip27_do_irq_mask1(struct pt_regs *regs) 174static void ip27_do_irq_mask1(struct pt_regs *regs)
175{ 175{
176 int irq, swlevel; 176 int irq, swlevel;
177 hubreg_t pend1, mask1; 177 hubreg_t pend1, mask1;
@@ -196,12 +196,12 @@ void ip27_do_irq_mask1(struct pt_regs *regs)
196 LOCAL_HUB_L(PI_INT_PEND1); 196 LOCAL_HUB_L(PI_INT_PEND1);
197} 197}
198 198
199void ip27_prof_timer(struct pt_regs *regs) 199static void ip27_prof_timer(struct pt_regs *regs)
200{ 200{
201 panic("CPU %d got a profiling interrupt", smp_processor_id()); 201 panic("CPU %d got a profiling interrupt", smp_processor_id());
202} 202}
203 203
204void ip27_hub_error(struct pt_regs *regs) 204static void ip27_hub_error(struct pt_regs *regs)
205{ 205{
206 panic("CPU %d got a hub error interrupt", smp_processor_id()); 206 panic("CPU %d got a hub error interrupt", smp_processor_id());
207} 207}
@@ -421,9 +421,26 @@ int __devinit request_bridge_irq(struct bridge_controller *bc)
421 return irq; 421 return irq;
422} 422}
423 423
424extern void ip27_rt_timer_interrupt(struct pt_regs *regs);
425
426asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
427{
428 unsigned long pending = read_c0_cause() & read_c0_status();
429
430 if (pending & CAUSEF_IP4)
431 ip27_rt_timer_interrupt(regs);
432 else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */
433 ip27_do_irq_mask0(regs);
434 else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */
435 ip27_do_irq_mask1(regs);
436 else if (pending & CAUSEF_IP5)
437 ip27_prof_timer(regs);
438 else if (pending & CAUSEF_IP6)
439 ip27_hub_error(regs);
440}
441
424void __init arch_init_irq(void) 442void __init arch_init_irq(void)
425{ 443{
426 set_except_vector(0, ip27_irq);
427} 444}
428 445
429void install_ipi(void) 446void install_ipi(void)
diff --git a/arch/mips/sgi-ip32/Makefile b/arch/mips/sgi-ip32/Makefile
index 470898f4afe1..530bf848c3d0 100644
--- a/arch/mips/sgi-ip32/Makefile
+++ b/arch/mips/sgi-ip32/Makefile
@@ -3,7 +3,7 @@
3# under Linux. 3# under Linux.
4# 4#
5 5
6obj-y += ip32-berr.o ip32-irq.o ip32-irq-glue.o ip32-setup.o ip32-reset.o \ 6obj-y += ip32-berr.o ip32-irq.o ip32-setup.o ip32-reset.o \
7 crime.o ip32-memory.o 7 crime.o ip32-memory.o
8 8
9EXTRA_AFLAGS := $(CFLAGS) 9EXTRA_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 200924e1c4f5..000000000000
--- a/arch/mips/sgi-ip32/ip32-irq-glue.S
+++ /dev/null
@@ -1,86 +0,0 @@
1/*
2 * Low level interrupt handler for the SGI O2 aka IP32 aka Moosehead
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (C) 2000 Harald Koerfgen
9 * Copyright (C) 2001 Keith M Wesolowski
10 */
11#include <asm/asm.h>
12#include <asm/regdef.h>
13#include <asm/mipsregs.h>
14#include <asm/stackframe.h>
15#include <asm/addrspace.h>
16
17 .text
18 .set noreorder
19 .set noat
20 .align 5
21 NESTED(ip32_handle_int, PT_SIZE, ra)
22 .set noat
23 SAVE_ALL
24 CLI # TEST: interrupts should be off
25 .set at
26 .set noreorder
27
28 mfc0 s0,CP0_CAUSE
29
30 andi t1, s0, IE_IRQ0
31 bnez t1, handle_irq0
32 andi t1, s0, IE_IRQ1
33 bnez t1, handle_irq1
34 andi t1, s0, IE_IRQ2
35 bnez t1, handle_irq2
36 andi t1, s0, IE_IRQ3
37 bnez t1, handle_irq3
38 andi t1, s0, IE_IRQ4
39 bnez t1, handle_irq4
40 andi t1, s0, IE_IRQ5
41 bnez t1, handle_irq5
42 nop
43
44 /* Either someone has triggered the "software interrupts"
45 * or we lost an interrupt somehow. Ignore it.
46 */
47 j ret_from_irq
48 nop
49
50handle_irq0:
51 jal ip32_irq0
52 move a0, sp
53 j ret_from_irq
54 nop
55
56handle_irq1:
57 jal ip32_irq1
58 move a0, sp
59 j ret_from_irq
60 nop
61
62handle_irq2:
63 jal ip32_irq2
64 move a0, sp
65 j ret_from_irq
66 nop
67
68handle_irq3:
69 jal ip32_irq3
70 move a0, sp
71 j ret_from_irq
72 nop
73
74handle_irq4:
75 jal ip32_irq4
76 move a0, sp
77 j ret_from_irq
78 nop
79
80handle_irq5:
81 jal ip32_irq5
82 move a0, sp
83 j ret_from_irq
84 nop
85
86 END(ip32_handle_int)
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
index 2eb22d692ed9..22a6df94b4a1 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,
130struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT, 130struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT,
131 CPU_MASK_NONE, "CRIME CPU error", NULL, NULL }; 131 CPU_MASK_NONE, "CRIME CPU error", NULL, NULL };
132 132
133extern void ip32_handle_int(void);
134
135/* 133/*
136 * For interrupts wired from a single device to the CPU. Only the clock 134 * For interrupts wired from a single device to the CPU. Only the clock
137 * uses this it seems, which is IRQ 0 and IP7. 135 * uses this it seems, which is IRQ 0 and IP7.
@@ -503,7 +501,7 @@ static void ip32_unknown_interrupt(struct pt_regs *regs)
503 501
504/* CRIME 1.1 appears to deliver all interrupts to this one pin. */ 502/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
505/* change this to loop over all edge-triggered irqs, exception masked out ones */ 503/* change this to loop over all edge-triggered irqs, exception masked out ones */
506void ip32_irq0(struct pt_regs *regs) 504static void ip32_irq0(struct pt_regs *regs)
507{ 505{
508 uint64_t crime_int; 506 uint64_t crime_int;
509 int irq = 0; 507 int irq = 0;
@@ -520,31 +518,49 @@ void ip32_irq0(struct pt_regs *regs)
520 do_IRQ(irq, regs); 518 do_IRQ(irq, regs);
521} 519}
522 520
523void ip32_irq1(struct pt_regs *regs) 521static void ip32_irq1(struct pt_regs *regs)
524{ 522{
525 ip32_unknown_interrupt(regs); 523 ip32_unknown_interrupt(regs);
526} 524}
527 525
528void ip32_irq2(struct pt_regs *regs) 526static void ip32_irq2(struct pt_regs *regs)
529{ 527{
530 ip32_unknown_interrupt(regs); 528 ip32_unknown_interrupt(regs);
531} 529}
532 530
533void ip32_irq3(struct pt_regs *regs) 531static void ip32_irq3(struct pt_regs *regs)
534{ 532{
535 ip32_unknown_interrupt(regs); 533 ip32_unknown_interrupt(regs);
536} 534}
537 535
538void ip32_irq4(struct pt_regs *regs) 536static void ip32_irq4(struct pt_regs *regs)
539{ 537{
540 ip32_unknown_interrupt(regs); 538 ip32_unknown_interrupt(regs);
541} 539}
542 540
543void ip32_irq5(struct pt_regs *regs) 541static void ip32_irq5(struct pt_regs *regs)
544{ 542{
545 ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs); 543 ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs);
546} 544}
547 545
546asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
547{
548 unsigned int pending = read_c0_cause();
549
550 if (likely(pending & IE_IRQ0))
551 ip32_irq0(regs);
552 else if (unlikely(pending & IE_IRQ1))
553 ip32_irq1(regs);
554 else if (unlikely(pending & IE_IRQ2))
555 ip32_irq2(regs);
556 else if (unlikely(pending & IE_IRQ3))
557 ip32_irq3(regs);
558 else if (unlikely(pending & IE_IRQ4))
559 ip32_irq4(regs);
560 else if (likely(pending & IE_IRQ5))
561 ip32_irq5(regs);
562}
563
548void __init arch_init_irq(void) 564void __init arch_init_irq(void)
549{ 565{
550 unsigned int irq; 566 unsigned int irq;
@@ -556,7 +572,6 @@ void __init arch_init_irq(void)
556 crime->soft_int = 0; 572 crime->soft_int = 0;
557 mace->perif.ctrl.istat = 0; 573 mace->perif.ctrl.istat = 0;
558 mace->perif.ctrl.imask = 0; 574 mace->perif.ctrl.imask = 0;
559 set_except_vector(0, ip32_handle_int);
560 575
561 for (irq = 0; irq <= IP32_IRQ_MAX; irq++) { 576 for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
562 hw_irq_controller *controller; 577 hw_irq_controller *controller;
diff --git a/arch/mips/sibyte/bcm1480/Makefile b/arch/mips/sibyte/bcm1480/Makefile
index 538d5a51ae94..7b36ff3873b7 100644
--- a/arch/mips/sibyte/bcm1480/Makefile
+++ b/arch/mips/sibyte/bcm1480/Makefile
@@ -1,4 +1,4 @@
1obj-y := setup.o irq.o irq_handler.o time.o 1obj-y := setup.o irq.o time.o
2 2
3obj-$(CONFIG_SMP) += smp.o 3obj-$(CONFIG_SMP) += smp.o
4 4
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index 9cf7d713b13c..e61760b14d99 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)
187#endif 187#endif
188 188
189 189
190/* Defined in arch/mips/sibyte/bcm1480/irq_handler.S */
191extern void bcm1480_irq_handler(void);
192
193/*****************************************************************************/ 190/*****************************************************************************/
194 191
195static unsigned int startup_bcm1480_irq(unsigned int irq) 192static unsigned int startup_bcm1480_irq(unsigned int irq)
@@ -422,7 +419,6 @@ void __init arch_init_irq(void)
422#endif 419#endif
423 /* Enable necessary IPs, disable the rest */ 420 /* Enable necessary IPs, disable the rest */
424 change_c0_status(ST0_IM, imask); 421 change_c0_status(ST0_IM, imask);
425 set_except_vector(0, bcm1480_irq_handler);
426 422
427#ifdef CONFIG_KGDB 423#ifdef CONFIG_KGDB
428 if (kgdb_flag) { 424 if (kgdb_flag) {
@@ -473,3 +469,76 @@ void bcm1480_kgdb_interrupt(struct pt_regs *regs)
473} 469}
474 470
475#endif /* CONFIG_KGDB */ 471#endif /* CONFIG_KGDB */
472
473static inline int dclz(unsigned long long x)
474{
475 int lz;
476
477 __asm__ (
478 " .set push \n"
479 " .set mips64 \n"
480 " dclz %0, %1 \n"
481 " .set pop \n"
482 : "=r" (lz)
483 : "r" (x));
484
485 return lz;
486}
487
488extern void bcm1480_timer_interrupt(struct pt_regs *regs);
489extern void bcm1480_mailbox_interrupt(struct pt_regs *regs);
490extern void bcm1480_kgdb_interrupt(struct pt_regs *regs);
491
492asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
493{
494 unsigned int pending;
495
496#ifdef CONFIG_SIBYTE_BCM1480_PROF
497 /* Set compare to count to silence count/compare timer interrupts */
498 write_c0_compare(read_c0_count());
499#endif
500
501 pending = read_c0_cause();
502
503#ifdef CONFIG_SIBYTE_BCM1480_PROF
504 if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */
505 sbprof_cpu_intr(exception_epc(regs));
506#endif
507
508 if (pending & CAUSEF_IP4)
509 bcm1480_timer_interrupt(regs);
510
511#ifdef CONFIG_SMP
512 if (pending & CAUSEF_IP3)
513 bcm1480_mailbox_interrupt(regs);
514#endif
515
516#ifdef CONFIG_KGDB
517 if (pending & CAUSEF_IP6)
518 bcm1480_kgdb_interrupt(regs); /* KGDB (uart 1) */
519#endif
520
521 if (pending & CAUSEF_IP2) {
522 unsigned long long mask_h, mask_l;
523 unsigned long base;
524
525 /*
526 * Default...we've hit an IP[2] interrupt, which means we've
527 * got to check the 1480 interrupt registers to figure out what
528 * to do. Need to detect which CPU we're on, now that
529 * smp_affinity is supported.
530 */
531 base = A_BCM1480_IMR_MAPPER(smp_processor_id());
532 mask_h = __raw_readq(
533 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
534 mask_l = __raw_readq(
535 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
536
537 if (!mask_h) {
538 if (mask_h ^ 1)
539 do_IRQ(63 - dclz(mask_h), regs);
540 else
541 do_IRQ(127 - dclz(mask_l), regs);
542 }
543 }
544}
diff --git a/arch/mips/sibyte/bcm1480/irq_handler.S b/arch/mips/sibyte/bcm1480/irq_handler.S
deleted file mode 100644
index 408db88d050f..000000000000
--- a/arch/mips/sibyte/bcm1480/irq_handler.S
+++ /dev/null
@@ -1,165 +0,0 @@
1/*
2 * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19/*
20 * bcm1480_irq_handler() is the routine that is actually called when an
21 * interrupt occurs. It is installed as the exception vector handler in
22 * init_IRQ() in arch/mips/sibyte/bcm1480/irq.c
23 *
24 * In the handle we figure out which interrupts need handling, and use that
25 * to call the dispatcher, which will take care of actually calling
26 * registered handlers
27 *
28 * Note that we take care of all raised interrupts in one go at the handler.
29 * This is more BSDish than the Indy code, and also, IMHO, more sane.
30 */
31#include <linux/config.h>
32
33#include <asm/addrspace.h>
34#include <asm/asm.h>
35#include <asm/mipsregs.h>
36#include <asm/regdef.h>
37#include <asm/stackframe.h>
38#include <asm/sibyte/sb1250_defs.h>
39#include <asm/sibyte/bcm1480_regs.h>
40#include <asm/sibyte/bcm1480_int.h>
41
42/*
43 * What a pain. We have to be really careful saving the upper 32 bits of any
44 * register across function calls if we don't want them trashed--since were
45 * running in -o32, the calling routing never saves the full 64 bits of a
46 * register across a function call. Being the interrupt handler, we're
47 * guaranteed that interrupts are disabled during this code so we don't have
48 * to worry about random interrupts blasting the high 32 bits.
49 */
50
51 .text
52 .set push
53 .set noreorder
54 .set noat
55 .set mips64
56 #.set mips4
57 .align 5
58 NESTED(bcm1480_irq_handler, PT_SIZE, sp)
59 SAVE_ALL
60 CLI
61
62#ifdef CONFIG_SIBYTE_BCM1480_PROF
63 /* Set compare to count to silence count/compare timer interrupts */
64 mfc0 t1, CP0_COUNT
65 mtc0 t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */
66#endif
67 /* Read cause */
68 mfc0 s0, CP0_CAUSE
69
70#ifdef CONFIG_SIBYTE_BCM1480_PROF
71 /* Cpu performance counter interrupt is routed to IP[7] */
72 andi t1, s0, CAUSEF_IP7
73 beqz t1, 0f
74 srl t1, s0, (CAUSEB_BD-2) /* Shift BD bit to bit 2 */
75 and t1, t1, 0x4 /* mask to get just BD bit */
76#ifdef CONFIG_MIPS64
77 dmfc0 a0, CP0_EPC
78 daddu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
79#else
80 mfc0 a0, CP0_EPC
81 addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
82#endif
83 jal sbprof_cpu_intr
84 nop
85 j ret_from_irq
86 nop
870:
88#endif
89
90 /* Timer interrupt is routed to IP[4] */
91 andi t1, s0, CAUSEF_IP4
92 beqz t1, 1f
93 nop
94 jal bcm1480_timer_interrupt
95 move a0, sp /* Pass the registers along */
96 j ret_from_irq
97 nop /* delay slot */
981:
99
100#ifdef CONFIG_SMP
101 /* Mailbox interrupt is routed to IP[3] */
102 andi t1, s0, CAUSEF_IP3
103 beqz t1, 2f
104 nop
105 jal bcm1480_mailbox_interrupt
106 move a0, sp
107 j ret_from_irq
108 nop /* delay slot */
1092:
110#endif
111
112#ifdef CONFIG_KGDB
113 /* KGDB (uart 1) interrupt is routed to IP[6] */
114 andi t1, s0, CAUSEF_IP6
115 beqz t1, 3f
116 nop /* delay slot */
117 jal bcm1480_kgdb_interrupt
118 move a0, sp
119 j ret_from_irq
120 nop /* delay slot */
1213:
122#endif
123
124 and t1, s0, CAUSEF_IP2
125 beqz t1, 9f
126 nop
127
128 /*
129 * Default...we've hit an IP[2] interrupt, which means we've got
130 * to check the 1480 interrupt registers to figure out what to do
131 * Need to detect which CPU we're on, now that smp_affinity is
132 * supported.
133 */
134 PTR_LA v0, CKSEG1 + A_BCM1480_IMR_CPU0_BASE
135#ifdef CONFIG_SMP
136 lw t1, TI_CPU($28)
137 sll t1, t1, BCM1480_IMR_REGISTER_SPACING_SHIFT
138 addu v0, v0, t1
139#endif
140
141 /* Read IP[2] status (get both high and low halves of status) */
142 ld s0, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H(v0)
143 ld s1, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L(v0)
144
145 move s2, zero /* intr number */
146 li s3, 64
147
148 beqz s0, 9f /* No interrupts. Return. */
149 move a1, sp
150
151 xori s4, s0, 1 /* if s0 (_H) == 1, it's a low intr, so... */
152 movz s2, s3, s4 /* start the intr number at 64, and */
153 movz s0, s1, s4 /* look at the low status value. */
154
155 dclz s1, s0 /* Find the next interrupt. */
156 dsubu a0, zero, s1
157 daddiu a0, a0, 63
158 jal do_IRQ
159 daddu a0, a0, s2
160
1619: j ret_from_irq
162 nop
163
164 .set pop
165 END(bcm1480_irq_handler)
diff --git a/arch/mips/sibyte/sb1250/Makefile b/arch/mips/sibyte/sb1250/Makefile
index a8af84697588..a2fdbd62f8ac 100644
--- a/arch/mips/sibyte/sb1250/Makefile
+++ b/arch/mips/sibyte/sb1250/Makefile
@@ -1,4 +1,4 @@
1obj-y := setup.o irq.o irq_handler.o time.o 1obj-y := setup.o irq.o time.o
2 2
3obj-$(CONFIG_SMP) += smp.o 3obj-$(CONFIG_SMP) += smp.o
4obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o 4obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index 589537bfcc3d..0f6e54db4888 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)
163} 163}
164#endif 164#endif
165 165
166
167/* Defined in arch/mips/sibyte/sb1250/irq_handler.S */
168extern void sb1250_irq_handler(void);
169
170/*****************************************************************************/ 166/*****************************************************************************/
171 167
172static unsigned int startup_sb1250_irq(unsigned int irq) 168static unsigned int startup_sb1250_irq(unsigned int irq)
@@ -379,7 +375,6 @@ void __init arch_init_irq(void)
379#endif 375#endif
380 /* Enable necessary IPs, disable the rest */ 376 /* Enable necessary IPs, disable the rest */
381 change_c0_status(ST0_IM, imask); 377 change_c0_status(ST0_IM, imask);
382 set_except_vector(0, sb1250_irq_handler);
383 378
384#ifdef CONFIG_KGDB 379#ifdef CONFIG_KGDB
385 if (kgdb_flag) { 380 if (kgdb_flag) {
@@ -409,7 +404,7 @@ void __init arch_init_irq(void)
409#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) 404#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
410#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) 405#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
411 406
412void sb1250_kgdb_interrupt(struct pt_regs *regs) 407static void sb1250_kgdb_interrupt(struct pt_regs *regs)
413{ 408{
414 /* 409 /*
415 * Clear break-change status (allow some time for the remote 410 * Clear break-change status (allow some time for the remote
@@ -424,3 +419,74 @@ void sb1250_kgdb_interrupt(struct pt_regs *regs)
424} 419}
425 420
426#endif /* CONFIG_KGDB */ 421#endif /* CONFIG_KGDB */
422
423static inline int dclz(unsigned long long x)
424{
425 int lz;
426
427 __asm__ (
428 " .set push \n"
429 " .set mips64 \n"
430 " dclz %0, %1 \n"
431 " .set pop \n"
432 : "=r" (lz)
433 : "r" (x));
434
435 return lz;
436}
437
438asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
439{
440 unsigned int pending;
441
442#ifdef CONFIG_SIBYTE_SB1250_PROF
443 /* Set compare to count to silence count/compare timer interrupts */
444 write_c0_count(read_c0_count());
445#endif
446
447 /*
448 * What a pain. We have to be really careful saving the upper 32 bits
449 * of any * register across function calls if we don't want them
450 * trashed--since were running in -o32, the calling routing never saves
451 * the full 64 bits of a register across a function call. Being the
452 * interrupt handler, we're guaranteed that interrupts are disabled
453 * during this code so we don't have to worry about random interrupts
454 * blasting the high 32 bits.
455 */
456
457 pending = read_c0_cause();
458
459#ifdef CONFIG_SIBYTE_SB1250_PROF
460 if (pending & CAUSEF_IP7) { /* Cpu performance counter interrupt */
461 sbprof_cpu_intr(exception_epc(regs));
462 }
463#endif
464
465 if (pending & CAUSEF_IP4)
466 sb1250_timer_interrupt(regs);
467
468#ifdef CONFIG_SMP
469 if (pending & CAUSEF_IP3)
470 sb1250_mailbox_interrupt(regs);
471#endif
472
473#ifdef CONFIG_KGDB
474 if (pending & CAUSEF_IP6) /* KGDB (uart 1) */
475 sb1250_kgdb_interrupt(regs);
476#endif
477
478 if (pending & CAUSEF_IP2) {
479 unsigned long long mask;
480
481 /*
482 * Default...we've hit an IP[2] interrupt, which means we've
483 * got to check the 1250 interrupt registers to figure out what
484 * to do. Need to detect which CPU we're on, now that
485 ~ smp_affinity is supported.
486 */
487 mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
488 R_IMR_INTERRUPT_STATUS_BASE)));
489 if (mask)
490 do_IRQ(63 - dclz(mask), regs);
491 }
492}
diff --git a/arch/mips/sibyte/sb1250/irq_handler.S b/arch/mips/sibyte/sb1250/irq_handler.S
deleted file mode 100644
index 60edc8fb302b..000000000000
--- a/arch/mips/sibyte/sb1250/irq_handler.S
+++ /dev/null
@@ -1,147 +0,0 @@
1/*
2 * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19/*
20 * sb1250_handle_int() is the routine that is actually called when an interrupt
21 * occurs. It is installed as the exception vector handler in arch_init_irq()
22 * in arch/mips/sibyte/sb1250/irq.c
23 *
24 * In the handle we figure out which interrupts need handling, and use that to
25 * call the dispatcher, which will take care of actually calling registered
26 * handlers
27 *
28 * Note that we take care of all raised interrupts in one go at the handler.
29 * This is more BSDish than the Indy code, and also, IMHO, more sane.
30 */
31#include <linux/config.h>
32
33#include <asm/addrspace.h>
34#include <asm/asm.h>
35#include <asm/mipsregs.h>
36#include <asm/regdef.h>
37#include <asm/stackframe.h>
38#include <asm/sibyte/sb1250_defs.h>
39#include <asm/sibyte/sb1250_regs.h>
40#include <asm/sibyte/sb1250_int.h>
41
42/*
43 * What a pain. We have to be really careful saving the upper 32 bits of any
44 * register across function calls if we don't want them trashed--since were
45 * running in -o32, the calling routing never saves the full 64 bits of a
46 * register across a function call. Being the interrupt handler, we're
47 * guaranteed that interrupts are disabled during this code so we don't have
48 * to worry about random interrupts blasting the high 32 bits.
49 */
50
51 .text
52 .set push
53 .set noreorder
54 .set noat
55 .set mips64
56 .align 5
57 NESTED(sb1250_irq_handler, PT_SIZE, sp)
58 SAVE_ALL
59 CLI
60
61#ifdef CONFIG_SIBYTE_SB1250_PROF
62 /* Set compare to count to silence count/compare timer interrupts */
63 mfc0 t1, CP0_COUNT
64 mtc0 t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */
65#endif
66 /* Read cause */
67 mfc0 s0, CP0_CAUSE
68
69#ifdef CONFIG_SIBYTE_SB1250_PROF
70 /* Cpu performance counter interrupt is routed to IP[7] */
71 andi t1, s0, CAUSEF_IP7
72 beqz t1, 0f
73 srl t1, s0, (CAUSEB_BD-2) /* Shift BD bit to bit 2 */
74 and t1, t1, 0x4 /* mask to get just BD bit */
75 mfc0 a0, CP0_EPC
76 jal sbprof_cpu_intr
77 addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
78 j ret_from_irq
79 nop
800:
81#endif
82
83 /* Timer interrupt is routed to IP[4] */
84 andi t1, s0, CAUSEF_IP4
85 beqz t1, 1f
86 nop
87 jal sb1250_timer_interrupt
88 move a0, sp /* Pass the registers along */
89 j ret_from_irq
90 nop # delay slot
911:
92
93#ifdef CONFIG_SMP
94 /* Mailbox interrupt is routed to IP[3] */
95 andi t1, s0, CAUSEF_IP3
96 beqz t1, 2f
97 nop
98 jal sb1250_mailbox_interrupt
99 move a0, sp
100 j ret_from_irq
101 nop # delay slot
1022:
103#endif
104
105#ifdef CONFIG_KGDB
106 /* KGDB (uart 1) interrupt is routed to IP[6] */
107 andi t1, s0, CAUSEF_IP6
108 beqz t1, 1f
109 nop # delay slot
110 jal sb1250_kgdb_interrupt
111 move a0, sp
112 j ret_from_irq
113 nop # delay slot
1141:
115#endif
116
117 and t1, s0, CAUSEF_IP2
118 beqz t1, 4f
119 nop
120
121 /*
122 * Default...we've hit an IP[2] interrupt, which means we've got to
123 * check the 1250 interrupt registers to figure out what to do
124 * Need to detect which CPU we're on, now that smp_affinity is supported.
125 */
126 PTR_LA v0, CKSEG1 + A_IMR_CPU0_BASE
127#ifdef CONFIG_SMP
128 lw t1, TI_CPU($28)
129 sll t1, IMR_REGISTER_SPACING_SHIFT
130 addu v0, t1
131#endif
132 ld s0, R_IMR_INTERRUPT_STATUS_BASE(v0) /* read IP[2] status */
133
134 beqz s0, 4f /* No interrupts. Return */
135 move a1, sp
136
1373: dclz s1, s0 /* Find the next interrupt */
138 dsubu a0, zero, s1
139 daddiu a0, a0, 63
140 jal do_IRQ
141 nop
142
1434: j ret_from_irq
144 nop
145
146 .set pop
147 END(sb1250_irq_handler)
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
index 1e5676e4be86..9c7eaa5fb210 100644
--- a/arch/mips/sni/Makefile
+++ b/arch/mips/sni/Makefile
@@ -2,6 +2,6 @@
2# Makefile for the SNI specific part of the kernel 2# Makefile for the SNI specific part of the kernel
3# 3#
4 4
5obj-y += int-handler.o irq.o pcimt_scache.o reset.o setup.o 5obj-y += irq.o pcimt_scache.o reset.o setup.o
6 6
7EXTRA_AFLAGS := $(CFLAGS) 7EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/sni/int-handler.S b/arch/mips/sni/int-handler.S
deleted file mode 100644
index 2cdc09f55f18..000000000000
--- a/arch/mips/sni/int-handler.S
+++ /dev/null
@@ -1,106 +0,0 @@
1/*
2 * SNI RM200 PCI specific interrupt handler code.
3 *
4 * Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000, 01 by Ralf Baechle
5 */
6#include <asm/asm.h>
7#include <asm/mipsregs.h>
8#include <asm/regdef.h>
9#include <asm/sni.h>
10#include <asm/stackframe.h>
11
12/*
13 * The PCI ASIC has the nasty property that it may delay writes if it is busy.
14 * As a consequence from writes that have not graduated when we exit from the
15 * interrupt handler we might catch a spurious interrupt. To avoid this we
16 * force the PCI ASIC to graduate all writes by executing a read from the
17 * PCI bus.
18 */
19 .set noreorder
20 .set noat
21 .align 5
22 NESTED(sni_rm200_pci_handle_int, PT_SIZE, sp)
23 SAVE_ALL
24 CLI
25 .set at
26
27 /* Blinken light ... */
28 lb t0, led_cache
29 addiu t0, 1
30 sb t0, led_cache
31 sb t0, PCIMT_CSLED # write only register
32 .data
33led_cache: .byte 0
34 .text
35
36 mfc0 t0, CP0_STATUS
37 mfc0 t1, CP0_CAUSE
38 and t0, t1
39
40 andi t1, t0, 0x0800 # hardware interrupt 1
41 bnez t1, _hwint1
42 andi t1, t0, 0x4000 # hardware interrupt 4
43 bnez t1, _hwint4
44 andi t1, t0, 0x2000 # hardware interrupt 3
45 bnez t1, _hwint3
46 andi t1, t0, 0x1000 # hardware interrupt 2
47 bnez t1, _hwint2
48 andi t1, t0, 0x8000 # hardware interrupt 5
49 bnez t1, _hwint5
50 andi t1, t0, 0x0400 # hardware interrupt 0
51 bnez t1, _hwint0
52 nop
53
54 j restore_all # spurious interrupt
55 nop
56
57 ##############################################################################
58
59/* hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
60 button interrupts. */
61_hwint0: jal pciasic_hwint0
62 move a0, sp
63 j ret_from_irq
64 nop
65
66/*
67 * hwint 1 deals with EISA and SCSI interrupts
68 */
69_hwint1: jal pciasic_hwint1
70 move a0, sp
71 j ret_from_irq
72 nop
73
74
75/*
76 * This interrupt was used for the com1 console on the first prototypes;
77 * it's unsed otherwise
78 */
79_hwint2: jal pciasic_hwint2
80 move a0, sp
81 j ret_from_irq
82 nop
83
84/*
85 * hwint 3 are the PCI interrupts A - D
86 */
87_hwint3: jal pciasic_hwint3
88 move a0, sp
89 j ret_from_irq
90 nop
91
92/*
93 * hwint 4 is used for only the onboard PCnet 32.
94 */
95_hwint4: jal pciasic_hwint4
96 move a0, sp
97 j ret_from_irq
98 nop
99
100/* hwint5 is the r4k count / compare interrupt */
101_hwint5: jal pciasic_hwint5
102 move a0, sp
103 j ret_from_irq
104 nop
105
106 END(sni_rm200_pci_handle_int)
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index 952038aa4b90..7365b4853ddb 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -19,8 +19,6 @@
19 19
20DEFINE_SPINLOCK(pciasic_lock); 20DEFINE_SPINLOCK(pciasic_lock);
21 21
22extern asmlinkage void sni_rm200_pci_handle_int(void);
23
24static void enable_pciasic_irq(unsigned int irq) 22static void enable_pciasic_irq(unsigned int irq)
25{ 23{
26 unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2); 24 unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
@@ -71,20 +69,20 @@ static struct hw_interrupt_type pciasic_irq_type = {
71 * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug 69 * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
72 * button interrupts. Later ... 70 * button interrupts. Later ...
73 */ 71 */
74void pciasic_hwint0(struct pt_regs *regs) 72static void pciasic_hwint0(struct pt_regs *regs)
75{ 73{
76 panic("Received int0 but no handler yet ..."); 74 panic("Received int0 but no handler yet ...");
77} 75}
78 76
79/* This interrupt was used for the com1 console on the first prototypes. */ 77/* This interrupt was used for the com1 console on the first prototypes. */
80void pciasic_hwint2(struct pt_regs *regs) 78static void pciasic_hwint2(struct pt_regs *regs)
81{ 79{
82 /* I think this shouldn't happen on production machines. */ 80 /* I think this shouldn't happen on production machines. */
83 panic("hwint2 and no handler yet"); 81 panic("hwint2 and no handler yet");
84} 82}
85 83
86/* hwint5 is the r4k count / compare interrupt */ 84/* hwint5 is the r4k count / compare interrupt */
87void pciasic_hwint5(struct pt_regs *regs) 85static void pciasic_hwint5(struct pt_regs *regs)
88{ 86{
89 panic("hwint5 and no handler yet"); 87 panic("hwint5 and no handler yet");
90} 88}
@@ -105,7 +103,7 @@ static unsigned int ls1bit8(unsigned int x)
105 * 103 *
106 * The EISA_INT bit in CSITPEND is high active, all others are low active. 104 * The EISA_INT bit in CSITPEND is high active, all others are low active.
107 */ 105 */
108void pciasic_hwint1(struct pt_regs *regs) 106static void pciasic_hwint1(struct pt_regs *regs)
109{ 107{
110 u8 pend = *(volatile char *)PCIMT_CSITPEND; 108 u8 pend = *(volatile char *)PCIMT_CSITPEND;
111 unsigned long flags; 109 unsigned long flags;
@@ -135,7 +133,7 @@ void pciasic_hwint1(struct pt_regs *regs)
135/* 133/*
136 * hwint 3 should deal with the PCI A - D interrupts, 134 * hwint 3 should deal with the PCI A - D interrupts,
137 */ 135 */
138void pciasic_hwint3(struct pt_regs *regs) 136static void pciasic_hwint3(struct pt_regs *regs)
139{ 137{
140 u8 pend = *(volatile char *)PCIMT_CSITPEND; 138 u8 pend = *(volatile char *)PCIMT_CSITPEND;
141 int irq; 139 int irq;
@@ -150,13 +148,34 @@ void pciasic_hwint3(struct pt_regs *regs)
150/* 148/*
151 * hwint 4 is used for only the onboard PCnet 32. 149 * hwint 4 is used for only the onboard PCnet 32.
152 */ 150 */
153void pciasic_hwint4(struct pt_regs *regs) 151static void pciasic_hwint4(struct pt_regs *regs)
154{ 152{
155 clear_c0_status(IE_IRQ4); 153 clear_c0_status(IE_IRQ4);
156 do_IRQ(PCIMT_IRQ_ETHERNET, regs); 154 do_IRQ(PCIMT_IRQ_ETHERNET, regs);
157 set_c0_status(IE_IRQ4); 155 set_c0_status(IE_IRQ4);
158} 156}
159 157
158asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
159{
160 unsigned int pending = read_c0_status() & read_c0_cause();
161 static unsigned char led_cache;
162
163 *(volatile unsigned char *) PCIMT_CSLED = ++led_cache;
164
165 if (pending & 0x0800)
166 pciasic_hwint1(regs);
167 else if (pending & 0x4000)
168 pciasic_hwint4(regs);
169 else if (pending & 0x2000)
170 pciasic_hwint3(regs);
171 else if (pending & 0x1000)
172 pciasic_hwint2(regs);
173 else if (pending & 0x8000)
174 pciasic_hwint5(regs);
175 else if (pending & 0x0400)
176 pciasic_hwint0(regs);
177}
178
160void __init init_pciasic(void) 179void __init init_pciasic(void)
161{ 180{
162 unsigned long flags; 181 unsigned long flags;
@@ -176,8 +195,6 @@ void __init arch_init_irq(void)
176{ 195{
177 int i; 196 int i;
178 197
179 set_except_vector(0, sni_rm200_pci_handle_int);
180
181 init_i8259_irqs(); /* Integrated i8259 */ 198 init_i8259_irqs(); /* Integrated i8259 */
182 init_pciasic(); 199 init_pciasic();
183 200
diff --git a/arch/mips/tx4927/common/Makefile b/arch/mips/tx4927/common/Makefile
index 8fa126b296e1..9cb9535ebacb 100644
--- a/arch/mips/tx4927/common/Makefile
+++ b/arch/mips/tx4927/common/Makefile
@@ -6,7 +6,7 @@
6# unless it's something special (ie not a .c file). 6# unless it's something special (ie not a .c file).
7# 7#
8 8
9obj-y += tx4927_prom.o tx4927_setup.o tx4927_irq.o tx4927_irq_handler.o 9obj-y += tx4927_prom.o tx4927_setup.o tx4927_irq.o
10 10
11obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o 11obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o
12obj-$(CONFIG_KGDB) += tx4927_dbgio.o 12obj-$(CONFIG_KGDB) += tx4927_dbgio.o
diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c
index 5ab2e2b76018..8ca68015cf40 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)
525 */ 525 */
526void __init tx4927_irq_init(void) 526void __init tx4927_irq_init(void)
527{ 527{
528 extern asmlinkage void tx4927_irq_handler(void);
529
530 TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "-\n"); 528 TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "-\n");
531 529
532 TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_cp0_init()\n"); 530 TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_cp0_init()\n");
@@ -535,16 +533,12 @@ void __init tx4927_irq_init(void)
535 TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_pic_init()\n"); 533 TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "=Calling tx4927_irq_pic_init()\n");
536 tx4927_irq_pic_init(); 534 tx4927_irq_pic_init();
537 535
538 TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT,
539 "=Calling set_except_vector(tx4927_irq_handler)\n");
540 set_except_vector(0, tx4927_irq_handler);
541
542 TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "+\n"); 536 TX4927_IRQ_DPRINTK(TX4927_IRQ_INIT, "+\n");
543 537
544 return; 538 return;
545} 539}
546 540
547int tx4927_irq_nested(void) 541static int tx4927_irq_nested(void)
548{ 542{
549 int sw_irq = 0; 543 int sw_irq = 0;
550 u32 level2; 544 u32 level2;
@@ -582,3 +576,25 @@ int tx4927_irq_nested(void)
582 576
583 return (sw_irq); 577 return (sw_irq);
584} 578}
579
580asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
581{
582 unsigned int pending = read_c0_status() & read_c0_cause();
583
584 if (pending & STATUSF_IP7) /* cpu timer */
585 do_IRQ(TX4927_IRQ_CPU_TIMER, regs);
586 else if (pending & STATUSF_IP2) { /* tx4927 pic */
587 unsigned int irq = tx4927_irq_nested();
588
589 if (unlikely(irq == 0)) {
590 spurious_interrupt(regs);
591 return;
592 }
593 do_IRQ(irq, regs);
594 } else if (pending & STATUSF_IP0) /* user line 0 */
595 do_IRQ(TX4927_IRQ_USER0, regs);
596 else if (pending & STATUSF_IP1) /* user line 1 */
597 do_IRQ(TX4927_IRQ_USER1, regs);
598 else
599 spurious_interrupt(regs);
600}
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 dd3ceda9d712..000000000000
--- a/arch/mips/tx4927/common/tx4927_irq_handler.S
+++ /dev/null
@@ -1,103 +0,0 @@
1/*
2 * linux/arch/mips/tx4927/common/tx4927_irq_handler.S
3 *
4 * Primary interrupt handler for tx4927 based systems
5 *
6 * Author: MontaVista Software, Inc.
7 * Author: jsun@mvista.com or jsun@junsun.net
8 * source@mvista.com
9 *
10 * Copyright 2001-2002 MontaVista Software Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * You should have received a copy of the GNU General Public License along
29 * with this program; if not, write to the Free Software Foundation, Inc.,
30 * 675 Mass Ave, Cambridge, MA 02139, USA.
31 */
32#include <asm/asm.h>
33#include <asm/mipsregs.h>
34#include <asm/addrspace.h>
35#include <asm/regdef.h>
36#include <asm/stackframe.h>
37#include <asm/tx4927/tx4927.h>
38
39 .align 5
40 NESTED(tx4927_irq_handler, PT_SIZE, sp)
41 SAVE_ALL
42 CLI
43 .set at
44
45 mfc0 t0, CP0_CAUSE
46 mfc0 t1, CP0_STATUS
47 and t0, t1
48
49 andi t1, t0, STATUSF_IP7 /* cpu timer */
50 bnez t1, ll_ip7
51
52 /* IP6..IP3 multiplexed -- do not use */
53
54 andi t1, t0, STATUSF_IP2 /* tx4927 pic */
55 bnez t1, ll_ip2
56
57 andi t1, t0, STATUSF_IP0 /* user line 0 */
58 bnez t1, ll_ip0
59
60 andi t1, t0, STATUSF_IP1 /* user line 1 */
61 bnez t1, ll_ip1
62
63 .set reorder
64
65 /* wrong alarm or masked ... */
66 j spurious_interrupt
67 nop
68 END(tx4927_irq_handler)
69
70 .align 5
71
72
73ll_ip7:
74 li a0, TX4927_IRQ_CPU_TIMER
75 move a1, sp
76 jal do_IRQ
77 j ret_from_irq
78
79ll_ip2:
80 jal tx4927_irq_nested
81 nop
82 beqz v0, goto_spurious_interrupt
83 nop
84 move a0, v0
85 move a1, sp
86 jal do_IRQ
87 j ret_from_irq
88
89goto_spurious_interrupt:
90 j spurious_interrupt
91 nop
92
93ll_ip1:
94 li a0, TX4927_IRQ_USER1
95 move a1, sp
96 jal do_IRQ
97 j ret_from_irq
98
99ll_ip0:
100 li a0, TX4927_IRQ_USER0
101 move a1, sp
102 jal do_IRQ
103 j ret_from_irq
diff --git a/arch/mips/tx4938/common/Makefile b/arch/mips/tx4938/common/Makefile
index 74c95c5bcdbf..2033ae77f632 100644
--- a/arch/mips/tx4938/common/Makefile
+++ b/arch/mips/tx4938/common/Makefile
@@ -6,6 +6,6 @@
6# unless it's something special (ie not a .c file). 6# unless it's something special (ie not a .c file).
7# 7#
8 8
9obj-y += prom.o setup.o irq.o irq_handler.o rtc_rx5c348.o 9obj-y += prom.o setup.o irq.o rtc_rx5c348.o
10obj-$(CONFIG_KGDB) += dbgio.o 10obj-$(CONFIG_KGDB) += dbgio.o
11 11
diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c
index 4f90d7faf634..873805178d8e 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)
392void __init 392void __init
393tx4938_irq_init(void) 393tx4938_irq_init(void)
394{ 394{
395 extern asmlinkage void tx4938_irq_handler(void);
396
397 tx4938_irq_cp0_init(); 395 tx4938_irq_cp0_init();
398 tx4938_irq_pic_init(); 396 tx4938_irq_pic_init();
399 set_except_vector(0, tx4938_irq_handler);
400 397
401 return; 398 return;
402} 399}
@@ -422,3 +419,21 @@ tx4938_irq_nested(void)
422 wbflush(); 419 wbflush();
423 return (sw_irq); 420 return (sw_irq);
424} 421}
422
423asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
424{
425 unsigned int pending = read_c0_cause() & read_c0_status();
426
427 if (pending & STATUSF_IP7)
428 do_IRQ(TX4938_IRQ_CPU_TIMER, regs);
429 else if (pending & STATUSF_IP2) {
430 int irq = tx4938_irq_nested();
431 if (irq)
432 do_IRQ(irq, regs);
433 else
434 spurious_interrupt(regs);
435 } else if (pending & STATUSF_IP1)
436 do_IRQ(TX4938_IRQ_USER1, regs);
437 else if (pending & STATUSF_IP0)
438 do_IRQ(TX4938_IRQ_USER0, regs);
439}
diff --git a/arch/mips/tx4938/common/irq_handler.S b/arch/mips/tx4938/common/irq_handler.S
deleted file mode 100644
index 1b2f72bac42d..000000000000
--- a/arch/mips/tx4938/common/irq_handler.S
+++ /dev/null
@@ -1,84 +0,0 @@
1/*
2 * linux/arch/mips/tx4938/common/handler.S
3 *
4 * Primary interrupt handler for tx4938 based systems
5 * Copyright (C) 2000-2001 Toshiba Corporation
6 *
7 * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
8 * terms of the GNU General Public License version 2. This program is
9 * licensed "as is" without any warranty of any kind, whether express
10 * or implied.
11 *
12 * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
13 */
14#include <asm/asm.h>
15#include <asm/mipsregs.h>
16#include <asm/addrspace.h>
17#include <asm/regdef.h>
18#include <asm/stackframe.h>
19#include <asm/tx4938/rbtx4938.h>
20
21
22 .align 5
23 NESTED(tx4938_irq_handler, PT_SIZE, sp)
24 SAVE_ALL
25 CLI
26 .set at
27
28 mfc0 t0, CP0_CAUSE
29 mfc0 t1, CP0_STATUS
30 and t0, t1
31
32 andi t1, t0, STATUSF_IP7 /* cpu timer */
33 bnez t1, ll_ip7
34
35 /* IP6..IP3 multiplexed -- do not use */
36
37 andi t1, t0, STATUSF_IP2 /* tx4938 pic */
38 bnez t1, ll_ip2
39
40 andi t1, t0, STATUSF_IP1 /* user line 1 */
41 bnez t1, ll_ip1
42
43 andi t1, t0, STATUSF_IP0 /* user line 0 */
44 bnez t1, ll_ip0
45
46 .set reorder
47
48 nop
49 END(tx4938_irq_handler)
50
51 .align 5
52
53
54ll_ip7:
55 li a0, TX4938_IRQ_CPU_TIMER
56 move a1, sp
57 jal do_IRQ
58 j ret_from_irq
59
60
61ll_ip2:
62 jal tx4938_irq_nested
63 nop
64 beqz v0, goto_spurious_interrupt
65 nop
66 move a0, v0
67 move a1, sp
68 jal do_IRQ
69 j ret_from_irq
70
71goto_spurious_interrupt:
72 j ret_from_irq
73
74ll_ip1:
75 li a0, TX4938_IRQ_USER1
76 move a1, sp
77 jal do_IRQ
78 j ret_from_irq
79
80ll_ip0:
81 li a0, TX4938_IRQ_USER0
82 move a1, sp
83 jal do_IRQ
84 j ret_from_irq
diff --git a/arch/mips/vr41xx/Kconfig b/arch/mips/vr41xx/Kconfig
index a7add16c9aa4..055a2cdfc841 100644
--- a/arch/mips/vr41xx/Kconfig
+++ b/arch/mips/vr41xx/Kconfig
@@ -4,6 +4,8 @@ config CASIO_E55
4 select DMA_NONCOHERENT 4 select DMA_NONCOHERENT
5 select IRQ_CPU 5 select IRQ_CPU
6 select ISA 6 select ISA
7 select SYS_HAS_CPU_VR41XX
8 select SYS_SUPPORTS_32BIT_KERNEL
7 select SYS_SUPPORTS_LITTLE_ENDIAN 9 select SYS_SUPPORTS_LITTLE_ENDIAN
8 10
9config IBM_WORKPAD 11config IBM_WORKPAD
@@ -12,6 +14,8 @@ config IBM_WORKPAD
12 select DMA_NONCOHERENT 14 select DMA_NONCOHERENT
13 select IRQ_CPU 15 select IRQ_CPU
14 select ISA 16 select ISA
17 select SYS_HAS_CPU_VR41XX
18 select SYS_SUPPORTS_32BIT_KERNEL
15 select SYS_SUPPORTS_LITTLE_ENDIAN 19 select SYS_SUPPORTS_LITTLE_ENDIAN
16 20
17config NEC_CMBVR4133 21config NEC_CMBVR4133
@@ -21,6 +25,9 @@ config NEC_CMBVR4133
21 select DMA_NONCOHERENT 25 select DMA_NONCOHERENT
22 select IRQ_CPU 26 select IRQ_CPU
23 select HW_HAS_PCI 27 select HW_HAS_PCI
28 select SYS_HAS_CPU_VR41XX
29 select SYS_SUPPORTS_32BIT_KERNEL
30 select SYS_SUPPORTS_LITTLE_ENDIAN
24 31
25config ROCKHOPPER 32config ROCKHOPPER
26 bool "Support for Rockhopper baseboard" 33 bool "Support for Rockhopper baseboard"
@@ -34,6 +41,8 @@ config TANBAC_TB022X
34 select DMA_NONCOHERENT 41 select DMA_NONCOHERENT
35 select HW_HAS_PCI 42 select HW_HAS_PCI
36 select IRQ_CPU 43 select IRQ_CPU
44 select SYS_HAS_CPU_VR41XX
45 select SYS_SUPPORTS_32BIT_KERNEL
37 select SYS_SUPPORTS_LITTLE_ENDIAN 46 select SYS_SUPPORTS_LITTLE_ENDIAN
38 help 47 help
39 The TANBAC VR4131 multichip module(TB0225) and 48 The TANBAC VR4131 multichip module(TB0225) and
@@ -65,6 +74,8 @@ config VICTOR_MPC30X
65 select DMA_NONCOHERENT 74 select DMA_NONCOHERENT
66 select HW_HAS_PCI 75 select HW_HAS_PCI
67 select IRQ_CPU 76 select IRQ_CPU
77 select SYS_HAS_CPU_VR41XX
78 select SYS_SUPPORTS_32BIT_KERNEL
68 select SYS_SUPPORTS_LITTLE_ENDIAN 79 select SYS_SUPPORTS_LITTLE_ENDIAN
69 80
70config ZAO_CAPCELLA 81config ZAO_CAPCELLA
@@ -73,6 +84,8 @@ config ZAO_CAPCELLA
73 select DMA_NONCOHERENT 84 select DMA_NONCOHERENT
74 select HW_HAS_PCI 85 select HW_HAS_PCI
75 select IRQ_CPU 86 select IRQ_CPU
87 select SYS_HAS_CPU_VR41XX
88 select SYS_SUPPORTS_32BIT_KERNEL
76 select SYS_SUPPORTS_LITTLE_ENDIAN 89 select SYS_SUPPORTS_LITTLE_ENDIAN
77 90
78config PCI_VR41XX 91config PCI_VR41XX
diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile
index 9096302a7ecc..aa373974c80f 100644
--- a/arch/mips/vr41xx/common/Makefile
+++ b/arch/mips/vr41xx/common/Makefile
@@ -2,7 +2,7 @@
2# Makefile for common code of the NEC VR4100 series. 2# Makefile for common code of the NEC VR4100 series.
3# 3#
4 4
5obj-y += bcu.o cmu.o icu.o init.o int-handler.o irq.o pmu.o type.o 5obj-y += bcu.o cmu.o icu.o init.o irq.o pmu.o type.o
6obj-$(CONFIG_VRC4173) += vrc4173.o 6obj-$(CONFIG_VRC4173) += vrc4173.o
7 7
8EXTRA_AFLAGS := $(CFLAGS) 8EXTRA_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 2b6043f16d09..000000000000
--- a/arch/mips/vr41xx/common/int-handler.S
+++ /dev/null
@@ -1,114 +0,0 @@
1/*
2 * FILE NAME
3 * arch/mips/vr41xx/common/int-handler.S
4 *
5 * BRIEF MODULE DESCRIPTION
6 * Interrupt dispatcher for the NEC VR4100 series.
7 *
8 * Author: Yoichi Yuasa
9 * yyuasa@mvista.com or source@mvista.com
10 *
11 * Copyright 2001 MontaVista Software Inc.
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33/*
34 * Changes:
35 * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
36 * - New creation, NEC VR4100 series are supported.
37 *
38 * Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
39 * - Coped with INTASSIGN of NEC VR4133.
40 */
41#include <asm/asm.h>
42#include <asm/regdef.h>
43#include <asm/mipsregs.h>
44#include <asm/stackframe.h>
45
46 .text
47 .set noreorder
48
49 .align 5
50 NESTED(vr41xx_handle_interrupt, PT_SIZE, ra)
51 .set noat
52 SAVE_ALL
53 CLI
54 .set at
55 .set noreorder
56
57 /*
58 * Get the pending interrupts
59 */
60 mfc0 t0, CP0_CAUSE
61 mfc0 t1, CP0_STATUS
62 andi t0, 0xff00
63 and t0, t0, t1
64
65 andi t1, t0, CAUSEF_IP7 # MIPS timer interrupt
66 bnez t1, handle_irq
67 li a0, 7
68
69 andi t1, t0, 0x7800 # check for Int1-4
70 beqz t1, 1f
71
72 andi t1, t0, CAUSEF_IP3 # check for Int1
73 bnez t1, handle_int
74 li a0, 3
75
76 andi t1, t0, CAUSEF_IP4 # check for Int2
77 bnez t1, handle_int
78 li a0, 4
79
80 andi t1, t0, CAUSEF_IP5 # check for Int3
81 bnez t1, handle_int
82 li a0, 5
83
84 andi t1, t0, CAUSEF_IP6 # check for Int4
85 bnez t1, handle_int
86 li a0, 6
87
881:
89 andi t1, t0, CAUSEF_IP2 # check for Int0
90 bnez t1, handle_int
91 li a0, 2
92
93 andi t1, t0, CAUSEF_IP0 # check for IP0
94 bnez t1, handle_irq
95 li a0, 0
96
97 andi t1, t0, CAUSEF_IP1 # check for IP1
98 bnez t1, handle_irq
99 li a0, 1
100
101 j spurious_interrupt
102 nop
103
104handle_int:
105 jal irq_dispatch
106 move a1, sp
107 j ret_from_irq
108 nop
109
110handle_irq:
111 jal do_IRQ
112 move a1, sp
113 j ret_from_irq
114 END(vr41xx_handle_interrupt)
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
index 61aa264275ff..86796bb63c3c 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 *)
59 59
60EXPORT_SYMBOL_GPL(cascade_irq); 60EXPORT_SYMBOL_GPL(cascade_irq);
61 61
62asmlinkage void irq_dispatch(unsigned int irq, struct pt_regs *regs) 62static void irq_dispatch(unsigned int irq, struct pt_regs *regs)
63{ 63{
64 irq_cascade_t *cascade; 64 irq_cascade_t *cascade;
65 irq_desc_t *desc; 65 irq_desc_t *desc;
@@ -84,11 +84,32 @@ asmlinkage void irq_dispatch(unsigned int irq, struct pt_regs *regs)
84 do_IRQ(irq, regs); 84 do_IRQ(irq, regs);
85} 85}
86 86
87extern asmlinkage void vr41xx_handle_interrupt(void); 87asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
88{
89 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
90
91 if (pending & CAUSEF_IP7)
92 do_IRQ(7, regs);
93 else if (pending & 0x7800) {
94 if (pending & CAUSEF_IP3)
95 irq_dispatch(3, regs);
96 else if (pending & CAUSEF_IP4)
97 irq_dispatch(4, regs);
98 else if (pending & CAUSEF_IP5)
99 irq_dispatch(5, regs);
100 else if (pending & CAUSEF_IP6)
101 irq_dispatch(6, regs);
102 } else if (pending & CAUSEF_IP2)
103 irq_dispatch(2, regs);
104 else if (pending & CAUSEF_IP0)
105 do_IRQ(0, regs);
106 else if (pending & CAUSEF_IP1)
107 do_IRQ(1, regs);
108 else
109 spurious_interrupt(regs);
110}
88 111
89void __init arch_init_irq(void) 112void __init arch_init_irq(void)
90{ 113{
91 mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); 114 mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
92
93 set_except_vector(0, vr41xx_handle_interrupt);
94} 115}