diff options
Diffstat (limited to 'arch/mips')
161 files changed, 6506 insertions, 3911 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index e15709ce8866..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 | ||
819 | config 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 | ||
1450 | config MIPS_MT_SMTC | ||
1451 | bool "SMTC: Use all TCs on all VPEs for SMP" | ||
1452 | select SMP | ||
1453 | |||
1446 | config MIPS_MT_SMP | 1454 | config 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 | ||
1457 | endchoice | 1465 | endchoice |
1458 | 1466 | ||
1467 | config MIPS_MT_FPAFF | ||
1468 | bool "Dynamic FPU affinity for FP-intensive threads" | ||
1469 | depends on MIPS_MT | ||
1470 | default y | ||
1471 | |||
1459 | config MIPS_VPE_LOADER_TOM | 1472 | config 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 | ||
1488 | config 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 | |||
1475 | config SB1_PASS_1_WORKAROUNDS | 1498 | config SB1_PASS_1_WORKAROUNDS |
1476 | bool | 1499 | bool |
1477 | depends on CPU_SB1_PASS_1 | 1500 | depends on CPU_SB1_PASS_1 |
@@ -1590,11 +1613,16 @@ config ARCH_FLATMEM_ENABLE | |||
1590 | def_bool y | 1613 | def_bool y |
1591 | depends on !NUMA | 1614 | depends on !NUMA |
1592 | 1615 | ||
1616 | config NODES_SHIFT | ||
1617 | int | ||
1618 | default "6" | ||
1619 | depends on NEED_MULTIPLE_NODES | ||
1620 | |||
1593 | source "mm/Kconfig" | 1621 | source "mm/Kconfig" |
1594 | 1622 | ||
1595 | config SMP | 1623 | config SMP |
1596 | bool "Multi-Processing support" | 1624 | bool "Multi-Processing support" |
1597 | 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 |
1598 | ---help--- | 1626 | ---help--- |
1599 | 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 |
1600 | 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 | |||
105 | cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap | 105 | cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap |
106 | cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap | 106 | cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap |
107 | cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap | 107 | cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap |
108 | cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips2 -mtune=r4600) \ | 108 | cflags-$(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 |
110 | cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips2 -mtune=r4600) \ | 110 | cflags-$(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 |
112 | cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips2 -mtune=r4600) \ | 112 | cflags-$(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 |
114 | cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips2 -mtune=r4600 ) \ | 114 | cflags-$(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 |
116 | cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap | 116 | cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap |
117 | cflags-$(CONFIG_CPU_R5432) += $(call cc-options,-march=r5400,-march=r5000) \ | 117 | cflags-$(CONFIG_CPU_R5432) += $(call cc-option,-march=r5400,-march=r5000) \ |
118 | -Wa,--trap | 118 | -Wa,--trap |
119 | cflags-$(CONFIG_CPU_NEVADA) += $(call cc-options,-march=rm5200,-march=r5000) \ | 119 | cflags-$(CONFIG_CPU_NEVADA) += $(call cc-option,-march=rm5200,-march=r5000) \ |
120 | -Wa,--trap | 120 | -Wa,--trap |
121 | cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=r5000) \ | 121 | cflags-$(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 | ||
9 | obj-y += prom.o int-handler.o irq.o puts.o time.o reset.o \ | 9 | obj-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 | |||
23 | NESTED(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 | |||
40 | 1: | ||
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 | ||
46 | 2: | ||
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 | ||
52 | 3: | ||
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 | ||
58 | 4: | ||
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 | |||
65 | 5: | ||
66 | move a0, sp | ||
67 | j spurious_interrupt | ||
68 | END(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 | ||
69 | extern asmlinkage void au1000_IRQ(void); | ||
70 | extern void set_debug_traps(void); | 69 | extern void set_debug_traps(void); |
71 | extern irq_cpustat_t irq_stat [NR_CPUS]; | 70 | extern 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 | |||
663 | asmlinkage 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 | ||
5 | obj-y := irq.o int-handler.o reset.o setup.o | 5 | obj-y := irq.o reset.o setup.o |
6 | 6 | ||
7 | obj-$(CONFIG_EARLY_PRINTK) += console.o | 7 | obj-$(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 | ||
23 | extern 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 | ||
82 | asmlinkage void cobalt_irq(struct pt_regs *regs) | 80 | asmlinkage 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 | # | ||
6 | CONFIG_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 | ||
47 | CONFIG_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 | ||
69 | CONFIG_TANBAC_TB022X=y | ||
70 | # CONFIG_TANBAC_TB0226 is not set | ||
71 | CONFIG_TANBAC_TB0287=y | ||
72 | # CONFIG_VICTOR_MPC30X is not set | ||
73 | # CONFIG_ZAO_CAPCELLA is not set | ||
74 | CONFIG_PCI_VR41XX=y | ||
75 | # CONFIG_VRC4173 is not set | ||
76 | CONFIG_RWSEM_GENERIC_SPINLOCK=y | ||
77 | CONFIG_GENERIC_CALIBRATE_DELAY=y | ||
78 | CONFIG_DMA_NONCOHERENT=y | ||
79 | CONFIG_DMA_NEED_PCI_MAP_STATE=y | ||
80 | # CONFIG_CPU_BIG_ENDIAN is not set | ||
81 | CONFIG_CPU_LITTLE_ENDIAN=y | ||
82 | CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y | ||
83 | CONFIG_IRQ_CPU=y | ||
84 | CONFIG_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 | ||
95 | CONFIG_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 | ||
108 | CONFIG_SYS_HAS_CPU_VR41XX=y | ||
109 | CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y | ||
110 | CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y | ||
111 | CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y | ||
112 | CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y | ||
113 | |||
114 | # | ||
115 | # Kernel type | ||
116 | # | ||
117 | CONFIG_32BIT=y | ||
118 | # CONFIG_64BIT is not set | ||
119 | CONFIG_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 | ||
125 | CONFIG_CPU_HAS_SYNC=y | ||
126 | CONFIG_GENERIC_HARDIRQS=y | ||
127 | CONFIG_GENERIC_IRQ_PROBE=y | ||
128 | CONFIG_ARCH_FLATMEM_ENABLE=y | ||
129 | CONFIG_SELECT_MEMORY_MODEL=y | ||
130 | CONFIG_FLATMEM_MANUAL=y | ||
131 | # CONFIG_DISCONTIGMEM_MANUAL is not set | ||
132 | # CONFIG_SPARSEMEM_MANUAL is not set | ||
133 | CONFIG_FLATMEM=y | ||
134 | CONFIG_FLAT_NODE_MEM_MAP=y | ||
135 | # CONFIG_SPARSEMEM_STATIC is not set | ||
136 | CONFIG_SPLIT_PTLOCK_CPUS=4 | ||
137 | CONFIG_PREEMPT_NONE=y | ||
138 | # CONFIG_PREEMPT_VOLUNTARY is not set | ||
139 | # CONFIG_PREEMPT is not set | ||
140 | |||
141 | # | ||
142 | # Code maturity level options | ||
143 | # | ||
144 | CONFIG_EXPERIMENTAL=y | ||
145 | CONFIG_BROKEN_ON_SMP=y | ||
146 | CONFIG_INIT_ENV_ARG_LIMIT=32 | ||
147 | |||
148 | # | ||
149 | # General setup | ||
150 | # | ||
151 | CONFIG_LOCALVERSION="" | ||
152 | CONFIG_LOCALVERSION_AUTO=y | ||
153 | CONFIG_SWAP=y | ||
154 | CONFIG_SYSVIPC=y | ||
155 | # CONFIG_POSIX_MQUEUE is not set | ||
156 | # CONFIG_BSD_PROCESS_ACCT is not set | ||
157 | CONFIG_SYSCTL=y | ||
158 | # CONFIG_AUDIT is not set | ||
159 | # CONFIG_IKCONFIG is not set | ||
160 | CONFIG_INITRAMFS_SOURCE="" | ||
161 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | ||
162 | CONFIG_EMBEDDED=y | ||
163 | CONFIG_KALLSYMS=y | ||
164 | # CONFIG_KALLSYMS_EXTRA_PASS is not set | ||
165 | # CONFIG_HOTPLUG is not set | ||
166 | CONFIG_PRINTK=y | ||
167 | CONFIG_BUG=y | ||
168 | CONFIG_ELF_CORE=y | ||
169 | CONFIG_BASE_FULL=y | ||
170 | CONFIG_FUTEX=y | ||
171 | CONFIG_EPOLL=y | ||
172 | CONFIG_SHMEM=y | ||
173 | CONFIG_CC_ALIGN_FUNCTIONS=0 | ||
174 | CONFIG_CC_ALIGN_LABELS=0 | ||
175 | CONFIG_CC_ALIGN_LOOPS=0 | ||
176 | CONFIG_CC_ALIGN_JUMPS=0 | ||
177 | CONFIG_SLAB=y | ||
178 | # CONFIG_TINY_SHMEM is not set | ||
179 | CONFIG_BASE_SMALL=0 | ||
180 | # CONFIG_SLOB is not set | ||
181 | |||
182 | # | ||
183 | # Loadable module support | ||
184 | # | ||
185 | CONFIG_MODULES=y | ||
186 | CONFIG_MODULE_UNLOAD=y | ||
187 | # CONFIG_MODULE_FORCE_UNLOAD is not set | ||
188 | CONFIG_OBSOLETE_MODPARM=y | ||
189 | CONFIG_MODVERSIONS=y | ||
190 | CONFIG_MODULE_SRCVERSION_ALL=y | ||
191 | CONFIG_KMOD=y | ||
192 | |||
193 | # | ||
194 | # Block layer | ||
195 | # | ||
196 | # CONFIG_LBD is not set | ||
197 | |||
198 | # | ||
199 | # IO Schedulers | ||
200 | # | ||
201 | CONFIG_IOSCHED_NOOP=y | ||
202 | CONFIG_IOSCHED_AS=y | ||
203 | CONFIG_IOSCHED_DEADLINE=y | ||
204 | CONFIG_IOSCHED_CFQ=y | ||
205 | CONFIG_DEFAULT_AS=y | ||
206 | # CONFIG_DEFAULT_DEADLINE is not set | ||
207 | # CONFIG_DEFAULT_CFQ is not set | ||
208 | # CONFIG_DEFAULT_NOOP is not set | ||
209 | CONFIG_DEFAULT_IOSCHED="anticipatory" | ||
210 | |||
211 | # | ||
212 | # Bus options (PCI, PCMCIA, EISA, ISA, TC) | ||
213 | # | ||
214 | CONFIG_HW_HAS_PCI=y | ||
215 | CONFIG_PCI=y | ||
216 | # CONFIG_PCI_LEGACY_PROC is not set | ||
217 | CONFIG_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 | # | ||
232 | CONFIG_BINFMT_ELF=y | ||
233 | # CONFIG_BINFMT_MISC is not set | ||
234 | CONFIG_TRAD_SIGNALS=y | ||
235 | |||
236 | # | ||
237 | # Networking | ||
238 | # | ||
239 | CONFIG_NET=y | ||
240 | |||
241 | # | ||
242 | # Networking options | ||
243 | # | ||
244 | # CONFIG_NETDEBUG is not set | ||
245 | CONFIG_PACKET=y | ||
246 | # CONFIG_PACKET_MMAP is not set | ||
247 | CONFIG_UNIX=y | ||
248 | CONFIG_XFRM=y | ||
249 | CONFIG_XFRM_USER=m | ||
250 | # CONFIG_NET_KEY is not set | ||
251 | CONFIG_INET=y | ||
252 | CONFIG_IP_MULTICAST=y | ||
253 | CONFIG_IP_ADVANCED_ROUTER=y | ||
254 | CONFIG_ASK_IP_FIB_HASH=y | ||
255 | # CONFIG_IP_FIB_TRIE is not set | ||
256 | CONFIG_IP_FIB_HASH=y | ||
257 | CONFIG_IP_MULTIPLE_TABLES=y | ||
258 | CONFIG_IP_ROUTE_MULTIPATH=y | ||
259 | # CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set | ||
260 | CONFIG_IP_ROUTE_VERBOSE=y | ||
261 | CONFIG_IP_PNP=y | ||
262 | # CONFIG_IP_PNP_DHCP is not set | ||
263 | CONFIG_IP_PNP_BOOTP=y | ||
264 | # CONFIG_IP_PNP_RARP is not set | ||
265 | CONFIG_NET_IPIP=m | ||
266 | CONFIG_NET_IPGRE=m | ||
267 | # CONFIG_NET_IPGRE_BROADCAST is not set | ||
268 | # CONFIG_IP_MROUTE is not set | ||
269 | # CONFIG_ARPD is not set | ||
270 | CONFIG_SYN_COOKIES=y | ||
271 | # CONFIG_INET_AH is not set | ||
272 | # CONFIG_INET_ESP is not set | ||
273 | # CONFIG_INET_IPCOMP is not set | ||
274 | CONFIG_INET_TUNNEL=m | ||
275 | CONFIG_INET_DIAG=y | ||
276 | CONFIG_INET_TCP_DIAG=y | ||
277 | CONFIG_TCP_CONG_ADVANCED=y | ||
278 | |||
279 | # | ||
280 | # TCP congestion control | ||
281 | # | ||
282 | CONFIG_TCP_CONG_BIC=y | ||
283 | CONFIG_TCP_CONG_CUBIC=m | ||
284 | CONFIG_TCP_CONG_WESTWOOD=m | ||
285 | CONFIG_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 | # | ||
341 | CONFIG_STANDALONE=y | ||
342 | CONFIG_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 | ||
372 | CONFIG_BLK_DEV_LOOP=m | ||
373 | # CONFIG_BLK_DEV_CRYPTOLOOP is not set | ||
374 | CONFIG_BLK_DEV_NBD=m | ||
375 | # CONFIG_BLK_DEV_SX8 is not set | ||
376 | # CONFIG_BLK_DEV_UB is not set | ||
377 | CONFIG_BLK_DEV_RAM=y | ||
378 | CONFIG_BLK_DEV_RAM_COUNT=16 | ||
379 | CONFIG_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 | # | ||
387 | CONFIG_IDE=y | ||
388 | CONFIG_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 | ||
394 | CONFIG_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 | # | ||
405 | CONFIG_IDE_GENERIC=y | ||
406 | CONFIG_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 | ||
411 | CONFIG_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 | ||
431 | CONFIG_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 | ||
436 | CONFIG_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 | ||
445 | CONFIG_SCSI=y | ||
446 | CONFIG_SCSI_PROC_FS=y | ||
447 | |||
448 | # | ||
449 | # SCSI support type (disk, tape, CD-ROM) | ||
450 | # | ||
451 | CONFIG_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 | # | ||
521 | CONFIG_IEEE1394=m | ||
522 | |||
523 | # | ||
524 | # Subsystem Options | ||
525 | # | ||
526 | # CONFIG_IEEE1394_VERBOSEDEBUG is not set | ||
527 | # CONFIG_IEEE1394_OUI_DB is not set | ||
528 | CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y | ||
529 | CONFIG_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 | # | ||
539 | CONFIG_IEEE1394_OHCI1394=m | ||
540 | |||
541 | # | ||
542 | # Protocol Drivers | ||
543 | # | ||
544 | CONFIG_IEEE1394_VIDEO1394=m | ||
545 | CONFIG_IEEE1394_SBP2=m | ||
546 | # CONFIG_IEEE1394_SBP2_PHYS_DMA is not set | ||
547 | CONFIG_IEEE1394_ETH1394=m | ||
548 | CONFIG_IEEE1394_DV1394=m | ||
549 | CONFIG_IEEE1394_RAWIO=m | ||
550 | |||
551 | # | ||
552 | # I2O device support | ||
553 | # | ||
554 | # CONFIG_I2O is not set | ||
555 | |||
556 | # | ||
557 | # Network device support | ||
558 | # | ||
559 | CONFIG_NETDEVICES=y | ||
560 | CONFIG_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 | # | ||
578 | CONFIG_NET_ETHERNET=y | ||
579 | CONFIG_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 | ||
602 | CONFIG_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 | # | ||
655 | CONFIG_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 | # | ||
684 | CONFIG_VT=y | ||
685 | CONFIG_VT_CONSOLE=y | ||
686 | CONFIG_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 | # | ||
697 | CONFIG_SERIAL_CORE=y | ||
698 | CONFIG_SERIAL_CORE_CONSOLE=y | ||
699 | CONFIG_SERIAL_VR41XX=y | ||
700 | CONFIG_SERIAL_VR41XX_CONSOLE=y | ||
701 | # CONFIG_SERIAL_JSM is not set | ||
702 | CONFIG_UNIX98_PTYS=y | ||
703 | CONFIG_LEGACY_PTYS=y | ||
704 | CONFIG_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 | ||
727 | CONFIG_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 | ||
785 | CONFIG_DUMMY_CONSOLE=y | ||
786 | |||
787 | # | ||
788 | # Sound | ||
789 | # | ||
790 | # CONFIG_SOUND is not set | ||
791 | |||
792 | # | ||
793 | # USB support | ||
794 | # | ||
795 | CONFIG_USB_ARCH_HAS_HCD=y | ||
796 | CONFIG_USB_ARCH_HAS_OHCI=y | ||
797 | CONFIG_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 | # | ||
811 | CONFIG_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 | ||
815 | CONFIG_USB_OHCI_HCD=m | ||
816 | # CONFIG_USB_OHCI_BIG_ENDIAN is not set | ||
817 | CONFIG_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 | # | ||
834 | CONFIG_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 | # | ||
850 | CONFIG_USB_HID=m | ||
851 | CONFIG_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 | ||
899 | CONFIG_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 | # | ||
953 | CONFIG_EXT2_FS=y | ||
954 | # CONFIG_EXT2_FS_XATTR is not set | ||
955 | # CONFIG_EXT2_FS_XIP is not set | ||
956 | CONFIG_EXT3_FS=y | ||
957 | CONFIG_EXT3_FS_XATTR=y | ||
958 | # CONFIG_EXT3_FS_POSIX_ACL is not set | ||
959 | # CONFIG_EXT3_FS_SECURITY is not set | ||
960 | CONFIG_JBD=y | ||
961 | # CONFIG_JBD_DEBUG is not set | ||
962 | CONFIG_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 | ||
966 | CONFIG_XFS_FS=y | ||
967 | CONFIG_XFS_QUOTA=y | ||
968 | # CONFIG_XFS_SECURITY is not set | ||
969 | CONFIG_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 | ||
973 | CONFIG_ROMFS_FS=m | ||
974 | CONFIG_INOTIFY=y | ||
975 | # CONFIG_QUOTA is not set | ||
976 | CONFIG_QUOTACTL=y | ||
977 | # CONFIG_DNOTIFY is not set | ||
978 | # CONFIG_AUTOFS_FS is not set | ||
979 | CONFIG_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 | # | ||
998 | CONFIG_PROC_FS=y | ||
999 | CONFIG_PROC_KCORE=y | ||
1000 | CONFIG_SYSFS=y | ||
1001 | CONFIG_TMPFS=y | ||
1002 | # CONFIG_HUGETLB_PAGE is not set | ||
1003 | CONFIG_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 | ||
1017 | CONFIG_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 | # | ||
1027 | CONFIG_NFS_FS=y | ||
1028 | CONFIG_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 | ||
1033 | CONFIG_ROOT_NFS=y | ||
1034 | CONFIG_LOCKD=y | ||
1035 | CONFIG_LOCKD_V4=y | ||
1036 | CONFIG_NFS_COMMON=y | ||
1037 | CONFIG_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 | ||
1051 | CONFIG_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 | ||
1069 | CONFIG_LOG_BUF_SHIFT=14 | ||
1070 | CONFIG_CROSSCOMPILE=y | ||
1071 | CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs" | ||
1072 | |||
1073 | # | ||
1074 | # Security options | ||
1075 | # | ||
1076 | CONFIG_KEYS=y | ||
1077 | CONFIG_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 | ||
1094 | CONFIG_CRC32=y | ||
1095 | # CONFIG_LIBCRC32C is not set | ||
1096 | CONFIG_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 | ||
6 | obj-y += setup.o irq.o int-handler.o nile4_pic.o | 6 | obj-y += setup.o irq.o nile4_pic.o |
7 | 7 | ||
8 | EXTRA_AFLAGS := $(CFLAGS) | 8 | EXTRA_AFLAGS := $(CFLAGS) |
diff --git a/arch/mips/ddb5xxx/ddb5074/int-handler.S b/arch/mips/ddb5xxx/ddb5074/int-handler.S deleted file mode 100644 index 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 | |||
81 | 1: | ||
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 | |||
93 | 1: | ||
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 | |||
105 | 1: | ||
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 | ||
117 | 1: | ||
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 | ||
24 | extern asmlinkage void ddbIRQ(void); | ||
25 | |||
26 | static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; | 24 | static 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 | ||
93 | void ddb_local0_irqdispatch(struct pt_regs *regs) | 91 | static 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 | ||
121 | void ddb_local1_irqdispatch(void) | 119 | static 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 | ||
126 | void ddb_buserror_irq(void) | 124 | static 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 | ||
131 | void ddb_8254timer_irq(void) | 129 | static 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 | ||
134 | asmlinkage 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 | |||
136 | void __init arch_init_irq(void) | 148 | void __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 | ||
6 | obj-y += setup.o irq.o int-handler.o nile4_pic.o vrc5476_irq.o | 6 | obj-y += setup.o irq.o nile4_pic.o vrc5476_irq.o |
7 | obj-$(CONFIG_KGDB) += dbg_io.o | 7 | obj-$(CONFIG_KGDB) += dbg_io.o |
8 | 8 | ||
9 | EXTRA_AFLAGS := $(CFLAGS) | 9 | EXTRA_AFLAGS := $(CFLAGS) |
diff --git a/arch/mips/ddb5xxx/ddb5476/int-handler.S b/arch/mips/ddb5xxx/ddb5476/int-handler.S deleted file mode 100644 index 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 | |||
65 | ll_cpu_ip0: | ||
66 | li a0, CPU_IRQ_BASE + 0 | ||
67 | move a1, sp | ||
68 | jal do_IRQ | ||
69 | j ret_from_irq | ||
70 | |||
71 | ll_cpu_ip1: | ||
72 | li a0, CPU_IRQ_BASE + 1 | ||
73 | move a1, sp | ||
74 | jal do_IRQ | ||
75 | j ret_from_irq | ||
76 | |||
77 | ll_cpu_ip2: /* jump to second-level dispatching */ | ||
78 | move a0, sp | ||
79 | jal vrc5476_irq_dispatch | ||
80 | j ret_from_irq | ||
81 | |||
82 | ll_cpu_ip3: | ||
83 | li a0, CPU_IRQ_BASE + 3 | ||
84 | move a1, sp | ||
85 | jal do_IRQ | ||
86 | j ret_from_irq | ||
87 | |||
88 | ll_cpu_ip4: | ||
89 | li a0, CPU_IRQ_BASE + 4 | ||
90 | move a1, sp | ||
91 | jal do_IRQ | ||
92 | j ret_from_irq | ||
93 | |||
94 | ll_cpu_ip5: | ||
95 | li a0, CPU_IRQ_BASE + 5 | ||
96 | move a1, sp | ||
97 | jal do_IRQ | ||
98 | j ret_from_irq | ||
99 | |||
100 | ll_cpu_ip6: | ||
101 | li a0, CPU_IRQ_BASE + 6 | ||
102 | move a1, sp | ||
103 | jal do_IRQ | ||
104 | j ret_from_irq | ||
105 | |||
106 | ll_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) | |||
110 | static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; | 110 | static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; |
111 | static struct irqaction irq_error = { no_action, 0, CPU_MASK_NONE, "error", NULL, NULL }; | 111 | static struct irqaction irq_error = { no_action, 0, CPU_MASK_NONE, "error", NULL, NULL }; |
112 | 112 | ||
113 | extern asmlinkage void ddb5476_handle_int(void); | ||
114 | extern int setup_irq(unsigned int irq, struct irqaction *irqaction); | 113 | extern int setup_irq(unsigned int irq, struct irqaction *irqaction); |
115 | extern void mips_cpu_irq_init(u32 irq_base); | 114 | extern void mips_cpu_irq_init(u32 irq_base); |
116 | extern void vrc5476_irq_init(u32 irq_base); | 115 | extern void vrc5476_irq_init(u32 irq_base); |
117 | 116 | ||
117 | extern void vrc5476_irq_dispatch(struct pt_regs *regs); | ||
118 | |||
119 | asmlinkage 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 | |||
118 | void __init arch_init_irq(void) | 143 | void __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 | ||
80 | asmlinkage void | 80 | void |
81 | vrc5476_irq_dispatch(struct pt_regs *regs) | 81 | vrc5476_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 | ||
5 | obj-y += int-handler.o irq.o irq_5477.o setup.o lcd44780.o | 5 | obj-y += irq.o irq_5477.o setup.o lcd44780.o |
6 | 6 | ||
7 | obj-$(CONFIG_RUNTIME_DEBUG) += debug.o | 7 | obj-$(CONFIG_RUNTIME_DEBUG) += debug.o |
8 | obj-$(CONFIG_KGDB) += kgdb_io.o | 8 | obj-$(CONFIG_KGDB) += kgdb_io.o |
diff --git a/arch/mips/ddb5xxx/ddb5477/int-handler.S b/arch/mips/ddb5xxx/ddb5477/int-handler.S deleted file mode 100644 index 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 | |||
53 | ll_vrc5477_irq: | ||
54 | move a0, sp | ||
55 | jal vrc5477_irq_dispatch | ||
56 | j ret_from_irq | ||
57 | |||
58 | ll_cputimer_irq: | ||
59 | li a0, CPU_IRQ_BASE + 7 | ||
60 | move a1, sp | ||
61 | jal do_IRQ | ||
62 | j ret_from_irq | ||
63 | |||
64 | |||
65 | ll_cpu_ip0: | ||
66 | li a0, CPU_IRQ_BASE + 0 | ||
67 | move a1, sp | ||
68 | jal do_IRQ | ||
69 | j ret_from_irq | ||
70 | |||
71 | ll_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 | ||
76 | extern void vrc5477_irq_init(u32 base); | 76 | extern void vrc5477_irq_init(u32 base); |
77 | extern void mips_cpu_irq_init(u32 base); | 77 | extern void mips_cpu_irq_init(u32 base); |
78 | extern asmlinkage void ddb5477_handle_int(void); | ||
79 | extern int setup_irq(unsigned int irq, struct irqaction *irqaction); | 78 | extern int setup_irq(unsigned int irq, struct irqaction *irqaction); |
80 | static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; | 79 | static 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 | ||
143 | u8 i8259_interrupt_ack(void) | 139 | u8 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 |
162 | asmlinkage void | 158 | static void |
163 | vrc5477_irq_dispatch(struct pt_regs *regs) | 159 | vrc5477_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 | |||
199 | asmlinkage 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 | ||
27 | extern int _ftext, _end; /* begin and end of kernel image */ | 28 | extern int _ftext; /* begin and end of kernel image */ |
28 | extern void kernel_entry(int, char **, unsigned long, int *); | 29 | extern void kernel_entry(int, char **, unsigned long, int *); |
29 | 30 | ||
30 | void * memcpy(void * dest, const void *src, unsigned int count) | 31 | void * memcpy(void * dest, const void *src, unsigned int count) |
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index 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 | ||
284 | spurious: | 280 | spurious: |
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); | |||
48 | extern void dec_machine_power_off(void); | 48 | extern void dec_machine_power_off(void); |
49 | extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs); | 49 | extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs); |
50 | 50 | ||
51 | extern asmlinkage void decstation_handle_int(void); | ||
52 | |||
53 | unsigned long dec_kn_slot_base, dec_kn_slot_size; | 51 | unsigned long dec_kn_slot_base, dec_kn_slot_size; |
54 | 52 | ||
55 | EXPORT_SYMBOL(dec_kn_slot_base); | 53 | EXPORT_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 | ||
9 | obj-y += init.o irq.o puts.o reset.o time.o int-handler.o setup.o | 9 | obj-y += init.o irq.o puts.o reset.o time.o setup.o |
diff --git a/arch/mips/galileo-boards/ev96100/int-handler.S b/arch/mips/galileo-boards/ev96100/int-handler.S deleted file mode 100644 index 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 | |||
9 | NESTED(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 | |||
25 | 1: 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 | |||
32 | 3: 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 | ||
43 | extern asmlinkage void ev96100IRQ(void); | ||
44 | |||
45 | static inline unsigned int ffz8(unsigned int word) | 43 | static 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 | ||
57 | asmlinkage void ev96100_cpu_irq(unsigned int pendin) | 55 | extern void mips_timer_interrupt(struct pt_regs *regs); |
56 | |||
57 | asmlinkage 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 | ||
62 | asmlinkage 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 | |||
62 | void __init arch_init_irq(void) | 74 | void __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 | ||
9 | obj-y += int-handler.o irq.o promcon.o reset.o serialGT.o setup.o | 9 | obj-y += irq.o promcon.o reset.o serialGT.o setup.o |
10 | 10 | ||
11 | EXTRA_AFLAGS := $(CFLAGS) | 11 | EXTRA_AFLAGS := $(CFLAGS) |
diff --git a/arch/mips/gt64120/ev64120/int-handler.S b/arch/mips/gt64120/ev64120/int-handler.S deleted file mode 100644 index 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 | ||
49 | ll_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 | ||
59 | ll_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 | ||
69 | ll_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 | ||
79 | ll_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 | ||
88 | ll_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 | ||
98 | ll_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 | ||
107 | ll_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 | ||
49 | asmlinkage inline void pci_intA(struct pt_regs *regs) | 49 | asmlinkage 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) */ | |
54 | asmlinkage 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 | ||
59 | static void disable_ev64120_irq(unsigned int irq_nr) | 67 | static void disable_ev64120_irq(unsigned int irq_nr) |
@@ -109,16 +117,11 @@ static struct hw_interrupt_type ev64120_irq_type = { | |||
109 | 117 | ||
110 | void gt64120_irq_setup(void) | 118 | void 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 | ||
5 | obj-y += int-handler.o irq.o prom.o reset.o setup.o | 5 | obj-y += irq.o prom.o reset.o setup.o |
6 | 6 | ||
7 | obj-$(CONFIG_KGDB) += dbg_io.o | 7 | obj-$(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 | ||
73 | ll_pri_enet_irq: | ||
74 | li a0, 2 | ||
75 | move a1, sp | ||
76 | jal do_IRQ | ||
77 | j ret_from_irq | ||
78 | |||
79 | ll_sec_enet_irq: | ||
80 | li a0, 3 | ||
81 | move a1, sp | ||
82 | jal do_IRQ | ||
83 | j ret_from_irq | ||
84 | |||
85 | ll_uart1_irq: | ||
86 | li a0, 4 | ||
87 | move a1, sp | ||
88 | jal do_IRQ | ||
89 | j ret_from_irq | ||
90 | |||
91 | ll_cpci_irq: | ||
92 | li a0, 5 | ||
93 | move a1, sp | ||
94 | jal do_IRQ | ||
95 | j ret_from_irq | ||
96 | |||
97 | ll_galileo_irq: | ||
98 | li a0, 6 | ||
99 | move a1, sp | ||
100 | jal do_IRQ | ||
101 | j ret_from_irq | ||
102 | |||
103 | ll_cputimer_irq: | ||
104 | li a0, 7 | ||
105 | move a1, sp | ||
106 | jal do_IRQ | ||
107 | j ret_from_irq | ||
108 | |||
109 | ll_pmc1_irq: | ||
110 | li a0, 8 | ||
111 | move a1, sp | ||
112 | jal do_IRQ | ||
113 | j ret_from_irq | ||
114 | |||
115 | ll_pmc2_irq: | ||
116 | li a0, 9 | ||
117 | move a1, sp | ||
118 | jal do_IRQ | ||
119 | j ret_from_irq | ||
120 | |||
121 | ll_cpci_abcd_irq: | ||
122 | li a0, 10 | ||
123 | move a1, sp | ||
124 | jal do_IRQ | ||
125 | j ret_from_irq | ||
126 | |||
127 | ll_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 | ||
51 | extern asmlinkage void ocelot_handle_int(void); | 51 | asmlinkage 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 | ||
53 | void __init arch_init_irq(void) | 84 | void __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 | ||
9 | obj-y += it8172_setup.o irq.o int-handler.o pmon_prom.o \ | 9 | obj-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 | ||
12 | obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o | 12 | obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o |
diff --git a/arch/mips/ite-boards/generic/int-handler.S b/arch/mips/ite-boards/generic/int-handler.S deleted file mode 100644 index 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 | |||
11 | NESTED(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 | |||
36 | 1: | ||
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 | |||
54 | 3: | ||
55 | move a0, sp | ||
56 | jal mips_spurious_interrupt | ||
57 | nop | ||
58 | la a1, ret_from_irq | ||
59 | jr a1 | ||
60 | nop | ||
61 | |||
62 | END(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 | ||
65 | void disable_it8172_irq(unsigned int irq_nr); | ||
66 | void enable_it8172_irq(unsigned int irq_nr); | ||
67 | |||
68 | extern void set_debug_traps(void); | 65 | extern void set_debug_traps(void); |
69 | extern void mips_timer_interrupt(int irq, struct pt_regs *regs); | 66 | extern void mips_timer_interrupt(int irq, struct pt_regs *regs); |
70 | extern asmlinkage void it8172_IRQ(void); | ||
71 | 67 | ||
72 | struct it8172_intc_regs volatile *it8172_hw0_icregs = | 68 | struct 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 | ||
279 | asmlinkage 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 | |||
285 | void show_pending_irqs(void) | 291 | void 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 | ||
40 | int prom_argc; | 41 | int prom_argc; |
41 | char **prom_argv, **prom_envp; | 42 | char **prom_argv, **prom_envp; |
42 | 43 | ||
43 | extern char _end; | ||
44 | extern void __init prom_init_cmdline(void); | 44 | extern void __init prom_init_cmdline(void); |
45 | extern unsigned long __init prom_get_memsize(void); | 45 | extern unsigned long __init prom_get_memsize(void); |
46 | extern void __init it8172_init_ram_resource(unsigned long memsize); | 46 | extern void __init it8172_init_ram_resource(unsigned long memsize); |
diff --git a/arch/mips/ite-boards/qed-4n-s01b/init.c b/arch/mips/ite-boards/qed-4n-s01b/init.c index 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 | ||
40 | int prom_argc; | 41 | int prom_argc; |
41 | char **prom_argv, **prom_envp; | 42 | char **prom_argv, **prom_envp; |
42 | 43 | ||
43 | extern char _end; | ||
44 | extern void __init prom_init_cmdline(void); | 44 | extern void __init prom_init_cmdline(void); |
45 | extern unsigned long __init prom_get_memsize(void); | 45 | extern unsigned long __init prom_get_memsize(void); |
46 | extern void __init it8172_init_ram_resource(unsigned long memsize); | 46 | extern 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 | ||
5 | obj-y := int-handler.o irq.o jazzdma.o reset.o setup.o | 5 | obj-y := irq.o jazzdma.o reset.o setup.o |
6 | 6 | ||
7 | EXTRA_AFLAGS := $(CFLAGS) | 7 | EXTRA_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 | ||
47 | 1: 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 | */ | ||
55 | 2: lw t0,(t1) | ||
56 | jr t0 | ||
57 | nop # delay slot | ||
58 | END(jazz_handle_int) | ||
59 | |||
60 | ll_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 | |||
66 | ll_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 | |||
72 | ll_local_dma: li s1,~IE_IRQ0 | ||
73 | PANIC("Unimplemented local_dma handler") | ||
74 | |||
75 | ll_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 | */ | ||
91 | ll_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 | */ | ||
104 | ll_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 | */ | ||
118 | ll_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 | */ | ||
136 | ll_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 | */ | ||
144 | call_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 | ||
170 | ll_vectors: PTR ll_count # Count/Compare IRQ | ||
171 | |||
172 | /* | ||
173 | * Interrupt handlers for local devices. | ||
174 | */ | ||
175 | .text | ||
176 | .set reorder | ||
177 | loc_no_irq: PANIC("Unimplemented loc_no_irq handler") | ||
178 | /* | ||
179 | * Parallel port IRQ | ||
180 | */ | ||
181 | loc_parallel: li s1,~JAZZ_IE_PARALLEL | ||
182 | li a0,JAZZ_PARALLEL_IRQ | ||
183 | b loc_call | ||
184 | |||
185 | /* | ||
186 | * Floppy IRQ | ||
187 | */ | ||
188 | loc_floppy: li s1,~JAZZ_IE_FLOPPY | ||
189 | li a0,JAZZ_FLOPPY_IRQ | ||
190 | b loc_call | ||
191 | |||
192 | /* | ||
193 | * Sound IRQ | ||
194 | */ | ||
195 | loc_sound: PANIC("Unimplemented loc_sound handler") | ||
196 | loc_video: PANIC("Unimplemented loc_video handler") | ||
197 | |||
198 | /* | ||
199 | * Ethernet interrupt handler | ||
200 | */ | ||
201 | loc_ethernet: li s1,~JAZZ_IE_ETHERNET | ||
202 | li a0,JAZZ_ETHERNET_IRQ | ||
203 | b loc_call | ||
204 | |||
205 | /* | ||
206 | * SCSI interrupt handler | ||
207 | */ | ||
208 | loc_scsi: li s1,~JAZZ_IE_SCSI | ||
209 | li a0,JAZZ_SCSI_IRQ | ||
210 | b loc_call | ||
211 | |||
212 | /* | ||
213 | * Keyboard interrupt handler | ||
214 | */ | ||
215 | loc_keyboard: li s1,~JAZZ_IE_KEYBOARD | ||
216 | li a0,JAZZ_KEYBOARD_IRQ | ||
217 | b loc_call | ||
218 | |||
219 | /* | ||
220 | * Mouse interrupt handler | ||
221 | */ | ||
222 | loc_mouse: li s1,~JAZZ_IE_MOUSE | ||
223 | li a0,JAZZ_MOUSE_IRQ | ||
224 | b loc_call | ||
225 | |||
226 | /* | ||
227 | * Serial port 1 IRQ | ||
228 | */ | ||
229 | loc_serial1: li s1,~JAZZ_IE_SERIAL1 | ||
230 | li a0,JAZZ_SERIAL1_IRQ | ||
231 | b loc_call | ||
232 | |||
233 | /* | ||
234 | * Serial port 2 IRQ | ||
235 | */ | ||
236 | loc_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 | */ | ||
244 | loc_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 | */ | ||
266 | 3: j spurious_interrupt | ||
267 | |||
268 | /* | ||
269 | * Vectors for interrupts generated by local devices | ||
270 | */ | ||
271 | .data | ||
272 | local_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 | ||
18 | extern asmlinkage void jazz_handle_int(void); | ||
19 | |||
20 | static DEFINE_SPINLOCK(r4030_lock); | 18 | static DEFINE_SPINLOCK(r4030_lock); |
21 | 19 | ||
22 | static void enable_r4030_irq(unsigned int irq) | 20 | static void enable_r4030_irq(unsigned int irq) |
@@ -90,10 +88,82 @@ void __init init_r4030_ints(void) | |||
90 | */ | 88 | */ |
91 | void __init arch_init_irq(void) | 89 | void __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 | |||
97 | static 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 | |||
106 | static 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 | |||
145 | asmlinkage 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 | ||
5 | obj-y += init.o int-handler.o irq.o setup.o | 5 | obj-y += init.o irq.o setup.o |
6 | obj-$(CONFIG_RUNTIME_DEBUG) += debug.o | 6 | obj-$(CONFIG_RUNTIME_DEBUG) += debug.o |
7 | obj-$(CONFIG_KGDB) += kgdb_io.o | 7 | obj-$(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 | ||
80 | extern 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 | ||
265 | void jmr3927_irc_irqdispatch(struct pt_regs *regs) | 263 | asmlinkage 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 | ||
35 | obj-$(CONFIG_SMP) += smp.o | 35 | obj-$(CONFIG_SMP) += smp.o |
36 | 36 | ||
37 | obj-$(CONFIG_MIPS_MT_SMP) += smp_mt.o | 37 | obj-$(CONFIG_MIPS_MT) += mips-mt.o |
38 | obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o | ||
39 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o | ||
38 | 40 | ||
41 | obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o | ||
39 | obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o | 42 | obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o |
40 | obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o | 43 | obj-$(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 | ||
77 | FEXPORT(restore_all) # restore full frame | 80 | FEXPORT(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 | ||
102 | 1: | ||
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 | */ |
126 | LEAF(spurious_interrupt) | 164 | LEAF(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 */ |
133 | 1: 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 | ||
285 | 3: | 285 | 3: |
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 | ||
306 | 9: | ||
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 | */ | ||
677 | static 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 | ||
129 | NESTED(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 | */ | ||
181 | EXPORT(except_vec_vi_mori) | ||
182 | ori a0, $0, 0 | ||
183 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
160 | EXPORT(except_vec_vi_lui) | 184 | EXPORT(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) | |||
173 | NESTED(except_vec_vi_handler, 0, sp) | 197 | NESTED(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 | */ |
168 | NESTED(smp_bootstrap, 16, sp) | 208 | NESTED(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 | ||
226 | 2: | ||
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 | ||
39 | atomic_t irq_err_count; | 39 | atomic_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 | */ | ||
47 | unsigned 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 | ||
114 | asmlinkage void spurious_interrupt(struct pt_regs *regs) | ||
115 | { | ||
116 | atomic_inc(&irq_err_count); | ||
117 | } | ||
118 | |||
104 | #ifdef CONFIG_KGDB | 119 | #ifdef CONFIG_KGDB |
105 | extern void breakpoint(void); | 120 | extern void breakpoint(void); |
106 | extern void set_debug_traps(void); | 121 | extern 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 | |||
32 | static struct workqueue_struct *workqueue = NULL; | ||
33 | static struct work_struct work; | ||
34 | |||
35 | extern unsigned long cpu_khz; | ||
36 | |||
37 | struct mtsp_syscall { | ||
38 | int cmd; | ||
39 | unsigned char abi; | ||
40 | unsigned char size; | ||
41 | }; | ||
42 | |||
43 | struct mtsp_syscall_ret { | ||
44 | int retval; | ||
45 | int errno; | ||
46 | }; | ||
47 | |||
48 | struct 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 | |||
58 | static struct list_head kspd_notifylist; | ||
59 | static 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 | |||
92 | struct apsp_table { | ||
93 | int sp; | ||
94 | int ap; | ||
95 | }; | ||
96 | |||
97 | /* we might want to do the mode flags too */ | ||
98 | struct 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 | |||
108 | struct 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 | |||
116 | static 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 | |||
143 | static 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 | |||
156 | static 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 | |||
172 | static 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 | */ | ||
186 | void 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 | |||
288 | static 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 | |||
319 | static int channel_open = 0; | ||
320 | |||
321 | /* the work handler */ | ||
322 | static 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 | |||
347 | static 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 | |||
364 | static void stopwork(int vpe) | ||
365 | { | ||
366 | sp_stopping = 1; | ||
367 | |||
368 | printk(KERN_DEBUG "KSPD: SP stopping\n"); | ||
369 | } | ||
370 | |||
371 | void kspd_notify(struct kspd_notifications *notify) | ||
372 | { | ||
373 | list_add(¬ify->list, &kspd_notifylist); | ||
374 | } | ||
375 | |||
376 | static struct vpe_notifications notify; | ||
377 | static 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, ¬ify); | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static void kspd_module_exit(void) | ||
389 | { | ||
390 | |||
391 | } | ||
392 | |||
393 | module_init(kspd_module_init); | ||
394 | module_exit(kspd_module_exit); | ||
395 | |||
396 | MODULE_DESCRIPTION("MIPS KSPD"); | ||
397 | MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc."); | ||
398 | MODULE_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 | ||
1185 | asmlinkage 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)) |
1187 | static unsigned char socketcall_nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), | 1197 | static unsigned char socketcall_nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), |
diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c new file mode 100644 index 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 | |||
26 | cpumask_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 | |||
34 | unsigned 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 | */ | ||
50 | static 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 | */ | ||
59 | asmlinkage 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 | |||
115 | out_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 | */ | ||
124 | asmlinkage 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 | |||
148 | out_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 | |||
165 | void 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 | |||
237 | static int mt_opt_norps = 0; | ||
238 | static int mt_opt_rpsctl = -1; | ||
239 | static int mt_opt_nblsu = -1; | ||
240 | static int mt_opt_forceconfig7 = 0; | ||
241 | static int mt_opt_config7 = -1; | ||
242 | |||
243 | static int __init rps_disable(char *s) | ||
244 | { | ||
245 | mt_opt_norps = 1; | ||
246 | return 1; | ||
247 | } | ||
248 | __setup("norps", rps_disable); | ||
249 | |||
250 | static int __init rpsctl_set(char *str) | ||
251 | { | ||
252 | get_option(&str, &mt_opt_rpsctl); | ||
253 | return 1; | ||
254 | } | ||
255 | __setup("rpsctl=", rpsctl_set); | ||
256 | |||
257 | static int __init nblsu_set(char *str) | ||
258 | { | ||
259 | get_option(&str, &mt_opt_nblsu); | ||
260 | return 1; | ||
261 | } | ||
262 | __setup("nblsu=", nblsu_set); | ||
263 | |||
264 | static 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 */ | ||
273 | int mt_protiflush = 0; | ||
274 | int mt_protdflush = 0; | ||
275 | int mt_n_iflushes = 1; | ||
276 | int mt_n_dflushes = 1; | ||
277 | |||
278 | static int __init set_protiflush(char *s) | ||
279 | { | ||
280 | mt_protiflush = 1; | ||
281 | return 1; | ||
282 | } | ||
283 | __setup("protiflush", set_protiflush); | ||
284 | |||
285 | static int __init set_protdflush(char *s) | ||
286 | { | ||
287 | mt_protdflush = 1; | ||
288 | return 1; | ||
289 | } | ||
290 | __setup("protdflush", set_protdflush); | ||
291 | |||
292 | static int __init niflush(char *s) | ||
293 | { | ||
294 | get_option(&s, &mt_n_iflushes); | ||
295 | return 1; | ||
296 | } | ||
297 | __setup("niflush=", niflush); | ||
298 | |||
299 | static 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 | ||
306 | static int fpaff_threshold = -1; | ||
307 | |||
308 | static 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 | |||
317 | static unsigned int itc_base = 0; | ||
318 | |||
319 | static 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 | |||
327 | void 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 | |||
431 | void 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 | |||
441 | void 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 86e42c633f73..0a71a4c33716 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c | |||
@@ -28,22 +28,9 @@ extern long __strnlen_user_asm(const char *s); | |||
28 | /* | 28 | /* |
29 | * String functions | 29 | * String functions |
30 | */ | 30 | */ |
31 | EXPORT_SYMBOL(memchr); | ||
32 | EXPORT_SYMBOL(memcmp); | ||
33 | EXPORT_SYMBOL(memset); | 31 | EXPORT_SYMBOL(memset); |
34 | EXPORT_SYMBOL(memcpy); | 32 | EXPORT_SYMBOL(memcpy); |
35 | EXPORT_SYMBOL(memmove); | 33 | EXPORT_SYMBOL(memmove); |
36 | EXPORT_SYMBOL(strcat); | ||
37 | EXPORT_SYMBOL(strchr); | ||
38 | #ifdef CONFIG_64BIT | ||
39 | EXPORT_SYMBOL(strncmp); | ||
40 | #endif | ||
41 | EXPORT_SYMBOL(strlen); | ||
42 | EXPORT_SYMBOL(strpbrk); | ||
43 | EXPORT_SYMBOL(strncat); | ||
44 | EXPORT_SYMBOL(strnlen); | ||
45 | EXPORT_SYMBOL(strrchr); | ||
46 | EXPORT_SYMBOL(strstr); | ||
47 | 34 | ||
48 | EXPORT_SYMBOL(kernel_thread); | 35 | EXPORT_SYMBOL(kernel_thread); |
49 | 36 | ||
@@ -62,6 +49,3 @@ EXPORT_SYMBOL(__strnlen_user_asm); | |||
62 | EXPORT_SYMBOL(csum_partial); | 49 | EXPORT_SYMBOL(csum_partial); |
63 | 50 | ||
64 | EXPORT_SYMBOL(invalid_pte_table); | 51 | EXPORT_SYMBOL(invalid_pte_table); |
65 | #ifdef CONFIG_GENERIC_IRQ_PROBE | ||
66 | EXPORT_SYMBOL(probe_irq_mask); | ||
67 | #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> | ||
46 | extern 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 | ||
116 | 1: | ||
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 | ||
133 | LEAF(_init_fpu) | 156 | LEAF(_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 | ||
39 | static struct rtlx_info *rtlx; | 47 | static struct rtlx_info *rtlx; |
40 | static int major; | 48 | static int major; |
41 | static char module_name[] = "rtlx"; | 49 | static char module_name[] = "rtlx"; |
42 | static struct irqaction irq; | ||
43 | static int irq_num; | ||
44 | |||
45 | static 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 | ||
58 | static struct chan_waitqueues { | 51 | static 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 | ||
57 | static struct irqaction irq; | ||
58 | static int irq_num; | ||
59 | static struct vpe_notifications notify; | ||
60 | static int sp_stopping = 0; | ||
61 | |||
63 | extern void *vpe_get_shared(int index); | 62 | extern void *vpe_get_shared(int index); |
64 | 63 | ||
65 | static void rtlx_dispatch(struct pt_regs *regs) | 64 | static 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 | */ | ||
70 | static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 73 | static 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. */ | 85 | static __attribute_used__ void dump_rtlx(void) |
85 | static 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. */ | ||
109 | static 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 */ |
119 | static int rtlx_open(struct inode *inode, struct file *filp) | 122 | static 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 | |||
135 | static 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 | |||
145 | int 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 | ||
152 | static int rtlx_release(struct inode *inode, struct file *filp) | 253 | int 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 | ||
162 | static unsigned int rtlx_poll(struct file *file, poll_table * wait) | 259 | unsigned 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 | ||
185 | static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count, | 302 | static 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? */ | 315 | unsigned 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 */ | 321 | static 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) | 329 | static 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); | 337 | ssize_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 | ||
237 | out: | ||
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 | ||
245 | static ssize_t rtlx_write(struct file *file, const char __user * buffer, | 368 | ssize_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 | |||
399 | static 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 | |||
406 | static 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 | |||
414 | static 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 | |||
438 | static 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 | |||
451 | static 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 | |||
294 | out: | ||
295 | rt->rt_write += count; | ||
296 | rt->rt_write %= rt->buffer_size; | ||
297 | |||
298 | return count; | ||
299 | } | 478 | } |
300 | 479 | ||
301 | static struct file_operations rtlx_fops = { | 480 | static 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 | ||
489 | static struct irqaction rtlx_irq = { | ||
490 | .handler = rtlx_interrupt, | ||
491 | .flags = SA_INTERRUPT, | ||
492 | .name = "RTLX", | ||
493 | }; | ||
494 | |||
495 | static int rtlx_irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ; | ||
496 | |||
310 | static char register_chrdev_failed[] __initdata = | 497 | static 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 | ||
313 | static int __init rtlx_module_init(void) | 500 | static 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, ¬ify); | ||
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); | |||
330 | module_exit(rtlx_module_exit); | 537 | module_exit(rtlx_module_exit); |
331 | 538 | ||
332 | MODULE_DESCRIPTION("MIPS RTLX"); | 539 | MODULE_DESCRIPTION("MIPS RTLX"); |
333 | MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc."); | 540 | MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc."); |
334 | MODULE_LICENSE("GPL"); | 541 | MODULE_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 | ||
530 | int __init fpu_disable(char *s) | 530 | int __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 | ||
107 | static void ipi_resched_dispatch (struct pt_regs *regs) | 109 | static 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 | ||
112 | static void ipi_call_dispatch (struct pt_regs *regs) | 114 | static 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 | ||
117 | irqreturn_t ipi_resched_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 119 | irqreturn_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 | ||
249 | void __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 | ||
244 | void __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 | |||
41 | cpumask_t phys_cpu_present_map; /* Bitmask of available CPUs */ | 45 | cpumask_t phys_cpu_present_map; /* Bitmask of available CPUs */ |
42 | volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ | 46 | volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ |
43 | cpumask_t cpu_online_map; /* Bitmask of currently online CPUs */ | 47 | cpumask_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 | |||
187 | void smp_call_function_interrupt(void) | 197 | void 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 | ||
447 | EXPORT_SYMBOL(flush_tlb_page); | 457 | EXPORT_SYMBOL(flush_tlb_page); |
448 | EXPORT_SYMBOL(flush_tlb_one); | 458 | EXPORT_SYMBOL(flush_tlb_one); |
449 | EXPORT_SYMBOL(cpu_data); | ||
450 | EXPORT_SYMBOL(synchronize_irq); | ||
diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S new file mode 100644 index 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 | /* | ||
26 | The __smtc_ipi_vector would use k0 and k1 as temporaries and | ||
27 | 1) Set EXL (this is per-VPE, so this can't be done by proxy!) | ||
28 | 2) Restore the K/CU and IXMT bits to the pre "exception" state | ||
29 | (EXL means no interrupts and access to the kernel map). | ||
30 | 3) Set EPC to be the saved value of TCRestart. | ||
31 | 4) Jump to the exception handler entry point passed by the sender. | ||
32 | |||
33 | CAN 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 | ||
51 | FEXPORT(__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 | ||
65 | 1: | ||
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 */ | ||
88 | 2: 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 | |||
114 | LEAF(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 | ||
130 | END(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 | */ | ||
31 | unsigned long selfipis[NR_CPUS]; | ||
32 | |||
33 | struct smtc_cpu_proc smtc_cpu_stats[NR_CPUS]; | ||
34 | |||
35 | static struct proc_dir_entry *smtc_stats; | ||
36 | |||
37 | atomic_t smtc_fpu_recoveries; | ||
38 | |||
39 | static 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 | |||
80 | void 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 | |||
65 | asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS]; | ||
66 | |||
67 | /* | ||
68 | * Clock interrupt "latch" buffers, per "CPU" | ||
69 | */ | ||
70 | |||
71 | unsigned 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 | |||
79 | struct smtc_ipi_q IPIQ[NR_CPUS]; | ||
80 | struct smtc_ipi_q freeIPIq; | ||
81 | |||
82 | |||
83 | /* Forward declarations */ | ||
84 | |||
85 | void ipi_decode(struct pt_regs *, struct smtc_ipi *); | ||
86 | void post_direct_ipi(int cpu, struct smtc_ipi *pipi); | ||
87 | void setup_cross_vpe_interrupts(void); | ||
88 | void init_smtc_stats(void); | ||
89 | |||
90 | /* Global SMTC Status */ | ||
91 | |||
92 | unsigned int smtc_status = 0; | ||
93 | |||
94 | /* Boot command line configuration overrides */ | ||
95 | |||
96 | static int vpelimit = 0; | ||
97 | static int tclimit = 0; | ||
98 | static int ipibuffers = 0; | ||
99 | static int nostlb = 0; | ||
100 | static int asidmask = 0; | ||
101 | unsigned long smtc_asid_mask = 0xff; | ||
102 | |||
103 | static int __init maxvpes(char *str) | ||
104 | { | ||
105 | get_option(&str, &vpelimit); | ||
106 | return 1; | ||
107 | } | ||
108 | |||
109 | static int __init maxtcs(char *str) | ||
110 | { | ||
111 | get_option(&str, &tclimit); | ||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | static int __init ipibufs(char *str) | ||
116 | { | ||
117 | get_option(&str, &ipibuffers); | ||
118 | return 1; | ||
119 | } | ||
120 | |||
121 | static int __init stlb_disable(char *s) | ||
122 | { | ||
123 | nostlb = 1; | ||
124 | return 1; | ||
125 | } | ||
126 | |||
127 | static 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 | |||
158 | static int hang_trig = 0; | ||
159 | |||
160 | static 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 | |||
171 | static int timerq_limit = DEFAULT_BLOCKED_IPI_LIMIT; | ||
172 | |||
173 | static int __init tintq(char *str) | ||
174 | { | ||
175 | get_option(&str, &timerq_limit); | ||
176 | return 1; | ||
177 | } | ||
178 | |||
179 | __setup("tintq=", tintq); | ||
180 | |||
181 | int imstuckcount[2][8]; | ||
182 | /* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */ | ||
183 | int vpemask[2][8] = {{0,1,1,0,0,0,0,1},{0,1,0,0,0,0,0,1}}; | ||
184 | int tcnoprog[NR_CPUS]; | ||
185 | static atomic_t idle_hook_initialized = {0}; | ||
186 | static 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 | |||
192 | void __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 | |||
202 | void 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 | |||
302 | int __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 | |||
335 | static 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 | |||
356 | void 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 | */ | ||
546 | void 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 | |||
576 | void 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 | |||
594 | void 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 | |||
600 | void 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 | |||
614 | int 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 | |||
645 | void 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 | */ | ||
664 | static __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 | |||
685 | static __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 | |||
705 | void 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 | */ | ||
778 | void 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 | |||
823 | void ipi_resched_interrupt(struct pt_regs *regs) | ||
824 | { | ||
825 | /* Return from interrupt should be enough to cause scheduler check */ | ||
826 | } | ||
827 | |||
828 | |||
829 | void ipi_call_interrupt(struct pt_regs *regs) | ||
830 | { | ||
831 | /* Invoke generic function invocation code in smp.c */ | ||
832 | smp_call_function_interrupt(); | ||
833 | } | ||
834 | |||
835 | void 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 | |||
871 | void 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 | |||
896 | void 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 | |||
918 | static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ; | ||
919 | |||
920 | static 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 | |||
990 | static void ipi_irq_dispatch(struct pt_regs *regs) | ||
991 | { | ||
992 | do_IRQ(cpu_ipi_irq, regs); | ||
993 | } | ||
994 | |||
995 | static struct irqaction irq_ipi; | ||
996 | |||
997 | void 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 | |||
1017 | void 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 | |||
1138 | void 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 | |||
1164 | void 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 | |||
1243 | void 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 | |||
1278 | int 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 | |||
1289 | void 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 | |||
1305 | void 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 | ||
45 | extern asmlinkage void handle_int(void); | ||
45 | extern asmlinkage void handle_tlbm(void); | 46 | extern asmlinkage void handle_tlbm(void); |
46 | extern asmlinkage void handle_tlbl(void); | 47 | extern asmlinkage void handle_tlbl(void); |
47 | extern asmlinkage void handle_tlbs(void); | 48 | extern asmlinkage void handle_tlbs(void); |
@@ -279,9 +280,16 @@ static DEFINE_SPINLOCK(die_lock); | |||
279 | NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs) | 280 | NORET_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 | ¤t->thread.fpu.soft); | 758 | ¤t->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 | ||
794 | asmlinkage void do_mt(struct pt_regs *regs) | 833 | asmlinkage 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 | */ |
929 | void nmi_exception_handler(struct pt_regs *regs) | 998 | void 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 */ | 1044 | static struct shadow_registers { |
968 | struct 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 | ||
974 | void mips_srs_init(void) | 1055 | static 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 | ||
986 | int mips_srs_max(void) | 1065 | int 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 | ||
991 | int mips_srs_alloc (void) | 1070 | int 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); | 1075 | again: |
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 | ||
1012 | void mips_srs_free (int set) | 1086 | void 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 | ||
1022 | void *set_vi_srs_handler (int n, void *addr, int srs) | 1093 | static 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 | ||
1098 | void *set_vi_handler (int n, void *addr) | 1182 | void *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); | |||
1113 | extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc); | 1197 | extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc); |
1114 | extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc); | 1198 | extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc); |
1115 | 1199 | ||
1200 | #ifdef CONFIG_SMP | ||
1201 | static 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 | |||
1208 | static 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 | |||
1116 | static inline void signal_init(void) | 1216 | static 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 |
7 | OUTPUT_ARCH(mips) | 7 | OUTPUT_ARCH(mips) |
8 | ENTRY(kernel_entry) | 8 | ENTRY(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 | ||
59 | typedef void *vpe_handle; | 57 | typedef void *vpe_handle; |
60 | 58 | ||
@@ -68,6 +66,11 @@ typedef void *vpe_handle; | |||
68 | static char module_name[] = "vpe"; | 66 | static char module_name[] = "vpe"; |
69 | static int major; | 67 | static int major; |
70 | 68 | ||
69 | #ifdef CONFIG_MIPS_APSP_KSPD | ||
70 | static struct kspd_notifications kspd_events; | ||
71 | static 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 | ||
82 | extern unsigned long physical_memsize; | ||
83 | |||
79 | #define MAX_VPES 16 | 84 | #define MAX_VPES 16 |
85 | #define VPE_PATH_MAX 256 | ||
80 | 86 | ||
81 | enum vpe_state { | 87 | enum 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 | ||
118 | struct tc { | 129 | struct tc { |
@@ -138,7 +149,7 @@ struct vpecontrol_ { | |||
138 | } vpecontrol; | 149 | } vpecontrol; |
139 | 150 | ||
140 | static void release_progmem(void *ptr); | 151 | static void release_progmem(void *ptr); |
141 | static void dump_vpe(struct vpe * v); | 152 | /* static __attribute_used__ void dump_vpe(struct vpe * v); */ |
142 | extern void save_gp_address(unsigned int secbase, unsigned int rel); | 153 | extern 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 | |||
504 | out_danger: | ||
505 | printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name); | ||
506 | |||
507 | return -ENOEXEC; | ||
508 | } | 509 | } |
509 | 510 | ||
510 | static int (*reloc_handlers[]) (struct module *me, uint32_t *location, | 511 | static 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 | ||
522 | static 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 | ||
522 | int apply_relocations(Elf32_Shdr *sechdrs, | 532 | int 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. */ |
579 | static int simplify_symbols(Elf_Shdr * sechdrs, | 587 | static 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 | ||
656 | static void dump_tc(struct tc *t) | 662 | static 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 | ||
663 | static void dump_tclist(void) | 686 | static 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... */ |
673 | int vpe_run(struct vpe * v) | 696 | int 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 | ||
764 | static unsigned long find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, | 799 | static 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 | */ |
789 | int vpe_elfload(struct vpe * v) | 827 | int 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; | |
921 | cleanup: | ||
922 | return err; | ||
923 | } | 1014 | } |
924 | 1015 | ||
925 | static 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 */ | 1029 | static 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 | |||
1052 | static 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 */ | ||
938 | static int vpe_open(struct inode *inode, struct file *filp) | 1068 | static 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 | ||
1160 | EXPORT_SYMBOL(vpe_get_shared); | 1302 | EXPORT_SYMBOL(vpe_get_shared); |
1161 | 1303 | ||
1304 | int 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 | |||
1314 | EXPORT_SYMBOL(vpe_getuid); | ||
1315 | |||
1316 | int 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 | |||
1326 | EXPORT_SYMBOL(vpe_getgid); | ||
1327 | |||
1328 | int 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(¬ify->list, &v->notify); | ||
1336 | return 0; | ||
1337 | } | ||
1338 | |||
1339 | EXPORT_SYMBOL(vpe_notify); | ||
1340 | |||
1341 | char *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 | |||
1351 | EXPORT_SYMBOL(vpe_getcwd); | ||
1352 | |||
1353 | #ifdef CONFIG_MIPS_APSP_KSPD | ||
1354 | static void kspd_sp_exit( int sp_id) | ||
1355 | { | ||
1356 | cleanup_tc(get_tc(sp_id)); | ||
1357 | } | ||
1358 | #endif | ||
1359 | |||
1162 | static int __init vpe_module_init(void) | 1360 | static 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) | |||
1281 | module_init(vpe_module_init); | 1490 | module_init(vpe_module_init); |
1282 | module_exit(vpe_module_exit); | 1491 | module_exit(vpe_module_exit); |
1283 | MODULE_DESCRIPTION("MIPS VPE Loader"); | 1492 | MODULE_DESCRIPTION("MIPS VPE Loader"); |
1284 | MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc"); | 1493 | MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc."); |
1285 | MODULE_LICENSE("GPL"); | 1494 | MODULE_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 | ||
5 | obj-y += reset.o setup.o prom.o lasat_board.o \ | 5 | obj-y += reset.o setup.o prom.o lasat_board.o \ |
6 | at93c.o interrupt.o lasatIRQ.o | 6 | at93c.o interrupt.o |
7 | 7 | ||
8 | obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o | 8 | obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o |
9 | obj-$(CONFIG_DS1603) += ds1603.o | 9 | obj-$(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 | ||
32 | static volatile int *lasat_int_status = NULL; | 33 | static volatile int *lasat_int_status = NULL; |
33 | static volatile int *lasat_int_mask = NULL; | 34 | static volatile int *lasat_int_mask = NULL; |
34 | static volatile int lasat_int_mask_shift; | 35 | static volatile int lasat_int_mask_shift; |
35 | 36 | ||
36 | extern asmlinkage void lasatIRQ(void); | ||
37 | |||
38 | void disable_lasat_irq(unsigned int irq_nr) | 37 | void 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 | ||
112 | void lasat_hw0_irqdispatch(struct pt_regs *regs) | 111 | asmlinkage 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 | |||
50 | 1: | ||
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 | |||
58 | 1: | ||
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 | ||
40 | static struct atlas_ictrl_regs *atlas_hw0_icregs; | 40 | static struct atlas_ictrl_regs *atlas_hw0_icregs; |
41 | 41 | ||
42 | extern 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 | ||
101 | void atlas_hw0_irqdispatch(struct pt_regs *regs) | 99 | static 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 | ||
117 | static 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 | */ | ||
133 | static 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 | */ | ||
187 | asmlinkage 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 | |||
119 | void __init arch_init_irq(void) | 202 | void __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 | ||
21 | obj-y := mipsIRQ.o reset.o display.o init.o memory.o \ | 21 | obj-y := reset.o display.o init.o memory.o printf.o \ |
22 | printf.o cmdline.o time.o | 22 | cmdline.o time.o |
23 | obj-$(CONFIG_PCI) += pci.o | 23 | obj-$(CONFIG_PCI) += pci.o |
24 | obj-$(CONFIG_KGDB) += gdb_hook.o | 24 | obj-$(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 | ||
28 | static struct serial_state rs_table[RS_TABLE_SIZE] = { | 28 | static 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 */ | ||
50 | extern char _end; | ||
51 | |||
52 | struct prom_pmemblock * __init prom_getmdesc(void) | 51 | struct 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 | ||
140 | 1: | ||
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 | |||
152 | spurious: | ||
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; | |||
50 | static char display_string[] = " LINUX ON ATLAS "; | 51 | static 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) | ||
55 | static char display_string[] = " SMTC LINUX ON MALTA "; | ||
56 | #else | ||
53 | static char display_string[] = " LINUX ON MALTA "; | 57 | static 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) |
56 | static char display_string[] = " LINUX ON SEAD "; | 61 | static char display_string[] = " LINUX ON SEAD "; |
57 | #endif | 62 | #endif |
58 | static unsigned int display_count = 0; | 63 | static unsigned int display_count; |
59 | #define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) | 64 | #define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) |
60 | 65 | ||
61 | static unsigned int timer_tick_count=0; | 66 | #define CPUCTR_IMASKBIT (0x100 << MIPSCPU_INT_CPUCTR) |
67 | |||
68 | static unsigned int timer_tick_count; | ||
62 | static int mips_cpu_timer_irq; | 69 | static int mips_cpu_timer_irq; |
70 | extern void smtc_timer_broadcast(int); | ||
63 | 71 | ||
64 | static inline void scroll_display_message(void) | 72 | static 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 | */ | ||
78 | extern int null_perf_irq(struct pt_regs *regs); | 89 | extern int null_perf_irq(struct pt_regs *regs); |
79 | 90 | ||
80 | extern int (*perf_irq)(struct pt_regs *regs); | 91 | extern int (*perf_irq)(struct pt_regs *regs); |
81 | 92 | ||
82 | irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 93 | irqreturn_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 | ||
117 | out: | 167 | out: |
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 | ||
22 | obj-y := malta_int.o malta_setup.o | 22 | obj-y := malta_int.o malta_setup.o |
23 | obj-$(CONFIG_SMP) += malta_smp.o | ||
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index 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 | ||
43 | extern asmlinkage void mipsIRQ(void); | ||
44 | extern void mips_timer_interrupt(void); | 43 | extern void mips_timer_interrupt(void); |
45 | 44 | ||
46 | static DEFINE_SPINLOCK(mips_irq_lock); | 45 | static 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 | ||
117 | void malta_hw0_irqdispatch(struct pt_regs *regs) | 116 | static 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 | ||
185 | static 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 | */ | ||
201 | static 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 | |||
256 | asmlinkage 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 | |||
185 | static struct irqaction i8259irq = { | 271 | static 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 | ||
215 | void __init arch_init_irq(void) | 301 | void __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 | |||
28 | void 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 | |||
40 | void __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 | |||
59 | void 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 | |||
70 | void 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 | |||
97 | void plat_smp_setup(void) | ||
98 | { | ||
99 | if (read_c0_config3() & (1<<2)) | ||
100 | mipsmt_build_cpu_map(0); | ||
101 | } | ||
102 | |||
103 | void __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 | |||
113 | void 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 | |||
124 | void 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 | ||
31 | extern asmlinkage void mipsIRQ(void); | 32 | static 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 | */ | ||
48 | static 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 | */ | ||
101 | asmlinkage 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 | ||
33 | void __init arch_init_irq(void) | 114 | void __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 | |||
25 | extern int prom_argc; | ||
26 | extern 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 | |||
34 | char arcs_cmdline[CL_SIZE]; | ||
35 | |||
36 | char * __init prom_getcmdline(void) | ||
37 | { | ||
38 | return &(arcs_cmdline[0]); | ||
39 | } | ||
40 | |||
41 | |||
42 | void __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 | |||
30 | void __init prom_init_cmdline(void) | 29 | void __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 | ||
26 | extern void mips_cpu_irq_init(int); | 26 | extern void mips_cpu_irq_init(int); |
27 | 27 | ||
28 | extern asmlinkage void simIRQ(void); | 28 | static 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 | */ | ||
44 | static 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 | ||
30 | asmlinkage 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 | |||
74 | static 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 | ||
35 | void __init arch_init_irq(void) | 79 | asmlinkage 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 | |||
92 | void __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 | ||
96 | spurious: | 96 | spurious: |
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 */ | ||
43 | extern char _end; | ||
44 | |||
45 | struct prom_pmemblock * __init prom_getmdesc(void) | 44 | struct 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 @@ | |||
44 | void core_send_ipi(int cpu, unsigned int action) | 44 | void 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) | |||
59 | void __init prom_build_cpu_map(void) | 57 | void __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) | |||
87 | void prom_boot_secondary(int cpu, struct task_struct *idle) | 78 | void 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) | |||
113 | void prom_prepare_cpus(unsigned int max_cpus) | 102 | void 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) | |||
132 | void prom_smp_finish(void) | 120 | void 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 | ||
263 | static void local_r3k_flush_data_cache_page(unsigned long addr) | ||
264 | { | ||
265 | } | ||
266 | |||
263 | static void r3k_flush_data_cache_page(unsigned long addr) | 267 | static 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 | ||
155 | static inline void tx49_blast_icache32_page_indexed(unsigned long page) | 155 | static 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 | ||
219 | static void local_tx39_flush_data_cache_page(void * addr) | ||
220 | { | ||
221 | tx39_blast_dcache_page(addr); | ||
222 | } | ||
223 | |||
219 | static void tx39_flush_data_cache_page(unsigned long addr) | 224 | static 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 */ |
32 | void (*flush_cache_sigtramp)(unsigned long addr); | 32 | void (*flush_cache_sigtramp)(unsigned long addr); |
33 | void (*local_flush_data_cache_page)(void * addr); | ||
33 | void (*flush_data_cache_page)(unsigned long addr); | 34 | void (*flush_data_cache_page)(unsigned long addr); |
34 | void (*flush_icache_all)(void); | 35 | void (*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 | |||
205 | vmalloc_fault: | 212 | vmalloc_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 | ||
105 | struct page *__kmap_atomic_to_page(void *ptr) | 107 | struct 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 | ||
279 | void 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 |
280 | void free_initrd_mem(unsigned long start, unsigned long end) | 294 | void 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 | ||
302 | void free_initmem(void) | 307 | void 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 | |||
35 | void local_flush_tlb_all(void) | 57 | void 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 | ||
168 | void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | 191 | void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) |
@@ -175,7 +198,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | |||
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); |
388 | out: | 411 | out: |
389 | local_irq_restore(flags); | 412 | EXIT_CRITICAL(flags); |
390 | return ret; | 413 | return ret; |
391 | } | 414 | } |
392 | 415 | ||
416 | extern void __init sanitize_tlb_entries(void); | ||
393 | static void __init probe_tlb(unsigned long config) | 417 | static void __init probe_tlb(unsigned long config) |
394 | { | 418 | { |
395 | struct cpuinfo_mips *c = ¤t_cpu_data; | 419 | struct cpuinfo_mips *c = ¤t_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 | ||
445 | static int __initdata ntlb = 0; | ||
446 | static int __init set_ntlb(char *str) | ||
447 | { | ||
448 | get_option(&str, &ntlb); | ||
449 | return 1; | ||
450 | } | ||
451 | |||
452 | __setup("ntlb=", set_ntlb); | ||
453 | |||
413 | void __init tlb_init(void) | 454 | void __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 | ||
90 | enum opcode { | 103 | enum 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 | ||
258 | static __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); | |||
358 | I_u1s2(_bltz); | 380 | I_u1s2(_bltz); |
359 | I_u1s2(_bltzl); | 381 | I_u1s2(_bltzl); |
360 | I_u1u2s3(_bne); | 382 | I_u1u2s3(_bne); |
361 | I_u1u2(_dmfc0); | 383 | I_u1u2u3(_dmfc0); |
362 | I_u1u2(_dmtc0); | 384 | I_u1u2u3(_dmtc0); |
363 | I_u2u1s3(_daddiu); | 385 | I_u2u1s3(_daddiu); |
364 | I_u3u1u2(_daddu); | 386 | I_u3u1u2(_daddu); |
365 | I_u2u1u3(_dsll); | 387 | I_u2u1u3(_dsll); |
@@ -376,8 +398,8 @@ I_u2s3u1(_ll); | |||
376 | I_u2s3u1(_lld); | 398 | I_u2s3u1(_lld); |
377 | I_u1s2(_lui); | 399 | I_u1s2(_lui); |
378 | I_u2s3u1(_lw); | 400 | I_u2s3u1(_lw); |
379 | I_u1u2(_mfc0); | 401 | I_u1u2u3(_mfc0); |
380 | I_u1u2(_mtc0); | 402 | I_u1u2u3(_mtc0); |
381 | I_u2u1u3(_ori); | 403 | I_u2u1u3(_ori); |
382 | I_0(_rfe); | 404 | I_0(_rfe); |
383 | I_u2s3u1(_sc); | 405 | I_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 | ||
9 | obj-y += int-handler.o irq.o prom.o reset.o setup.o | 9 | obj-y += irq.o prom.o reset.o setup.o |
10 | 10 | ||
11 | obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o | 11 | obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o |
12 | obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o | 12 | obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o |
diff --git a/arch/mips/momentum/jaguar_atx/int-handler.S b/arch/mips/momentum/jaguar_atx/int-handler.S deleted file mode 100644 index 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 | ||
79 | ll_sw0_irq: | ||
80 | li a0, 0 | ||
81 | move a1, sp | ||
82 | jal do_IRQ | ||
83 | j ret_from_irq | ||
84 | ll_sw1_irq: | ||
85 | li a0, 1 | ||
86 | move a1, sp | ||
87 | jal do_IRQ | ||
88 | j ret_from_irq | ||
89 | ll_pcixa_irq: | ||
90 | li a0, 2 | ||
91 | move a1, sp | ||
92 | jal do_IRQ | ||
93 | j ret_from_irq | ||
94 | |||
95 | ll_pcixb_irq: | ||
96 | li a0, 3 | ||
97 | move a1, sp | ||
98 | jal do_IRQ | ||
99 | j ret_from_irq | ||
100 | |||
101 | ll_pcia_irq: | ||
102 | li a0, 4 | ||
103 | move a1, sp | ||
104 | jal do_IRQ | ||
105 | j ret_from_irq | ||
106 | |||
107 | ll_pcib_irq: | ||
108 | li a0, 5 | ||
109 | move a1, sp | ||
110 | jal do_IRQ | ||
111 | j ret_from_irq | ||
112 | |||
113 | ll_uart_irq: | ||
114 | li a0, 6 | ||
115 | move a1, sp | ||
116 | jal do_IRQ | ||
117 | j ret_from_irq | ||
118 | |||
119 | ll_cputimer_irq: | ||
120 | li a0, 7 | ||
121 | move a1, sp | ||
122 | jal ll_timer_interrupt | ||
123 | j ret_from_irq | ||
124 | |||
125 | ll_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 | ||
42 | extern asmlinkage void jaguar_handle_int(void); | 43 | asmlinkage 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 | ||
44 | static struct irqaction cascade_mv64340 = { | 73 | static 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 | # |
8 | obj-y += int-handler.o irq.o prom.o reset.o setup.o | 8 | obj-y += irq.o prom.o reset.o setup.o |
diff --git a/arch/mips/momentum/ocelot_3/int-handler.S b/arch/mips/momentum/ocelot_3/int-handler.S deleted file mode 100644 index 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 | ||
86 | ll_sw0_irq: | ||
87 | li a0, 0 /* IRQ 1 */ | ||
88 | move a1, sp | ||
89 | jal do_IRQ | ||
90 | j ret_from_irq | ||
91 | ll_sw1_irq: | ||
92 | li a0, 1 /* IRQ 2 */ | ||
93 | move a1, sp | ||
94 | jal do_IRQ | ||
95 | j ret_from_irq | ||
96 | |||
97 | ll_pci0slot1_irq: | ||
98 | li a0, 2 /* IRQ 3 */ | ||
99 | move a1, sp | ||
100 | jal do_IRQ | ||
101 | j ret_from_irq | ||
102 | |||
103 | ll_pci0slot2_irq: | ||
104 | li a0, 3 /* IRQ 4 */ | ||
105 | move a1, sp | ||
106 | jal do_IRQ | ||
107 | j ret_from_irq | ||
108 | |||
109 | ll_pci1slot1_irq: | ||
110 | li a0, 4 /* IRQ 5 */ | ||
111 | move a1, sp | ||
112 | jal do_IRQ | ||
113 | j ret_from_irq | ||
114 | |||
115 | ll_pci1slot2_irq: | ||
116 | li a0, 5 /* IRQ 6 */ | ||
117 | move a1, sp | ||
118 | jal do_IRQ | ||
119 | j ret_from_irq | ||
120 | |||
121 | ll_uart_irq: | ||
122 | li a0, 6 /* IRQ 7 */ | ||
123 | move a1, sp | ||
124 | jal do_IRQ | ||
125 | j ret_from_irq | ||
126 | |||
127 | ll_cputimer_irq: | ||
128 | li a0, 7 /* IRQ 8 */ | ||
129 | move a1, sp | ||
130 | jal do_IRQ | ||
131 | j ret_from_irq | ||
132 | |||
133 | ll_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 | ||
56 | extern asmlinkage void ocelot3_handle_int(void); | ||
57 | |||
58 | static struct irqaction cascade_mv64340 = { | 56 | static 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 | |||
78 | asmlinkage 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 | ||
5 | obj-y += cpci-irq.o int-handler.o irq.o prom.o reset.o \ | 5 | obj-y += cpci-irq.o irq.o prom.o reset.o \ |
6 | setup.o uart-irq.o | 6 | setup.o uart-irq.o |
7 | 7 | ||
8 | obj-$(CONFIG_KGDB) += dbg_io.o | 8 | obj-$(CONFIG_KGDB) += dbg_io.o |
diff --git a/arch/mips/momentum/ocelot_c/int-handler.S b/arch/mips/momentum/ocelot_c/int-handler.S deleted file mode 100644 index 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 | ||
60 | ll_sw0_irq: | ||
61 | li a0, 0 | ||
62 | move a1, sp | ||
63 | jal do_IRQ | ||
64 | j ret_from_irq | ||
65 | ll_sw1_irq: | ||
66 | li a0, 1 | ||
67 | move a1, sp | ||
68 | jal do_IRQ | ||
69 | j ret_from_irq | ||
70 | ll_scsi_irq: | ||
71 | li a0, 2 | ||
72 | move a1, sp | ||
73 | jal do_IRQ | ||
74 | j ret_from_irq | ||
75 | |||
76 | ll_uart_decode_irq: | ||
77 | move a0, sp | ||
78 | jal ll_uart_irq | ||
79 | j ret_from_irq | ||
80 | |||
81 | ll_pmc_irq: | ||
82 | li a0, 4 | ||
83 | move a1, sp | ||
84 | jal do_IRQ | ||
85 | j ret_from_irq | ||
86 | |||
87 | ll_cpci_decode_irq: | ||
88 | move a0, sp | ||
89 | jal ll_cpci_irq | ||
90 | j ret_from_irq | ||
91 | |||
92 | ll_mv64340_decode_irq: | ||
93 | move a0, sp | ||
94 | jal ll_mv64340_irq | ||
95 | j ret_from_irq | ||
96 | |||
97 | ll_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 | ||
51 | extern asmlinkage void ocelot_handle_int(void); | ||
52 | extern void uart_irq_init(void); | 51 | extern void uart_irq_init(void); |
53 | extern void cpci_irq_init(void); | 52 | extern 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 | ||
62 | extern void ll_uart_irq(struct pt_regs *regs); | ||
63 | extern void ll_cpci_irq(struct pt_regs *regs); | ||
64 | |||
65 | asmlinkage 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 | |||
63 | void __init arch_init_irq(void) | 89 | void __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 | ||
5 | obj-y += int-handler.o irq.o gt-irq.o prom.o reset.o setup.o | 5 | obj-y += irq.o gt-irq.o prom.o reset.o setup.o |
6 | obj-$(CONFIG_KGDB) += dbg_io.o | 6 | obj-$(CONFIG_KGDB) += dbg_io.o |
7 | 7 | ||
8 | EXTRA_AFLAGS := $(CFLAGS) | 8 | EXTRA_AFLAGS := $(CFLAGS) |
diff --git a/arch/mips/momentum/ocelot_g/int-handler.S b/arch/mips/momentum/ocelot_g/int-handler.S deleted file mode 100644 index 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 | ||
73 | ll_pri_enet_irq: | ||
74 | li a0, 2 | ||
75 | move a1, sp | ||
76 | jal do_IRQ | ||
77 | j ret_from_irq | ||
78 | |||
79 | ll_sec_enet_irq: | ||
80 | li a0, 3 | ||
81 | move a1, sp | ||
82 | jal do_IRQ | ||
83 | j ret_from_irq | ||
84 | |||
85 | ll_uart_irq: | ||
86 | li a0, 4 | ||
87 | move a1, sp | ||
88 | jal do_IRQ | ||
89 | j ret_from_irq | ||
90 | |||
91 | ll_cpci_irq: | ||
92 | li a0, 5 | ||
93 | move a1, sp | ||
94 | jal do_IRQ | ||
95 | j ret_from_irq | ||
96 | |||
97 | ll_galileo_p0_irq: | ||
98 | li a0, 6 | ||
99 | move a1, sp | ||
100 | jal do_IRQ | ||
101 | j ret_from_irq | ||
102 | |||
103 | ll_cputimer_irq: | ||
104 | li a0, 7 | ||
105 | move a1, sp | ||
106 | jal do_IRQ | ||
107 | j ret_from_irq | ||
108 | |||
109 | ll_galileo_p1_irq: | ||
110 | li a0, 8 | ||
111 | move a1, sp | ||
112 | jal do_IRQ | ||
113 | j ret_from_irq | ||
114 | |||
115 | ll_pmc_irq: | ||
116 | li a0, 9 | ||
117 | move a1, sp | ||
118 | jal do_IRQ | ||
119 | j ret_from_irq | ||
120 | |||
121 | ll_cpci_abcd_irq: | ||
122 | li a0, 10 | ||
123 | move a1, sp | ||
124 | jal do_IRQ | ||
125 | j ret_from_irq | ||
126 | |||
127 | ll_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 | ||
51 | extern asmlinkage void ocelot_handle_int(void); | 51 | asmlinkage 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 | |||
52 | extern void gt64240_irq_init(void); | 86 | extern void gt64240_irq_init(void); |
53 | 87 | ||
54 | void __init arch_init_irq(void) | 88 | void __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 | ||
25 | obj-y := setup.o prom.o mipsIRQ.o int.o reset.o time.o proc.o platform.o | 25 | obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o |
26 | obj-$(CONFIG_PCI) += pci.o | 26 | obj-$(CONFIG_PCI) += pci.o |
27 | obj-$(CONFIG_KGDB) += gdb_hook.o | 27 | obj-$(CONFIG_KGDB) += gdb_hook.o |
diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c index 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 | ||
41 | extern asmlinkage void cp0_irqdispatch(void); | ||
42 | |||
43 | static DEFINE_SPINLOCK(irq_lock); | 41 | static 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 | ||
58 | void hw0_irqdispatch(int irq, struct pt_regs *regs) | 56 | static 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 | ||
71 | void timer_irqdispatch(int irq, struct pt_regs *regs) | 69 | static 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 | ||
89 | asmlinkage 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 | |||
91 | static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) | 103 | static 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 | ||
55 | ll_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 | ||
65 | ll_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 | |||
75 | ll_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 | ||
5 | obj-y += irq-handler.o irq.o i2c-yosemite.o prom.o py-console.o setup.o | 5 | obj-y += irq.o i2c-yosemite.o prom.o py-console.o setup.o |
6 | 6 | ||
7 | obj-$(CONFIG_KGDB) += dbg_io.o | 7 | obj-$(CONFIG_KGDB) += dbg_io.o |
8 | obj-$(CONFIG_SMP) += smp.o | 8 | obj-$(CONFIG_SMP) += smp.o |
diff --git a/arch/mips/pmc-sierra/yosemite/irq-handler.S b/arch/mips/pmc-sierra/yosemite/irq-handler.S deleted file mode 100644 index 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 | |||
57 | ll_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 | |||
66 | ll_pcib_irq: | ||
67 | li a0, 3 | ||
68 | move a1, sp | ||
69 | j do_IRQ | ||
70 | |||
71 | ll_duart_irq: | ||
72 | li a0, 4 | ||
73 | move a1, sp | ||
74 | j do_IRQ | ||
75 | |||
76 | ll_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 | |||
85 | ll_ht_irq: | ||
86 | li a0, 6 | ||
87 | move a1, sp | ||
88 | j ll_ht_smp_irq_handler | ||
89 | |||
90 | ll_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 | ||
58 | extern asmlinkage void titan_handle_int(void); | ||
59 | extern void jaguar_mailbox_irq(struct pt_regs *); | 60 | extern 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 | ||
129 | asmlinkage 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 |
129 | extern void init_second_port(void); | 159 | extern 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 | ||
5 | obj-y = q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o | 5 | obj-y = q-firmware.o q-irq.o q-mem.o q-setup.o |
6 | 6 | ||
7 | obj-$(CONFIG_SMP) += q-smp.o | 7 | obj-$(CONFIG_SMP) += q-smp.o |
diff --git a/arch/mips/qemu/q-int.S b/arch/mips/qemu/q-int.S deleted file mode 100644 index 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 | ||
10 | extern asmlinkage void qemu_handle_int(void); | 10 | extern asmlinkage void qemu_handle_int(void); |
11 | 11 | ||
12 | asmlinkage void do_qemu_int(struct pt_regs *regs) | 12 | asmlinkage 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 | ||
30 | void __init arch_init_irq(void) | 30 | void __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 | ||
6 | obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-irq.o ip22-berr.o \ | 6 | obj-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 | ||
9 | obj-$(CONFIG_EISA) += ip22-eisa.o | 9 | obj-$(CONFIG_EISA) += ip22-eisa.o |
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index 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]; | |||
37 | static char lc2msk_to_irqnr[256]; | 37 | static char lc2msk_to_irqnr[256]; |
38 | static char lc3msk_to_irqnr[256]; | 38 | static char lc3msk_to_irqnr[256]; |
39 | 39 | ||
40 | extern asmlinkage void indyIRQ(void); | ||
41 | extern int ip22_eisa_init(void); | 40 | extern int ip22_eisa_init(void); |
42 | 41 | ||
43 | static void enable_local0_irq(unsigned int irq) | 42 | static 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 | ||
227 | void indy_local0_irqdispatch(struct pt_regs *regs) | 226 | static 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 | ||
245 | void indy_local1_irqdispatch(struct pt_regs *regs) | 244 | static 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 | ||
263 | extern void ip22_be_interrupt(int irq, struct pt_regs *regs); | 262 | extern void ip22_be_interrupt(int irq, struct pt_regs *regs); |
264 | 263 | ||
265 | void indy_buserror_irq(struct pt_regs *regs) | 264 | static 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 | ||
309 | extern void indy_r4k_timer_interrupt(struct pt_regs *regs); | ||
310 | extern 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 | |||
340 | asmlinkage 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 | |||
310 | extern void mips_cpu_irq_init(unsigned int irq_base); | 359 | extern void mips_cpu_irq_init(unsigned int irq_base); |
311 | 360 | ||
312 | void __init arch_init_irq(void) | 361 | void __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 | |||
73 | 1: | ||
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 | |||
84 | 1: | ||
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 | |||
94 | 1: | ||
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 | |||
104 | 1: | ||
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 | ||
115 | 1: | ||
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 | ||
5 | obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \ | 5 | obj-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 | |||
9 | in irix? | 9 | in irix? |
10 | 6. Investigate why things do not work without the setup_test() call | 10 | 6. Investigate why things do not work without the setup_test() call |
11 | being invoked on all nodes in ip27-memory.c. | 11 | being invoked on all nodes in ip27-memory.c. |
12 | 7. Too many CLIs in the locore handlers : | ||
13 | For the low level handlers set up by set_except_vector(), | ||
14 | __tlb_refill_debug_tramp, __xtlb_refill_debug_tramp and cacheerror, | ||
15 | investigate whether the code should do CLI, STI or KMODE. | ||
16 | 8. Too many do_page_faults invoked - investigate. | 12 | 8. Too many do_page_faults invoked - investigate. |
17 | 9. start_thread must turn off UX64 ... and define tlb_refill_debug. | 13 | 9. start_thread must turn off UX64 ... and define tlb_refill_debug. |
18 | 10. Need a bad pmd table, bad pte table. __bad_pmd_table/__bad_pagetable | 14 | 10. Need a bad pmd table, bad pte table. __bad_pmd_table/__bad_pagetable |
diff --git a/arch/mips/sgi-ip27/ip27-irq-glue.S b/arch/mips/sgi-ip27/ip27-irq-glue.S deleted file mode 100644 index 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 | ||
16 | NESTED(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 | |||
39 | ip2: j ip27_do_irq_mask0 # PI_INT_PEND_0 or CC_PEND_{A|B} | ||
40 | ip3: j ip27_do_irq_mask1 # PI_INT_PEND_1 | ||
41 | ip4: j ip27_rt_timer_interrupt | ||
42 | ip5: j ip27_prof_timer | ||
43 | ip6: 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 | ||
133 | void ip27_do_irq_mask0(struct pt_regs *regs) | 133 | static 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 | ||
174 | void ip27_do_irq_mask1(struct pt_regs *regs) | 174 | static 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 | ||
199 | void ip27_prof_timer(struct pt_regs *regs) | 199 | static 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 | ||
204 | void ip27_hub_error(struct pt_regs *regs) | 204 | static 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 | ||
424 | extern void ip27_rt_timer_interrupt(struct pt_regs *regs); | ||
425 | |||
426 | asmlinkage 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 | |||
424 | void __init arch_init_irq(void) | 442 | void __init arch_init_irq(void) |
425 | { | 443 | { |
426 | set_except_vector(0, ip27_irq); | ||
427 | } | 444 | } |
428 | 445 | ||
429 | void install_ipi(void) | 446 | void 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 | ||
6 | obj-y += ip32-berr.o ip32-irq.o ip32-irq-glue.o ip32-setup.o ip32-reset.o \ | 6 | obj-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 | ||
9 | EXTRA_AFLAGS := $(CFLAGS) | 9 | EXTRA_AFLAGS := $(CFLAGS) |
diff --git a/arch/mips/sgi-ip32/ip32-irq-glue.S b/arch/mips/sgi-ip32/ip32-irq-glue.S deleted file mode 100644 index 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 | |||
50 | handle_irq0: | ||
51 | jal ip32_irq0 | ||
52 | move a0, sp | ||
53 | j ret_from_irq | ||
54 | nop | ||
55 | |||
56 | handle_irq1: | ||
57 | jal ip32_irq1 | ||
58 | move a0, sp | ||
59 | j ret_from_irq | ||
60 | nop | ||
61 | |||
62 | handle_irq2: | ||
63 | jal ip32_irq2 | ||
64 | move a0, sp | ||
65 | j ret_from_irq | ||
66 | nop | ||
67 | |||
68 | handle_irq3: | ||
69 | jal ip32_irq3 | ||
70 | move a0, sp | ||
71 | j ret_from_irq | ||
72 | nop | ||
73 | |||
74 | handle_irq4: | ||
75 | jal ip32_irq4 | ||
76 | move a0, sp | ||
77 | j ret_from_irq | ||
78 | nop | ||
79 | |||
80 | handle_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, | |||
130 | struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT, | 130 | struct 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 | ||
133 | extern 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 */ |
506 | void ip32_irq0(struct pt_regs *regs) | 504 | static 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 | ||
523 | void ip32_irq1(struct pt_regs *regs) | 521 | static void ip32_irq1(struct pt_regs *regs) |
524 | { | 522 | { |
525 | ip32_unknown_interrupt(regs); | 523 | ip32_unknown_interrupt(regs); |
526 | } | 524 | } |
527 | 525 | ||
528 | void ip32_irq2(struct pt_regs *regs) | 526 | static void ip32_irq2(struct pt_regs *regs) |
529 | { | 527 | { |
530 | ip32_unknown_interrupt(regs); | 528 | ip32_unknown_interrupt(regs); |
531 | } | 529 | } |
532 | 530 | ||
533 | void ip32_irq3(struct pt_regs *regs) | 531 | static void ip32_irq3(struct pt_regs *regs) |
534 | { | 532 | { |
535 | ip32_unknown_interrupt(regs); | 533 | ip32_unknown_interrupt(regs); |
536 | } | 534 | } |
537 | 535 | ||
538 | void ip32_irq4(struct pt_regs *regs) | 536 | static void ip32_irq4(struct pt_regs *regs) |
539 | { | 537 | { |
540 | ip32_unknown_interrupt(regs); | 538 | ip32_unknown_interrupt(regs); |
541 | } | 539 | } |
542 | 540 | ||
543 | void ip32_irq5(struct pt_regs *regs) | 541 | static 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 | ||
546 | asmlinkage 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 | |||
548 | void __init arch_init_irq(void) | 564 | void __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 @@ | |||
1 | obj-y := setup.o irq.o irq_handler.o time.o | 1 | obj-y := setup.o irq.o time.o |
2 | 2 | ||
3 | obj-$(CONFIG_SMP) += smp.o | 3 | obj-$(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 */ | ||
191 | extern void bcm1480_irq_handler(void); | ||
192 | |||
193 | /*****************************************************************************/ | 190 | /*****************************************************************************/ |
194 | 191 | ||
195 | static unsigned int startup_bcm1480_irq(unsigned int irq) | 192 | static 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 | |||
473 | static 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 | |||
488 | extern void bcm1480_timer_interrupt(struct pt_regs *regs); | ||
489 | extern void bcm1480_mailbox_interrupt(struct pt_regs *regs); | ||
490 | extern void bcm1480_kgdb_interrupt(struct pt_regs *regs); | ||
491 | |||
492 | asmlinkage 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 | ||
87 | 0: | ||
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 */ | ||
98 | 1: | ||
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 */ | ||
109 | 2: | ||
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 */ | ||
121 | 3: | ||
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 | |||
161 | 9: 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 @@ | |||
1 | obj-y := setup.o irq.o irq_handler.o time.o | 1 | obj-y := setup.o irq.o time.o |
2 | 2 | ||
3 | obj-$(CONFIG_SMP) += smp.o | 3 | obj-$(CONFIG_SMP) += smp.o |
4 | obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o | 4 | obj-$(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 */ | ||
168 | extern void sb1250_irq_handler(void); | ||
169 | |||
170 | /*****************************************************************************/ | 166 | /*****************************************************************************/ |
171 | 167 | ||
172 | static unsigned int startup_sb1250_irq(unsigned int irq) | 168 | static 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 | ||
412 | void sb1250_kgdb_interrupt(struct pt_regs *regs) | 407 | static 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 | |||
423 | static 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 | |||
438 | asmlinkage 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 | ||
80 | 0: | ||
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 | ||
91 | 1: | ||
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 | ||
102 | 2: | ||
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 | ||
114 | 1: | ||
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 | |||
137 | 3: dclz s1, s0 /* Find the next interrupt */ | ||
138 | dsubu a0, zero, s1 | ||
139 | daddiu a0, a0, 63 | ||
140 | jal do_IRQ | ||
141 | nop | ||
142 | |||
143 | 4: 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 | ||
5 | obj-y += int-handler.o irq.o pcimt_scache.o reset.o setup.o | 5 | obj-y += irq.o pcimt_scache.o reset.o setup.o |
6 | 6 | ||
7 | EXTRA_AFLAGS := $(CFLAGS) | 7 | EXTRA_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 | ||
33 | led_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 | ||
20 | DEFINE_SPINLOCK(pciasic_lock); | 20 | DEFINE_SPINLOCK(pciasic_lock); |
21 | 21 | ||
22 | extern asmlinkage void sni_rm200_pci_handle_int(void); | ||
23 | |||
24 | static void enable_pciasic_irq(unsigned int irq) | 22 | static 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 | */ |
74 | void pciasic_hwint0(struct pt_regs *regs) | 72 | static 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. */ |
80 | void pciasic_hwint2(struct pt_regs *regs) | 78 | static 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 */ |
87 | void pciasic_hwint5(struct pt_regs *regs) | 85 | static 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 | */ |
108 | void pciasic_hwint1(struct pt_regs *regs) | 106 | static 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 | */ |
138 | void pciasic_hwint3(struct pt_regs *regs) | 136 | static 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 | */ |
153 | void pciasic_hwint4(struct pt_regs *regs) | 151 | static 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 | ||
158 | asmlinkage 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 | |||
160 | void __init init_pciasic(void) | 179 | void __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 | ||
9 | obj-y += tx4927_prom.o tx4927_setup.o tx4927_irq.o tx4927_irq_handler.o | 9 | obj-y += tx4927_prom.o tx4927_setup.o tx4927_irq.o |
10 | 10 | ||
11 | obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o | 11 | obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o |
12 | obj-$(CONFIG_KGDB) += tx4927_dbgio.o | 12 | obj-$(CONFIG_KGDB) += tx4927_dbgio.o |
diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c index 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 | */ |
526 | void __init tx4927_irq_init(void) | 526 | void __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 | ||
547 | int tx4927_irq_nested(void) | 541 | static 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 | |||
580 | asmlinkage 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 | |||
73 | ll_ip7: | ||
74 | li a0, TX4927_IRQ_CPU_TIMER | ||
75 | move a1, sp | ||
76 | jal do_IRQ | ||
77 | j ret_from_irq | ||
78 | |||
79 | ll_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 | |||
89 | goto_spurious_interrupt: | ||
90 | j spurious_interrupt | ||
91 | nop | ||
92 | |||
93 | ll_ip1: | ||
94 | li a0, TX4927_IRQ_USER1 | ||
95 | move a1, sp | ||
96 | jal do_IRQ | ||
97 | j ret_from_irq | ||
98 | |||
99 | ll_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 | ||
9 | obj-y += prom.o setup.o irq.o irq_handler.o rtc_rx5c348.o | 9 | obj-y += prom.o setup.o irq.o rtc_rx5c348.o |
10 | obj-$(CONFIG_KGDB) += dbgio.o | 10 | obj-$(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) | |||
392 | void __init | 392 | void __init |
393 | tx4938_irq_init(void) | 393 | tx4938_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 | |||
423 | asmlinkage 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 | |||
54 | ll_ip7: | ||
55 | li a0, TX4938_IRQ_CPU_TIMER | ||
56 | move a1, sp | ||
57 | jal do_IRQ | ||
58 | j ret_from_irq | ||
59 | |||
60 | |||
61 | ll_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 | |||
71 | goto_spurious_interrupt: | ||
72 | j ret_from_irq | ||
73 | |||
74 | ll_ip1: | ||
75 | li a0, TX4938_IRQ_USER1 | ||
76 | move a1, sp | ||
77 | jal do_IRQ | ||
78 | j ret_from_irq | ||
79 | |||
80 | ll_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 | ||
9 | config IBM_WORKPAD | 11 | config 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 | ||
17 | config NEC_CMBVR4133 | 21 | config 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 | ||
25 | config ROCKHOPPER | 32 | config 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 | ||
70 | config ZAO_CAPCELLA | 81 | config 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 | ||
78 | config PCI_VR41XX | 91 | config 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 | ||
5 | obj-y += bcu.o cmu.o icu.o init.o int-handler.o irq.o pmu.o type.o | 5 | obj-y += bcu.o cmu.o icu.o init.o irq.o pmu.o type.o |
6 | obj-$(CONFIG_VRC4173) += vrc4173.o | 6 | obj-$(CONFIG_VRC4173) += vrc4173.o |
7 | 7 | ||
8 | EXTRA_AFLAGS := $(CFLAGS) | 8 | EXTRA_AFLAGS := $(CFLAGS) |
diff --git a/arch/mips/vr41xx/common/int-handler.S b/arch/mips/vr41xx/common/int-handler.S deleted file mode 100644 index 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 | |||
88 | 1: | ||
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 | |||
104 | handle_int: | ||
105 | jal irq_dispatch | ||
106 | move a1, sp | ||
107 | j ret_from_irq | ||
108 | nop | ||
109 | |||
110 | handle_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 | ||
60 | EXPORT_SYMBOL_GPL(cascade_irq); | 60 | EXPORT_SYMBOL_GPL(cascade_irq); |
61 | 61 | ||
62 | asmlinkage void irq_dispatch(unsigned int irq, struct pt_regs *regs) | 62 | static 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 | ||
87 | extern asmlinkage void vr41xx_handle_interrupt(void); | 87 | asmlinkage 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 | ||
89 | void __init arch_init_irq(void) | 112 | void __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 | } |