Commit 110ed28246a0063a5984d7f72ba5c97f154a51cf
1 parent
0e670685e4
Exists in
master
and in
7 other branches
sh: Decouple 4k and soft/hardirq stacks.
While using separate IRQ stacks can cut down on stack consumption, many users can also use 4k stacks directly without the additional need of separate stacks for soft and hardirqs. With this split, we support the same rationale for 4KSTACKS as m68knommu, with the IRQSTACKS abstraction as per ppc64. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Showing 3 changed files with 13 additions and 5 deletions Inline Diff
arch/sh/Kconfig.debug
1 | menu "Kernel hacking" | 1 | menu "Kernel hacking" |
2 | 2 | ||
3 | config TRACE_IRQFLAGS_SUPPORT | 3 | config TRACE_IRQFLAGS_SUPPORT |
4 | bool | 4 | bool |
5 | default y | 5 | default y |
6 | 6 | ||
7 | source "lib/Kconfig.debug" | 7 | source "lib/Kconfig.debug" |
8 | 8 | ||
9 | config SH_STANDARD_BIOS | 9 | config SH_STANDARD_BIOS |
10 | bool "Use LinuxSH standard BIOS" | 10 | bool "Use LinuxSH standard BIOS" |
11 | help | 11 | help |
12 | Say Y here if your target has the gdb-sh-stub | 12 | Say Y here if your target has the gdb-sh-stub |
13 | package from www.m17n.org (or any conforming standard LinuxSH BIOS) | 13 | package from www.m17n.org (or any conforming standard LinuxSH BIOS) |
14 | in FLASH or EPROM. The kernel will use standard BIOS calls during | 14 | in FLASH or EPROM. The kernel will use standard BIOS calls during |
15 | boot for various housekeeping tasks (including calls to read and | 15 | boot for various housekeeping tasks (including calls to read and |
16 | write characters to a system console, get a MAC address from an | 16 | write characters to a system console, get a MAC address from an |
17 | on-board Ethernet interface, and shut down the hardware). Note this | 17 | on-board Ethernet interface, and shut down the hardware). Note this |
18 | does not work with machines with an existing operating system in | 18 | does not work with machines with an existing operating system in |
19 | mask ROM and no flash (WindowsCE machines fall in this category). | 19 | mask ROM and no flash (WindowsCE machines fall in this category). |
20 | If unsure, say N. | 20 | If unsure, say N. |
21 | 21 | ||
22 | config EARLY_SCIF_CONSOLE | 22 | config EARLY_SCIF_CONSOLE |
23 | bool "Use early SCIF console" | 23 | bool "Use early SCIF console" |
24 | help | 24 | help |
25 | This enables an early console using a fixed SCIF port. This can | 25 | This enables an early console using a fixed SCIF port. This can |
26 | be used by platforms that are either not running the SH | 26 | be used by platforms that are either not running the SH |
27 | standard BIOS, or do not wish to use the BIOS callbacks for the | 27 | standard BIOS, or do not wish to use the BIOS callbacks for the |
28 | serial I/O. | 28 | serial I/O. |
29 | 29 | ||
30 | config EARLY_SCIF_CONSOLE_PORT | 30 | config EARLY_SCIF_CONSOLE_PORT |
31 | hex | 31 | hex |
32 | depends on EARLY_SCIF_CONSOLE | 32 | depends on EARLY_SCIF_CONSOLE |
33 | default "0xffe00000" if CPU_SUBTYPE_SH7780 | 33 | default "0xffe00000" if CPU_SUBTYPE_SH7780 |
34 | default "0xffea0000" if CPU_SUBTYPE_SH7785 | 34 | default "0xffea0000" if CPU_SUBTYPE_SH7785 |
35 | default "0xfffe9800" if CPU_SUBTYPE_SH7206 | 35 | default "0xfffe9800" if CPU_SUBTYPE_SH7206 |
36 | default "0xf8420000" if CPU_SUBTYPE_SH7619 | 36 | default "0xf8420000" if CPU_SUBTYPE_SH7619 |
37 | default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705 | 37 | default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705 |
38 | default "0xa4430000" if CPU_SUBTYPE_SH7720 | 38 | default "0xa4430000" if CPU_SUBTYPE_SH7720 |
39 | default "0xffc30000" if CPU_SUBTYPE_SHX3 | 39 | default "0xffc30000" if CPU_SUBTYPE_SHX3 |
40 | default "0xffe80000" if CPU_SH4 | 40 | default "0xffe80000" if CPU_SH4 |
41 | default "0x00000000" | 41 | default "0x00000000" |
42 | 42 | ||
43 | config EARLY_PRINTK | 43 | config EARLY_PRINTK |
44 | bool "Early printk support" | 44 | bool "Early printk support" |
45 | depends on SH_STANDARD_BIOS || EARLY_SCIF_CONSOLE | 45 | depends on SH_STANDARD_BIOS || EARLY_SCIF_CONSOLE |
46 | help | 46 | help |
47 | Say Y here to redirect kernel printk messages to the serial port | 47 | Say Y here to redirect kernel printk messages to the serial port |
48 | used by the SH-IPL bootloader, starting very early in the boot | 48 | used by the SH-IPL bootloader, starting very early in the boot |
49 | process and ending when the kernel's serial console is initialised. | 49 | process and ending when the kernel's serial console is initialised. |
50 | This option is only useful porting the kernel to a new machine, | 50 | This option is only useful porting the kernel to a new machine, |
51 | when the kernel may crash or hang before the serial console is | 51 | when the kernel may crash or hang before the serial console is |
52 | initialised. If unsure, say N. | 52 | initialised. If unsure, say N. |
53 | 53 | ||
54 | On devices that are running SH-IPL and want to keep the port | 54 | On devices that are running SH-IPL and want to keep the port |
55 | initialization consistent while not using the BIOS callbacks, | 55 | initialization consistent while not using the BIOS callbacks, |
56 | select both the EARLY_SCIF_CONSOLE and SH_STANDARD_BIOS, using | 56 | select both the EARLY_SCIF_CONSOLE and SH_STANDARD_BIOS, using |
57 | the kernel command line option to toggle back and forth. | 57 | the kernel command line option to toggle back and forth. |
58 | 58 | ||
59 | config DEBUG_BOOTMEM | 59 | config DEBUG_BOOTMEM |
60 | depends on DEBUG_KERNEL | 60 | depends on DEBUG_KERNEL |
61 | bool "Debug BOOTMEM initialization" | 61 | bool "Debug BOOTMEM initialization" |
62 | 62 | ||
63 | config DEBUG_STACKOVERFLOW | 63 | config DEBUG_STACKOVERFLOW |
64 | bool "Check for stack overflows" | 64 | bool "Check for stack overflows" |
65 | depends on DEBUG_KERNEL | 65 | depends on DEBUG_KERNEL |
66 | help | 66 | help |
67 | This option will cause messages to be printed if free stack space | 67 | This option will cause messages to be printed if free stack space |
68 | drops below a certain limit. | 68 | drops below a certain limit. |
69 | 69 | ||
70 | config DEBUG_STACK_USAGE | 70 | config DEBUG_STACK_USAGE |
71 | bool "Stack utilization instrumentation" | 71 | bool "Stack utilization instrumentation" |
72 | depends on DEBUG_KERNEL | 72 | depends on DEBUG_KERNEL |
73 | help | 73 | help |
74 | Enables the display of the minimum amount of free stack which each | 74 | Enables the display of the minimum amount of free stack which each |
75 | task has ever had available in the sysrq-T and sysrq-P debug output. | 75 | task has ever had available in the sysrq-T and sysrq-P debug output. |
76 | 76 | ||
77 | This option will slow down process creation somewhat. | 77 | This option will slow down process creation somewhat. |
78 | 78 | ||
79 | config 4KSTACKS | 79 | config 4KSTACKS |
80 | bool "Use 4Kb for kernel stacks instead of 8Kb" | 80 | bool "Use 4Kb for kernel stacks instead of 8Kb" |
81 | depends on DEBUG_KERNEL | 81 | depends on DEBUG_KERNEL |
82 | help | 82 | help |
83 | If you say Y here the kernel will use a 4Kb stacksize for the | 83 | If you say Y here the kernel will use a 4Kb stacksize for the |
84 | kernel stack attached to each process/thread. This facilitates | 84 | kernel stack attached to each process/thread. This facilitates |
85 | running more threads on a system and also reduces the pressure | 85 | running more threads on a system and also reduces the pressure |
86 | on the VM subsystem for higher order allocations. This option | 86 | on the VM subsystem for higher order allocations. This option |
87 | will also use IRQ stacks to compensate for the reduced stackspace. | 87 | will also use IRQ stacks to compensate for the reduced stackspace. |
88 | 88 | ||
89 | config IRQSTACKS | ||
90 | bool "Use separate kernel stacks when processing interrupts" | ||
91 | depends on DEBUG_KERNEL | ||
92 | help | ||
93 | If you say Y here the kernel will use separate kernel stacks | ||
94 | for handling hard and soft interrupts. This can help avoid | ||
95 | overflowing the process kernel stacks. | ||
96 | |||
89 | config SH_KGDB | 97 | config SH_KGDB |
90 | bool "Include KGDB kernel debugger" | 98 | bool "Include KGDB kernel debugger" |
91 | select FRAME_POINTER | 99 | select FRAME_POINTER |
92 | select DEBUG_INFO | 100 | select DEBUG_INFO |
93 | depends on CPU_SH3 || CPU_SH4 | 101 | depends on CPU_SH3 || CPU_SH4 |
94 | help | 102 | help |
95 | Include in-kernel hooks for kgdb, the Linux kernel source level | 103 | Include in-kernel hooks for kgdb, the Linux kernel source level |
96 | debugger. See <http://kgdb.sourceforge.net/> for more information. | 104 | debugger. See <http://kgdb.sourceforge.net/> for more information. |
97 | Unless you are intending to debug the kernel, say N here. | 105 | Unless you are intending to debug the kernel, say N here. |
98 | 106 | ||
99 | menu "KGDB configuration options" | 107 | menu "KGDB configuration options" |
100 | depends on SH_KGDB | 108 | depends on SH_KGDB |
101 | 109 | ||
102 | config MORE_COMPILE_OPTIONS | 110 | config MORE_COMPILE_OPTIONS |
103 | bool "Add any additional compile options" | 111 | bool "Add any additional compile options" |
104 | help | 112 | help |
105 | If you want to add additional CFLAGS to the kernel build, enable this | 113 | If you want to add additional CFLAGS to the kernel build, enable this |
106 | option and then enter what you would like to add in the next question. | 114 | option and then enter what you would like to add in the next question. |
107 | Note however that -g is already appended with the selection of KGDB. | 115 | Note however that -g is already appended with the selection of KGDB. |
108 | 116 | ||
109 | config COMPILE_OPTIONS | 117 | config COMPILE_OPTIONS |
110 | string "Additional compile arguments" | 118 | string "Additional compile arguments" |
111 | depends on MORE_COMPILE_OPTIONS | 119 | depends on MORE_COMPILE_OPTIONS |
112 | 120 | ||
113 | config KGDB_NMI | 121 | config KGDB_NMI |
114 | bool "Enter KGDB on NMI" | 122 | bool "Enter KGDB on NMI" |
115 | default n | 123 | default n |
116 | 124 | ||
117 | config SH_KGDB_CONSOLE | 125 | config SH_KGDB_CONSOLE |
118 | bool "Console messages through GDB" | 126 | bool "Console messages through GDB" |
119 | depends on !SERIAL_SH_SCI_CONSOLE | 127 | depends on !SERIAL_SH_SCI_CONSOLE |
120 | select SERIAL_CORE_CONSOLE | 128 | select SERIAL_CORE_CONSOLE |
121 | default n | 129 | default n |
122 | 130 | ||
123 | config KGDB_SYSRQ | 131 | config KGDB_SYSRQ |
124 | bool "Allow SysRq 'G' to enter KGDB" | 132 | bool "Allow SysRq 'G' to enter KGDB" |
125 | default y | 133 | default y |
126 | 134 | ||
127 | comment "Serial port setup" | 135 | comment "Serial port setup" |
128 | 136 | ||
129 | config KGDB_DEFPORT | 137 | config KGDB_DEFPORT |
130 | int "Port number (ttySCn)" | 138 | int "Port number (ttySCn)" |
131 | default "1" | 139 | default "1" |
132 | 140 | ||
133 | config KGDB_DEFBAUD | 141 | config KGDB_DEFBAUD |
134 | int "Baud rate" | 142 | int "Baud rate" |
135 | default "115200" | 143 | default "115200" |
136 | 144 | ||
137 | choice | 145 | choice |
138 | prompt "Parity" | 146 | prompt "Parity" |
139 | depends on SH_KGDB | 147 | depends on SH_KGDB |
140 | default KGDB_DEFPARITY_N | 148 | default KGDB_DEFPARITY_N |
141 | 149 | ||
142 | config KGDB_DEFPARITY_N | 150 | config KGDB_DEFPARITY_N |
143 | bool "None" | 151 | bool "None" |
144 | 152 | ||
145 | config KGDB_DEFPARITY_E | 153 | config KGDB_DEFPARITY_E |
146 | bool "Even" | 154 | bool "Even" |
147 | 155 | ||
148 | config KGDB_DEFPARITY_O | 156 | config KGDB_DEFPARITY_O |
149 | bool "Odd" | 157 | bool "Odd" |
150 | 158 | ||
151 | endchoice | 159 | endchoice |
152 | 160 | ||
153 | choice | 161 | choice |
154 | prompt "Data bits" | 162 | prompt "Data bits" |
155 | depends on SH_KGDB | 163 | depends on SH_KGDB |
156 | default KGDB_DEFBITS_8 | 164 | default KGDB_DEFBITS_8 |
157 | 165 | ||
158 | config KGDB_DEFBITS_8 | 166 | config KGDB_DEFBITS_8 |
159 | bool "8" | 167 | bool "8" |
160 | 168 | ||
161 | config KGDB_DEFBITS_7 | 169 | config KGDB_DEFBITS_7 |
162 | bool "7" | 170 | bool "7" |
163 | 171 | ||
164 | endchoice | 172 | endchoice |
165 | 173 | ||
166 | endmenu | 174 | endmenu |
167 | 175 | ||
168 | endmenu | 176 | endmenu |
169 | 177 |
arch/sh/kernel/irq.c
1 | /* | 1 | /* |
2 | * linux/arch/sh/kernel/irq.c | 2 | * linux/arch/sh/kernel/irq.c |
3 | * | 3 | * |
4 | * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar | 4 | * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * SuperH version: Copyright (C) 1999 Niibe Yutaka | 7 | * SuperH version: Copyright (C) 1999 Niibe Yutaka |
8 | */ | 8 | */ |
9 | #include <linux/irq.h> | 9 | #include <linux/irq.h> |
10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/kernel_stat.h> | 12 | #include <linux/kernel_stat.h> |
13 | #include <linux/seq_file.h> | 13 | #include <linux/seq_file.h> |
14 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
15 | #include <asm/processor.h> | 15 | #include <asm/processor.h> |
16 | #include <asm/machvec.h> | 16 | #include <asm/machvec.h> |
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | #include <asm/thread_info.h> | 18 | #include <asm/thread_info.h> |
19 | #include <asm/cpu/mmu_context.h> | 19 | #include <asm/cpu/mmu_context.h> |
20 | 20 | ||
21 | atomic_t irq_err_count; | 21 | atomic_t irq_err_count; |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * 'what should we do if we get a hw irq event on an illegal vector'. | 24 | * 'what should we do if we get a hw irq event on an illegal vector'. |
25 | * each architecture has to answer this themselves, it doesn't deserve | 25 | * each architecture has to answer this themselves, it doesn't deserve |
26 | * a generic callback i think. | 26 | * a generic callback i think. |
27 | */ | 27 | */ |
28 | void ack_bad_irq(unsigned int irq) | 28 | void ack_bad_irq(unsigned int irq) |
29 | { | 29 | { |
30 | atomic_inc(&irq_err_count); | 30 | atomic_inc(&irq_err_count); |
31 | printk("unexpected IRQ trap at vector %02x\n", irq); | 31 | printk("unexpected IRQ trap at vector %02x\n", irq); |
32 | } | 32 | } |
33 | 33 | ||
34 | #if defined(CONFIG_PROC_FS) | 34 | #if defined(CONFIG_PROC_FS) |
35 | int show_interrupts(struct seq_file *p, void *v) | 35 | int show_interrupts(struct seq_file *p, void *v) |
36 | { | 36 | { |
37 | int i = *(loff_t *) v, j; | 37 | int i = *(loff_t *) v, j; |
38 | struct irqaction * action; | 38 | struct irqaction * action; |
39 | unsigned long flags; | 39 | unsigned long flags; |
40 | 40 | ||
41 | if (i == 0) { | 41 | if (i == 0) { |
42 | seq_puts(p, " "); | 42 | seq_puts(p, " "); |
43 | for_each_online_cpu(j) | 43 | for_each_online_cpu(j) |
44 | seq_printf(p, "CPU%d ",j); | 44 | seq_printf(p, "CPU%d ",j); |
45 | seq_putc(p, '\n'); | 45 | seq_putc(p, '\n'); |
46 | } | 46 | } |
47 | 47 | ||
48 | if (i < sh_mv.mv_nr_irqs) { | 48 | if (i < sh_mv.mv_nr_irqs) { |
49 | spin_lock_irqsave(&irq_desc[i].lock, flags); | 49 | spin_lock_irqsave(&irq_desc[i].lock, flags); |
50 | action = irq_desc[i].action; | 50 | action = irq_desc[i].action; |
51 | if (!action) | 51 | if (!action) |
52 | goto unlock; | 52 | goto unlock; |
53 | seq_printf(p, "%3d: ",i); | 53 | seq_printf(p, "%3d: ",i); |
54 | for_each_online_cpu(j) | 54 | for_each_online_cpu(j) |
55 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | 55 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); |
56 | seq_printf(p, " %14s", irq_desc[i].chip->name); | 56 | seq_printf(p, " %14s", irq_desc[i].chip->name); |
57 | seq_printf(p, "-%-8s", irq_desc[i].name); | 57 | seq_printf(p, "-%-8s", irq_desc[i].name); |
58 | seq_printf(p, " %s", action->name); | 58 | seq_printf(p, " %s", action->name); |
59 | 59 | ||
60 | for (action=action->next; action; action = action->next) | 60 | for (action=action->next; action; action = action->next) |
61 | seq_printf(p, ", %s", action->name); | 61 | seq_printf(p, ", %s", action->name); |
62 | seq_putc(p, '\n'); | 62 | seq_putc(p, '\n'); |
63 | unlock: | 63 | unlock: |
64 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); | 64 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); |
65 | } else if (i == sh_mv.mv_nr_irqs) | 65 | } else if (i == sh_mv.mv_nr_irqs) |
66 | seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count)); | 66 | seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count)); |
67 | 67 | ||
68 | return 0; | 68 | return 0; |
69 | } | 69 | } |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | #ifdef CONFIG_4KSTACKS | 72 | #ifdef CONFIG_IRQSTACKS |
73 | /* | 73 | /* |
74 | * per-CPU IRQ handling contexts (thread information and stack) | 74 | * per-CPU IRQ handling contexts (thread information and stack) |
75 | */ | 75 | */ |
76 | union irq_ctx { | 76 | union irq_ctx { |
77 | struct thread_info tinfo; | 77 | struct thread_info tinfo; |
78 | u32 stack[THREAD_SIZE/sizeof(u32)]; | 78 | u32 stack[THREAD_SIZE/sizeof(u32)]; |
79 | }; | 79 | }; |
80 | 80 | ||
81 | static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; | 81 | static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; |
82 | static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; | 82 | static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; |
83 | #endif | 83 | #endif |
84 | 84 | ||
85 | asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs) | 85 | asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs) |
86 | { | 86 | { |
87 | struct pt_regs *old_regs = set_irq_regs(regs); | 87 | struct pt_regs *old_regs = set_irq_regs(regs); |
88 | #ifdef CONFIG_4KSTACKS | 88 | #ifdef CONFIG_IRQSTACKS |
89 | union irq_ctx *curctx, *irqctx; | 89 | union irq_ctx *curctx, *irqctx; |
90 | #endif | 90 | #endif |
91 | 91 | ||
92 | irq_enter(); | 92 | irq_enter(); |
93 | 93 | ||
94 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | 94 | #ifdef CONFIG_DEBUG_STACKOVERFLOW |
95 | /* Debugging check for stack overflow: is there less than 1KB free? */ | 95 | /* Debugging check for stack overflow: is there less than 1KB free? */ |
96 | { | 96 | { |
97 | long sp; | 97 | long sp; |
98 | 98 | ||
99 | __asm__ __volatile__ ("and r15, %0" : | 99 | __asm__ __volatile__ ("and r15, %0" : |
100 | "=r" (sp) : "0" (THREAD_SIZE - 1)); | 100 | "=r" (sp) : "0" (THREAD_SIZE - 1)); |
101 | 101 | ||
102 | if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { | 102 | if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { |
103 | printk("do_IRQ: stack overflow: %ld\n", | 103 | printk("do_IRQ: stack overflow: %ld\n", |
104 | sp - sizeof(struct thread_info)); | 104 | sp - sizeof(struct thread_info)); |
105 | dump_stack(); | 105 | dump_stack(); |
106 | } | 106 | } |
107 | } | 107 | } |
108 | #endif | 108 | #endif |
109 | 109 | ||
110 | irq = irq_demux(evt2irq(irq)); | 110 | irq = irq_demux(evt2irq(irq)); |
111 | 111 | ||
112 | #ifdef CONFIG_4KSTACKS | 112 | #ifdef CONFIG_IRQSTACKS |
113 | curctx = (union irq_ctx *)current_thread_info(); | 113 | curctx = (union irq_ctx *)current_thread_info(); |
114 | irqctx = hardirq_ctx[smp_processor_id()]; | 114 | irqctx = hardirq_ctx[smp_processor_id()]; |
115 | 115 | ||
116 | /* | 116 | /* |
117 | * this is where we switch to the IRQ stack. However, if we are | 117 | * this is where we switch to the IRQ stack. However, if we are |
118 | * already using the IRQ stack (because we interrupted a hardirq | 118 | * already using the IRQ stack (because we interrupted a hardirq |
119 | * handler) we can't do that and just have to keep using the | 119 | * handler) we can't do that and just have to keep using the |
120 | * current stack (which is the irq stack already after all) | 120 | * current stack (which is the irq stack already after all) |
121 | */ | 121 | */ |
122 | if (curctx != irqctx) { | 122 | if (curctx != irqctx) { |
123 | u32 *isp; | 123 | u32 *isp; |
124 | 124 | ||
125 | isp = (u32 *)((char *)irqctx + sizeof(*irqctx)); | 125 | isp = (u32 *)((char *)irqctx + sizeof(*irqctx)); |
126 | irqctx->tinfo.task = curctx->tinfo.task; | 126 | irqctx->tinfo.task = curctx->tinfo.task; |
127 | irqctx->tinfo.previous_sp = current_stack_pointer; | 127 | irqctx->tinfo.previous_sp = current_stack_pointer; |
128 | 128 | ||
129 | /* | 129 | /* |
130 | * Copy the softirq bits in preempt_count so that the | 130 | * Copy the softirq bits in preempt_count so that the |
131 | * softirq checks work in the hardirq context. | 131 | * softirq checks work in the hardirq context. |
132 | */ | 132 | */ |
133 | irqctx->tinfo.preempt_count = | 133 | irqctx->tinfo.preempt_count = |
134 | (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) | | 134 | (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) | |
135 | (curctx->tinfo.preempt_count & SOFTIRQ_MASK); | 135 | (curctx->tinfo.preempt_count & SOFTIRQ_MASK); |
136 | 136 | ||
137 | __asm__ __volatile__ ( | 137 | __asm__ __volatile__ ( |
138 | "mov %0, r4 \n" | 138 | "mov %0, r4 \n" |
139 | "mov r15, r8 \n" | 139 | "mov r15, r8 \n" |
140 | "jsr @%1 \n" | 140 | "jsr @%1 \n" |
141 | /* swith to the irq stack */ | 141 | /* swith to the irq stack */ |
142 | " mov %2, r15 \n" | 142 | " mov %2, r15 \n" |
143 | /* restore the stack (ring zero) */ | 143 | /* restore the stack (ring zero) */ |
144 | "mov r8, r15 \n" | 144 | "mov r8, r15 \n" |
145 | : /* no outputs */ | 145 | : /* no outputs */ |
146 | : "r" (irq), "r" (generic_handle_irq), "r" (isp) | 146 | : "r" (irq), "r" (generic_handle_irq), "r" (isp) |
147 | : "memory", "r0", "r1", "r2", "r3", "r4", | 147 | : "memory", "r0", "r1", "r2", "r3", "r4", |
148 | "r5", "r6", "r7", "r8", "t", "pr" | 148 | "r5", "r6", "r7", "r8", "t", "pr" |
149 | ); | 149 | ); |
150 | } else | 150 | } else |
151 | #endif | 151 | #endif |
152 | generic_handle_irq(irq); | 152 | generic_handle_irq(irq); |
153 | 153 | ||
154 | irq_exit(); | 154 | irq_exit(); |
155 | 155 | ||
156 | set_irq_regs(old_regs); | 156 | set_irq_regs(old_regs); |
157 | return 1; | 157 | return 1; |
158 | } | 158 | } |
159 | 159 | ||
160 | #ifdef CONFIG_4KSTACKS | 160 | #ifdef CONFIG_IRQSTACKS |
161 | static char softirq_stack[NR_CPUS * THREAD_SIZE] | 161 | static char softirq_stack[NR_CPUS * THREAD_SIZE] |
162 | __attribute__((__section__(".bss.page_aligned"))); | 162 | __attribute__((__section__(".bss.page_aligned"))); |
163 | 163 | ||
164 | static char hardirq_stack[NR_CPUS * THREAD_SIZE] | 164 | static char hardirq_stack[NR_CPUS * THREAD_SIZE] |
165 | __attribute__((__section__(".bss.page_aligned"))); | 165 | __attribute__((__section__(".bss.page_aligned"))); |
166 | 166 | ||
167 | /* | 167 | /* |
168 | * allocate per-cpu stacks for hardirq and for softirq processing | 168 | * allocate per-cpu stacks for hardirq and for softirq processing |
169 | */ | 169 | */ |
170 | void irq_ctx_init(int cpu) | 170 | void irq_ctx_init(int cpu) |
171 | { | 171 | { |
172 | union irq_ctx *irqctx; | 172 | union irq_ctx *irqctx; |
173 | 173 | ||
174 | if (hardirq_ctx[cpu]) | 174 | if (hardirq_ctx[cpu]) |
175 | return; | 175 | return; |
176 | 176 | ||
177 | irqctx = (union irq_ctx *)&hardirq_stack[cpu * THREAD_SIZE]; | 177 | irqctx = (union irq_ctx *)&hardirq_stack[cpu * THREAD_SIZE]; |
178 | irqctx->tinfo.task = NULL; | 178 | irqctx->tinfo.task = NULL; |
179 | irqctx->tinfo.exec_domain = NULL; | 179 | irqctx->tinfo.exec_domain = NULL; |
180 | irqctx->tinfo.cpu = cpu; | 180 | irqctx->tinfo.cpu = cpu; |
181 | irqctx->tinfo.preempt_count = HARDIRQ_OFFSET; | 181 | irqctx->tinfo.preempt_count = HARDIRQ_OFFSET; |
182 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); | 182 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); |
183 | 183 | ||
184 | hardirq_ctx[cpu] = irqctx; | 184 | hardirq_ctx[cpu] = irqctx; |
185 | 185 | ||
186 | irqctx = (union irq_ctx *)&softirq_stack[cpu * THREAD_SIZE]; | 186 | irqctx = (union irq_ctx *)&softirq_stack[cpu * THREAD_SIZE]; |
187 | irqctx->tinfo.task = NULL; | 187 | irqctx->tinfo.task = NULL; |
188 | irqctx->tinfo.exec_domain = NULL; | 188 | irqctx->tinfo.exec_domain = NULL; |
189 | irqctx->tinfo.cpu = cpu; | 189 | irqctx->tinfo.cpu = cpu; |
190 | irqctx->tinfo.preempt_count = 0; | 190 | irqctx->tinfo.preempt_count = 0; |
191 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); | 191 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); |
192 | 192 | ||
193 | softirq_ctx[cpu] = irqctx; | 193 | softirq_ctx[cpu] = irqctx; |
194 | 194 | ||
195 | printk("CPU %u irqstacks, hard=%p soft=%p\n", | 195 | printk("CPU %u irqstacks, hard=%p soft=%p\n", |
196 | cpu, hardirq_ctx[cpu], softirq_ctx[cpu]); | 196 | cpu, hardirq_ctx[cpu], softirq_ctx[cpu]); |
197 | } | 197 | } |
198 | 198 | ||
199 | void irq_ctx_exit(int cpu) | 199 | void irq_ctx_exit(int cpu) |
200 | { | 200 | { |
201 | hardirq_ctx[cpu] = NULL; | 201 | hardirq_ctx[cpu] = NULL; |
202 | } | 202 | } |
203 | 203 | ||
204 | extern asmlinkage void __do_softirq(void); | 204 | extern asmlinkage void __do_softirq(void); |
205 | 205 | ||
206 | asmlinkage void do_softirq(void) | 206 | asmlinkage void do_softirq(void) |
207 | { | 207 | { |
208 | unsigned long flags; | 208 | unsigned long flags; |
209 | struct thread_info *curctx; | 209 | struct thread_info *curctx; |
210 | union irq_ctx *irqctx; | 210 | union irq_ctx *irqctx; |
211 | u32 *isp; | 211 | u32 *isp; |
212 | 212 | ||
213 | if (in_interrupt()) | 213 | if (in_interrupt()) |
214 | return; | 214 | return; |
215 | 215 | ||
216 | local_irq_save(flags); | 216 | local_irq_save(flags); |
217 | 217 | ||
218 | if (local_softirq_pending()) { | 218 | if (local_softirq_pending()) { |
219 | curctx = current_thread_info(); | 219 | curctx = current_thread_info(); |
220 | irqctx = softirq_ctx[smp_processor_id()]; | 220 | irqctx = softirq_ctx[smp_processor_id()]; |
221 | irqctx->tinfo.task = curctx->task; | 221 | irqctx->tinfo.task = curctx->task; |
222 | irqctx->tinfo.previous_sp = current_stack_pointer; | 222 | irqctx->tinfo.previous_sp = current_stack_pointer; |
223 | 223 | ||
224 | /* build the stack frame on the softirq stack */ | 224 | /* build the stack frame on the softirq stack */ |
225 | isp = (u32 *)((char *)irqctx + sizeof(*irqctx)); | 225 | isp = (u32 *)((char *)irqctx + sizeof(*irqctx)); |
226 | 226 | ||
227 | __asm__ __volatile__ ( | 227 | __asm__ __volatile__ ( |
228 | "mov r15, r9 \n" | 228 | "mov r15, r9 \n" |
229 | "jsr @%0 \n" | 229 | "jsr @%0 \n" |
230 | /* switch to the softirq stack */ | 230 | /* switch to the softirq stack */ |
231 | " mov %1, r15 \n" | 231 | " mov %1, r15 \n" |
232 | /* restore the thread stack */ | 232 | /* restore the thread stack */ |
233 | "mov r9, r15 \n" | 233 | "mov r9, r15 \n" |
234 | : /* no outputs */ | 234 | : /* no outputs */ |
235 | : "r" (__do_softirq), "r" (isp) | 235 | : "r" (__do_softirq), "r" (isp) |
236 | : "memory", "r0", "r1", "r2", "r3", "r4", | 236 | : "memory", "r0", "r1", "r2", "r3", "r4", |
237 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" | 237 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" |
238 | ); | 238 | ); |
239 | 239 | ||
240 | /* | 240 | /* |
241 | * Shouldnt happen, we returned above if in_interrupt(): | 241 | * Shouldnt happen, we returned above if in_interrupt(): |
242 | */ | 242 | */ |
243 | WARN_ON_ONCE(softirq_count()); | 243 | WARN_ON_ONCE(softirq_count()); |
244 | } | 244 | } |
245 | 245 | ||
246 | local_irq_restore(flags); | 246 | local_irq_restore(flags); |
247 | } | 247 | } |
248 | #endif | 248 | #endif |
249 | 249 | ||
250 | void __init init_IRQ(void) | 250 | void __init init_IRQ(void) |
251 | { | 251 | { |
252 | #ifdef CONFIG_CPU_HAS_PINT_IRQ | 252 | #ifdef CONFIG_CPU_HAS_PINT_IRQ |
253 | init_IRQ_pint(); | 253 | init_IRQ_pint(); |
254 | #endif | 254 | #endif |
255 | plat_irq_setup(); | 255 | plat_irq_setup(); |
256 | 256 | ||
257 | /* Perform the machine specific initialisation */ | 257 | /* Perform the machine specific initialisation */ |
258 | if (sh_mv.mv_init_irq) | 258 | if (sh_mv.mv_init_irq) |
259 | sh_mv.mv_init_irq(); | 259 | sh_mv.mv_init_irq(); |
260 | 260 | ||
261 | irq_ctx_init(smp_processor_id()); | 261 | irq_ctx_init(smp_processor_id()); |
262 | } | 262 | } |
263 | 263 |
include/asm-sh/irq.h
1 | #ifndef __ASM_SH_IRQ_H | 1 | #ifndef __ASM_SH_IRQ_H |
2 | #define __ASM_SH_IRQ_H | 2 | #define __ASM_SH_IRQ_H |
3 | 3 | ||
4 | #include <asm/machvec.h> | 4 | #include <asm/machvec.h> |
5 | 5 | ||
6 | /* | 6 | /* |
7 | * A sane default based on a reasonable vector table size, platforms are | 7 | * A sane default based on a reasonable vector table size, platforms are |
8 | * advised to cap this at the hard limit that they're interested in | 8 | * advised to cap this at the hard limit that they're interested in |
9 | * through the machvec. | 9 | * through the machvec. |
10 | */ | 10 | */ |
11 | #define NR_IRQS 256 | 11 | #define NR_IRQS 256 |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * Convert back and forth between INTEVT and IRQ values. | 14 | * Convert back and forth between INTEVT and IRQ values. |
15 | */ | 15 | */ |
16 | #ifdef CONFIG_CPU_HAS_INTEVT | 16 | #ifdef CONFIG_CPU_HAS_INTEVT |
17 | #define evt2irq(evt) (((evt) >> 5) - 16) | 17 | #define evt2irq(evt) (((evt) >> 5) - 16) |
18 | #define irq2evt(irq) (((irq) + 16) << 5) | 18 | #define irq2evt(irq) (((irq) + 16) << 5) |
19 | #else | 19 | #else |
20 | #define evt2irq(evt) (evt) | 20 | #define evt2irq(evt) (evt) |
21 | #define irq2evt(irq) (irq) | 21 | #define irq2evt(irq) (irq) |
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Simple Mask Register Support | 25 | * Simple Mask Register Support |
26 | */ | 26 | */ |
27 | extern void make_maskreg_irq(unsigned int irq); | 27 | extern void make_maskreg_irq(unsigned int irq); |
28 | extern unsigned short *irq_mask_register; | 28 | extern unsigned short *irq_mask_register; |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * PINT IRQs | 31 | * PINT IRQs |
32 | */ | 32 | */ |
33 | void init_IRQ_pint(void); | 33 | void init_IRQ_pint(void); |
34 | void make_imask_irq(unsigned int irq); | 34 | void make_imask_irq(unsigned int irq); |
35 | 35 | ||
36 | static inline int generic_irq_demux(int irq) | 36 | static inline int generic_irq_demux(int irq) |
37 | { | 37 | { |
38 | return irq; | 38 | return irq; |
39 | } | 39 | } |
40 | 40 | ||
41 | #define irq_canonicalize(irq) (irq) | 41 | #define irq_canonicalize(irq) (irq) |
42 | #define irq_demux(irq) sh_mv.mv_irq_demux(irq) | 42 | #define irq_demux(irq) sh_mv.mv_irq_demux(irq) |
43 | 43 | ||
44 | #ifdef CONFIG_4KSTACKS | 44 | #ifdef CONFIG_IRQSTACKS |
45 | extern void irq_ctx_init(int cpu); | 45 | extern void irq_ctx_init(int cpu); |
46 | extern void irq_ctx_exit(int cpu); | 46 | extern void irq_ctx_exit(int cpu); |
47 | # define __ARCH_HAS_DO_SOFTIRQ | 47 | # define __ARCH_HAS_DO_SOFTIRQ |
48 | #else | 48 | #else |
49 | # define irq_ctx_init(cpu) do { } while (0) | 49 | # define irq_ctx_init(cpu) do { } while (0) |
50 | # define irq_ctx_exit(cpu) do { } while (0) | 50 | # define irq_ctx_exit(cpu) do { } while (0) |
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | #endif /* __ASM_SH_IRQ_H */ | 53 | #endif /* __ASM_SH_IRQ_H */ |
54 | 54 |