diff options
Diffstat (limited to 'arch/sh/kernel/irq.c')
-rw-r--r-- | arch/sh/kernel/irq.c | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 944128ce9706..67be2b6e8cd1 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c | |||
@@ -12,7 +12,7 @@ | |||
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/io.h> | 14 | #include <linux/io.h> |
15 | #include <asm/irq.h> | 15 | #include <linux/irq.h> |
16 | #include <asm/processor.h> | 16 | #include <asm/processor.h> |
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | #include <asm/thread_info.h> | 18 | #include <asm/thread_info.h> |
@@ -78,15 +78,16 @@ union irq_ctx { | |||
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]; | 81 | static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; |
82 | static union irq_ctx *softirq_ctx[NR_CPUS]; | 82 | static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; |
83 | #endif | 83 | #endif |
84 | 84 | ||
85 | asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | 85 | asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, |
86 | unsigned long r6, unsigned long r7, | 86 | unsigned long r6, unsigned long r7, |
87 | struct pt_regs regs) | 87 | struct pt_regs __regs) |
88 | { | 88 | { |
89 | struct pt_regs *old_regs = set_irq_regs(®s); | 89 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
90 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
90 | int irq; | 91 | int irq; |
91 | #ifdef CONFIG_4KSTACKS | 92 | #ifdef CONFIG_4KSTACKS |
92 | union irq_ctx *curctx, *irqctx; | 93 | union irq_ctx *curctx, *irqctx; |
@@ -111,7 +112,7 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | |||
111 | #endif | 112 | #endif |
112 | 113 | ||
113 | #ifdef CONFIG_CPU_HAS_INTEVT | 114 | #ifdef CONFIG_CPU_HAS_INTEVT |
114 | irq = (ctrl_inl(INTEVT) >> 5) - 16; | 115 | irq = evt2irq(ctrl_inl(INTEVT)); |
115 | #else | 116 | #else |
116 | irq = r4; | 117 | irq = r4; |
117 | #endif | 118 | #endif |
@@ -135,17 +136,24 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | |||
135 | irqctx->tinfo.task = curctx->tinfo.task; | 136 | irqctx->tinfo.task = curctx->tinfo.task; |
136 | irqctx->tinfo.previous_sp = current_stack_pointer; | 137 | irqctx->tinfo.previous_sp = current_stack_pointer; |
137 | 138 | ||
139 | /* | ||
140 | * Copy the softirq bits in preempt_count so that the | ||
141 | * softirq checks work in the hardirq context. | ||
142 | */ | ||
143 | irqctx->tinfo.preempt_count = | ||
144 | (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) | | ||
145 | (curctx->tinfo.preempt_count & SOFTIRQ_MASK); | ||
146 | |||
138 | __asm__ __volatile__ ( | 147 | __asm__ __volatile__ ( |
139 | "mov %0, r4 \n" | 148 | "mov %0, r4 \n" |
140 | "mov r15, r9 \n" | 149 | "mov r15, r8 \n" |
141 | "jsr @%1 \n" | 150 | "jsr @%1 \n" |
142 | /* swith to the irq stack */ | 151 | /* swith to the irq stack */ |
143 | " mov %2, r15 \n" | 152 | " mov %2, r15 \n" |
144 | /* restore the stack (ring zero) */ | 153 | /* restore the stack (ring zero) */ |
145 | "mov r9, r15 \n" | 154 | "mov r8, r15 \n" |
146 | : /* no outputs */ | 155 | : /* no outputs */ |
147 | : "r" (irq), "r" (generic_handle_irq), "r" (isp) | 156 | : "r" (irq), "r" (generic_handle_irq), "r" (isp) |
148 | /* XXX: A somewhat excessive clobber list? -PFM */ | ||
149 | : "memory", "r0", "r1", "r2", "r3", "r4", | 157 | : "memory", "r0", "r1", "r2", "r3", "r4", |
150 | "r5", "r6", "r7", "r8", "t", "pr" | 158 | "r5", "r6", "r7", "r8", "t", "pr" |
151 | ); | 159 | ); |
@@ -193,7 +201,7 @@ void irq_ctx_init(int cpu) | |||
193 | irqctx->tinfo.task = NULL; | 201 | irqctx->tinfo.task = NULL; |
194 | irqctx->tinfo.exec_domain = NULL; | 202 | irqctx->tinfo.exec_domain = NULL; |
195 | irqctx->tinfo.cpu = cpu; | 203 | irqctx->tinfo.cpu = cpu; |
196 | irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET; | 204 | irqctx->tinfo.preempt_count = 0; |
197 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); | 205 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); |
198 | 206 | ||
199 | softirq_ctx[cpu] = irqctx; | 207 | softirq_ctx[cpu] = irqctx; |
@@ -239,13 +247,38 @@ asmlinkage void do_softirq(void) | |||
239 | "mov r9, r15 \n" | 247 | "mov r9, r15 \n" |
240 | : /* no outputs */ | 248 | : /* no outputs */ |
241 | : "r" (__do_softirq), "r" (isp) | 249 | : "r" (__do_softirq), "r" (isp) |
242 | /* XXX: A somewhat excessive clobber list? -PFM */ | ||
243 | : "memory", "r0", "r1", "r2", "r3", "r4", | 250 | : "memory", "r0", "r1", "r2", "r3", "r4", |
244 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" | 251 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" |
245 | ); | 252 | ); |
253 | |||
254 | /* | ||
255 | * Shouldnt happen, we returned above if in_interrupt(): | ||
256 | */ | ||
257 | WARN_ON_ONCE(softirq_count()); | ||
246 | } | 258 | } |
247 | 259 | ||
248 | local_irq_restore(flags); | 260 | local_irq_restore(flags); |
249 | } | 261 | } |
250 | EXPORT_SYMBOL(do_softirq); | 262 | EXPORT_SYMBOL(do_softirq); |
251 | #endif | 263 | #endif |
264 | |||
265 | void __init init_IRQ(void) | ||
266 | { | ||
267 | #ifdef CONFIG_CPU_HAS_PINT_IRQ | ||
268 | init_IRQ_pint(); | ||
269 | #endif | ||
270 | |||
271 | #ifdef CONFIG_CPU_HAS_INTC2_IRQ | ||
272 | init_IRQ_intc2(); | ||
273 | #endif | ||
274 | |||
275 | #ifdef CONFIG_CPU_HAS_IPR_IRQ | ||
276 | init_IRQ_ipr(); | ||
277 | #endif | ||
278 | |||
279 | /* Perform the machine specific initialisation */ | ||
280 | if (sh_mv.mv_init_irq) | ||
281 | sh_mv.mv_init_irq(); | ||
282 | |||
283 | irq_ctx_init(smp_processor_id()); | ||
284 | } | ||