diff options
author | Marc Gauthier <marc@tensilica.com> | 2013-01-04 19:57:17 -0500 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2013-02-23 22:12:52 -0500 |
commit | 2d1c645cc50b8f5a718b24bad9eb3931e7105d12 (patch) | |
tree | c385e5064cee10f79b9c359ddd99bd5d1b9f838a /arch/xtensa | |
parent | d0b73b488c55df905ea8faaad079f8535629ed26 (diff) |
xtensa: dispatch medium-priority interrupts
Add support for dispatching medium-priority interrupts, that is,
interrupts of priority levels 2 to EXCM_LEVEL. IRQ handling may be
preempted by higher priority IRQ.
Signed-off-by: Marc Gauthier <marc@tensilica.com>
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Chris Zankel <chris@zankel.net>
Diffstat (limited to 'arch/xtensa')
-rw-r--r-- | arch/xtensa/include/asm/atomic.h | 6 | ||||
-rw-r--r-- | arch/xtensa/include/asm/processor.h | 4 | ||||
-rw-r--r-- | arch/xtensa/include/asm/regs.h | 1 | ||||
-rw-r--r-- | arch/xtensa/include/asm/timex.h | 8 | ||||
-rw-r--r-- | arch/xtensa/kernel/entry.S | 55 | ||||
-rw-r--r-- | arch/xtensa/kernel/head.S | 9 | ||||
-rw-r--r-- | arch/xtensa/kernel/setup.c | 42 | ||||
-rw-r--r-- | arch/xtensa/kernel/traps.c | 55 | ||||
-rw-r--r-- | arch/xtensa/kernel/vectors.S | 57 | ||||
-rw-r--r-- | arch/xtensa/kernel/vmlinux.lds.S | 68 |
10 files changed, 260 insertions, 45 deletions
diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index c3f289174c10..e7fb447bce8e 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h | |||
@@ -7,7 +7,7 @@ | |||
7 | * License. See the file "COPYING" in the main directory of this archive | 7 | * License. See the file "COPYING" in the main directory of this archive |
8 | * for more details. | 8 | * for more details. |
9 | * | 9 | * |
10 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 10 | * Copyright (C) 2001 - 2008 Tensilica Inc. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef _XTENSA_ATOMIC_H | 13 | #ifndef _XTENSA_ATOMIC_H |
@@ -24,11 +24,11 @@ | |||
24 | 24 | ||
25 | /* | 25 | /* |
26 | * This Xtensa implementation assumes that the right mechanism | 26 | * This Xtensa implementation assumes that the right mechanism |
27 | * for exclusion is for locking interrupts to level 1. | 27 | * for exclusion is for locking interrupts to level EXCM_LEVEL. |
28 | * | 28 | * |
29 | * Locking interrupts looks like this: | 29 | * Locking interrupts looks like this: |
30 | * | 30 | * |
31 | * rsil a15, 1 | 31 | * rsil a15, LOCKLEVEL |
32 | * <code> | 32 | * <code> |
33 | * wsr a15, PS | 33 | * wsr a15, PS |
34 | * rsync | 34 | * rsync |
diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h index e5fb6b0abdf4..7e409a5b0ec5 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * License. See the file "COPYING" in the main directory of this archive | 5 | * License. See the file "COPYING" in the main directory of this archive |
6 | * for more details. | 6 | * for more details. |
7 | * | 7 | * |
8 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 8 | * Copyright (C) 2001 - 2008 Tensilica Inc. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #ifndef _XTENSA_PROCESSOR_H | 11 | #ifndef _XTENSA_PROCESSOR_H |
@@ -68,7 +68,7 @@ | |||
68 | /* LOCKLEVEL defines the interrupt level that masks all | 68 | /* LOCKLEVEL defines the interrupt level that masks all |
69 | * general-purpose interrupts. | 69 | * general-purpose interrupts. |
70 | */ | 70 | */ |
71 | #define LOCKLEVEL 1 | 71 | #define LOCKLEVEL XCHAL_EXCM_LEVEL |
72 | 72 | ||
73 | /* WSBITS and WBBITS are the width of the WINDOWSTART and WINDOWBASE | 73 | /* WSBITS and WBBITS are the width of the WINDOWSTART and WINDOWBASE |
74 | * registers | 74 | * registers |
diff --git a/arch/xtensa/include/asm/regs.h b/arch/xtensa/include/asm/regs.h index 76096a4e5b8d..b24de6717020 100644 --- a/arch/xtensa/include/asm/regs.h +++ b/arch/xtensa/include/asm/regs.h | |||
@@ -88,6 +88,7 @@ | |||
88 | #define PS_UM_BIT 5 | 88 | #define PS_UM_BIT 5 |
89 | #define PS_EXCM_BIT 4 | 89 | #define PS_EXCM_BIT 4 |
90 | #define PS_INTLEVEL_SHIFT 0 | 90 | #define PS_INTLEVEL_SHIFT 0 |
91 | #define PS_INTLEVEL_WIDTH 4 | ||
91 | #define PS_INTLEVEL_MASK 0x0000000F | 92 | #define PS_INTLEVEL_MASK 0x0000000F |
92 | 93 | ||
93 | /* DBREAKCn register fields. */ | 94 | /* DBREAKCn register fields. */ |
diff --git a/arch/xtensa/include/asm/timex.h b/arch/xtensa/include/asm/timex.h index 175b3d5e1b01..9e85ce8bd8dd 100644 --- a/arch/xtensa/include/asm/timex.h +++ b/arch/xtensa/include/asm/timex.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * License. See the file "COPYING" in the main directory of this archive | 5 | * License. See the file "COPYING" in the main directory of this archive |
6 | * for more details. | 6 | * for more details. |
7 | * | 7 | * |
8 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 8 | * Copyright (C) 2001 - 2008 Tensilica Inc. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #ifndef _XTENSA_TIMEX_H | 11 | #ifndef _XTENSA_TIMEX_H |
@@ -19,13 +19,13 @@ | |||
19 | #define _INTLEVEL(x) XCHAL_INT ## x ## _LEVEL | 19 | #define _INTLEVEL(x) XCHAL_INT ## x ## _LEVEL |
20 | #define INTLEVEL(x) _INTLEVEL(x) | 20 | #define INTLEVEL(x) _INTLEVEL(x) |
21 | 21 | ||
22 | #if INTLEVEL(XCHAL_TIMER0_INTERRUPT) == 1 | 22 | #if INTLEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL |
23 | # define LINUX_TIMER 0 | 23 | # define LINUX_TIMER 0 |
24 | # define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT | 24 | # define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT |
25 | #elif INTLEVEL(XCHAL_TIMER1_INTERRUPT) == 1 | 25 | #elif INTLEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL |
26 | # define LINUX_TIMER 1 | 26 | # define LINUX_TIMER 1 |
27 | # define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT | 27 | # define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT |
28 | #elif INTLEVEL(XCHAL_TIMER2_INTERRUPT) == 1 | 28 | #elif INTLEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL |
29 | # define LINUX_TIMER 2 | 29 | # define LINUX_TIMER 2 |
30 | # define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT | 30 | # define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT |
31 | #else | 31 | #else |
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 3777fec85e7c..0ace2acbbad0 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S | |||
@@ -7,7 +7,7 @@ | |||
7 | * License. See the file "COPYING" in the main directory of this archive | 7 | * License. See the file "COPYING" in the main directory of this archive |
8 | * for more details. | 8 | * for more details. |
9 | * | 9 | * |
10 | * Copyright (C) 2004-2007 by Tensilica Inc. | 10 | * Copyright (C) 2004 - 2008 by Tensilica Inc. |
11 | * | 11 | * |
12 | * Chris Zankel <chris@zankel.net> | 12 | * Chris Zankel <chris@zankel.net> |
13 | * | 13 | * |
@@ -349,15 +349,16 @@ common_exception: | |||
349 | * so we can allow exceptions and interrupts (*) again. | 349 | * so we can allow exceptions and interrupts (*) again. |
350 | * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) | 350 | * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) |
351 | * | 351 | * |
352 | * (*) We only allow interrupts if PS.INTLEVEL was not set to 1 before | 352 | * (*) We only allow interrupts of higher priority than current IRQ |
353 | * (interrupts disabled) and if this exception is not an interrupt. | ||
354 | */ | 353 | */ |
355 | 354 | ||
356 | rsr a3, ps | 355 | rsr a3, ps |
357 | addi a0, a0, -4 | 356 | addi a0, a0, -4 |
358 | movi a2, 1 | 357 | movi a2, 1 |
359 | extui a3, a3, 0, 1 # a3 = PS.INTLEVEL[0] | 358 | extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH |
360 | moveqz a3, a2, a0 # a3 = 1 iff interrupt exception | 359 | # a3 = PS.INTLEVEL |
360 | movnez a2, a3, a3 # a2 = 1: level-1, > 1: high priority | ||
361 | moveqz a3, a2, a0 # a3 = IRQ level iff interrupt | ||
361 | movi a2, 1 << PS_WOE_BIT | 362 | movi a2, 1 << PS_WOE_BIT |
362 | or a3, a3, a2 | 363 | or a3, a3, a2 |
363 | rsr a0, exccause | 364 | rsr a0, exccause |
@@ -641,19 +642,51 @@ common_exception_exit: | |||
641 | 642 | ||
642 | l32i a0, a1, PT_DEPC | 643 | l32i a0, a1, PT_DEPC |
643 | l32i a3, a1, PT_AREG3 | 644 | l32i a3, a1, PT_AREG3 |
645 | _bltui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f | ||
646 | |||
647 | wsr a0, depc | ||
644 | l32i a2, a1, PT_AREG2 | 648 | l32i a2, a1, PT_AREG2 |
645 | _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f | 649 | l32i a0, a1, PT_AREG0 |
650 | l32i a1, a1, PT_AREG1 | ||
651 | rfde | ||
646 | 652 | ||
653 | 1: | ||
647 | /* Restore a0...a3 and return */ | 654 | /* Restore a0...a3 and return */ |
648 | 655 | ||
656 | rsr a0, ps | ||
657 | extui a2, a0, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH | ||
658 | movi a0, 2f | ||
659 | slli a2, a2, 4 | ||
660 | add a0, a2, a0 | ||
661 | l32i a2, a1, PT_AREG2 | ||
662 | jx a0 | ||
663 | |||
664 | .macro irq_exit_level level | ||
665 | .align 16 | ||
666 | .if XCHAL_EXCM_LEVEL >= \level | ||
667 | l32i a0, a1, PT_PC | ||
668 | wsr a0, epc\level | ||
649 | l32i a0, a1, PT_AREG0 | 669 | l32i a0, a1, PT_AREG0 |
650 | l32i a1, a1, PT_AREG1 | 670 | l32i a1, a1, PT_AREG1 |
651 | rfe | 671 | rfi \level |
672 | .endif | ||
673 | .endm | ||
652 | 674 | ||
653 | 1: wsr a0, depc | 675 | .align 16 |
676 | 2: | ||
654 | l32i a0, a1, PT_AREG0 | 677 | l32i a0, a1, PT_AREG0 |
655 | l32i a1, a1, PT_AREG1 | 678 | l32i a1, a1, PT_AREG1 |
656 | rfde | 679 | rfe |
680 | |||
681 | .align 16 | ||
682 | /* no rfi for level-1 irq, handled by rfe above*/ | ||
683 | nop | ||
684 | |||
685 | irq_exit_level 2 | ||
686 | irq_exit_level 3 | ||
687 | irq_exit_level 4 | ||
688 | irq_exit_level 5 | ||
689 | irq_exit_level 6 | ||
657 | 690 | ||
658 | ENDPROC(kernel_exception) | 691 | ENDPROC(kernel_exception) |
659 | 692 | ||
@@ -753,7 +786,7 @@ ENTRY(unrecoverable_exception) | |||
753 | wsr a1, windowbase | 786 | wsr a1, windowbase |
754 | rsync | 787 | rsync |
755 | 788 | ||
756 | movi a1, (1 << PS_WOE_BIT) | 1 | 789 | movi a1, (1 << PS_WOE_BIT) | LOCKLEVEL |
757 | wsr a1, ps | 790 | wsr a1, ps |
758 | rsync | 791 | rsync |
759 | 792 | ||
@@ -1474,7 +1507,7 @@ ENTRY(_spill_registers) | |||
1474 | l32i a1, a3, EXC_TABLE_KSTK | 1507 | l32i a1, a3, EXC_TABLE_KSTK |
1475 | wsr a3, excsave1 | 1508 | wsr a3, excsave1 |
1476 | 1509 | ||
1477 | movi a4, (1 << PS_WOE_BIT) | 1 | 1510 | movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL |
1478 | wsr a4, ps | 1511 | wsr a4, ps |
1479 | rsync | 1512 | rsync |
1480 | 1513 | ||
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index 91d9095284de..df88f98737f4 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S | |||
@@ -7,7 +7,7 @@ | |||
7 | * License. See the file "COPYING" in the main directory of this archive | 7 | * License. See the file "COPYING" in the main directory of this archive |
8 | * for more details. | 8 | * for more details. |
9 | * | 9 | * |
10 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 10 | * Copyright (C) 2001 - 2008 Tensilica Inc. |
11 | * | 11 | * |
12 | * Chris Zankel <chris@zankel.net> | 12 | * Chris Zankel <chris@zankel.net> |
13 | * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> | 13 | * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> |
@@ -128,14 +128,14 @@ ENTRY(_startup) | |||
128 | wsr a0, cpenable | 128 | wsr a0, cpenable |
129 | #endif | 129 | #endif |
130 | 130 | ||
131 | /* Set PS.INTLEVEL=1, PS.WOE=0, kernel stack, PS.EXCM=0 | 131 | /* Set PS.INTLEVEL=LOCKLEVEL, PS.WOE=0, kernel stack, PS.EXCM=0 |
132 | * | 132 | * |
133 | * Note: PS.EXCM must be cleared before using any loop | 133 | * Note: PS.EXCM must be cleared before using any loop |
134 | * instructions; otherwise, they are silently disabled, and | 134 | * instructions; otherwise, they are silently disabled, and |
135 | * at most one iteration of the loop is executed. | 135 | * at most one iteration of the loop is executed. |
136 | */ | 136 | */ |
137 | 137 | ||
138 | movi a1, 1 | 138 | movi a1, LOCKLEVEL |
139 | wsr a1, ps | 139 | wsr a1, ps |
140 | rsync | 140 | rsync |
141 | 141 | ||
@@ -211,7 +211,8 @@ ENTRY(_startup) | |||
211 | movi a1, init_thread_union | 211 | movi a1, init_thread_union |
212 | addi a1, a1, KERNEL_STACK_SIZE | 212 | addi a1, a1, KERNEL_STACK_SIZE |
213 | 213 | ||
214 | movi a2, 0x00040001 # WOE=1, INTLEVEL=1, UM=0 | 214 | movi a2, (1 << PS_WOE_BIT) | LOCKLEVEL |
215 | # WOE=1, INTLEVEL=LOCKLEVEL, UM=0 | ||
215 | wsr a2, ps # (enable reg-windows; progmode stack) | 216 | wsr a2, ps # (enable reg-windows; progmode stack) |
216 | rsync | 217 | rsync |
217 | 218 | ||
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 24c1a57abb40..6dd25ecde3f5 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c | |||
@@ -328,6 +328,27 @@ extern char _UserExceptionVector_literal_start; | |||
328 | extern char _UserExceptionVector_text_end; | 328 | extern char _UserExceptionVector_text_end; |
329 | extern char _DoubleExceptionVector_literal_start; | 329 | extern char _DoubleExceptionVector_literal_start; |
330 | extern char _DoubleExceptionVector_text_end; | 330 | extern char _DoubleExceptionVector_text_end; |
331 | #if XCHAL_EXCM_LEVEL >= 2 | ||
332 | extern char _Level2InterruptVector_text_start; | ||
333 | extern char _Level2InterruptVector_text_end; | ||
334 | #endif | ||
335 | #if XCHAL_EXCM_LEVEL >= 3 | ||
336 | extern char _Level3InterruptVector_text_start; | ||
337 | extern char _Level3InterruptVector_text_end; | ||
338 | #endif | ||
339 | #if XCHAL_EXCM_LEVEL >= 4 | ||
340 | extern char _Level4InterruptVector_text_start; | ||
341 | extern char _Level4InterruptVector_text_end; | ||
342 | #endif | ||
343 | #if XCHAL_EXCM_LEVEL >= 5 | ||
344 | extern char _Level5InterruptVector_text_start; | ||
345 | extern char _Level5InterruptVector_text_end; | ||
346 | #endif | ||
347 | #if XCHAL_EXCM_LEVEL >= 6 | ||
348 | extern char _Level6InterruptVector_text_start; | ||
349 | extern char _Level6InterruptVector_text_end; | ||
350 | #endif | ||
351 | |||
331 | 352 | ||
332 | 353 | ||
333 | #ifdef CONFIG_S32C1I_SELFTEST | 354 | #ifdef CONFIG_S32C1I_SELFTEST |
@@ -482,6 +503,27 @@ void __init setup_arch(char **cmdline_p) | |||
482 | mem_reserve(__pa(&_DoubleExceptionVector_literal_start), | 503 | mem_reserve(__pa(&_DoubleExceptionVector_literal_start), |
483 | __pa(&_DoubleExceptionVector_text_end), 0); | 504 | __pa(&_DoubleExceptionVector_text_end), 0); |
484 | 505 | ||
506 | #if XCHAL_EXCM_LEVEL >= 2 | ||
507 | mem_reserve(__pa(&_Level2InterruptVector_text_start), | ||
508 | __pa(&_Level2InterruptVector_text_end), 0); | ||
509 | #endif | ||
510 | #if XCHAL_EXCM_LEVEL >= 3 | ||
511 | mem_reserve(__pa(&_Level3InterruptVector_text_start), | ||
512 | __pa(&_Level3InterruptVector_text_end), 0); | ||
513 | #endif | ||
514 | #if XCHAL_EXCM_LEVEL >= 4 | ||
515 | mem_reserve(__pa(&_Level4InterruptVector_text_start), | ||
516 | __pa(&_Level4InterruptVector_text_end), 0); | ||
517 | #endif | ||
518 | #if XCHAL_EXCM_LEVEL >= 5 | ||
519 | mem_reserve(__pa(&_Level5InterruptVector_text_start), | ||
520 | __pa(&_Level5InterruptVector_text_end), 0); | ||
521 | #endif | ||
522 | #if XCHAL_EXCM_LEVEL >= 6 | ||
523 | mem_reserve(__pa(&_Level6InterruptVector_text_start), | ||
524 | __pa(&_Level6InterruptVector_text_end), 0); | ||
525 | #endif | ||
526 | |||
485 | bootmem_init(); | 527 | bootmem_init(); |
486 | 528 | ||
487 | #ifdef CONFIG_OF | 529 | #ifdef CONFIG_OF |
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index 01e0111bf787..9b5c345d2b4f 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c | |||
@@ -193,28 +193,49 @@ void do_multihit(struct pt_regs *regs, unsigned long exccause) | |||
193 | } | 193 | } |
194 | 194 | ||
195 | /* | 195 | /* |
196 | * Level-1 interrupt. | 196 | * IRQ handler. |
197 | * We currently have no priority encoding. | 197 | * PS.INTLEVEL is the current IRQ priority level. |
198 | */ | 198 | */ |
199 | 199 | ||
200 | unsigned long ignored_level1_interrupts; | ||
201 | extern void do_IRQ(int, struct pt_regs *); | 200 | extern void do_IRQ(int, struct pt_regs *); |
202 | 201 | ||
203 | void do_interrupt (struct pt_regs *regs) | 202 | void do_interrupt(struct pt_regs *regs) |
204 | { | 203 | { |
205 | unsigned long intread = get_sr (interrupt); | 204 | static const unsigned int_level_mask[] = { |
206 | unsigned long intenable = get_sr (intenable); | 205 | 0, |
207 | int i, mask; | 206 | XCHAL_INTLEVEL1_MASK, |
208 | 207 | XCHAL_INTLEVEL2_MASK, | |
209 | /* Handle all interrupts (no priorities). | 208 | XCHAL_INTLEVEL3_MASK, |
210 | * (Clear the interrupt before processing, in case it's | 209 | XCHAL_INTLEVEL4_MASK, |
211 | * edge-triggered or software-generated) | 210 | XCHAL_INTLEVEL5_MASK, |
212 | */ | 211 | XCHAL_INTLEVEL6_MASK, |
212 | XCHAL_INTLEVEL7_MASK, | ||
213 | }; | ||
214 | unsigned level = get_sr(ps) & PS_INTLEVEL_MASK; | ||
215 | |||
216 | if (WARN_ON_ONCE(level >= ARRAY_SIZE(int_level_mask))) | ||
217 | return; | ||
213 | 218 | ||
214 | for (i=0, mask = 1; i < XCHAL_NUM_INTERRUPTS; i++, mask <<= 1) { | 219 | for (;;) { |
215 | if (mask & (intread & intenable)) { | 220 | unsigned intread = get_sr(interrupt); |
216 | set_sr (mask, intclear); | 221 | unsigned intenable = get_sr(intenable); |
217 | do_IRQ (i,regs); | 222 | unsigned int_at_level = intread & intenable & |
223 | int_level_mask[level]; | ||
224 | |||
225 | if (!int_at_level) | ||
226 | return; | ||
227 | |||
228 | /* | ||
229 | * Clear the interrupt before processing, in case it's | ||
230 | * edge-triggered or software-generated | ||
231 | */ | ||
232 | while (int_at_level) { | ||
233 | unsigned i = __ffs(int_at_level); | ||
234 | unsigned mask = 1 << i; | ||
235 | |||
236 | int_at_level ^= mask; | ||
237 | set_sr(mask, intclear); | ||
238 | do_IRQ(i, regs); | ||
218 | } | 239 | } |
219 | } | 240 | } |
220 | } | 241 | } |
@@ -397,7 +418,7 @@ static inline void spill_registers(void) | |||
397 | unsigned int a0, ps; | 418 | unsigned int a0, ps; |
398 | 419 | ||
399 | __asm__ __volatile__ ( | 420 | __asm__ __volatile__ ( |
400 | "movi a14, " __stringify(PS_EXCM_BIT | 1) "\n\t" | 421 | "movi a14, " __stringify(PS_EXCM_BIT | LOCKLEVEL) "\n\t" |
401 | "mov a12, a0\n\t" | 422 | "mov a12, a0\n\t" |
402 | "rsr a13, sar\n\t" | 423 | "rsr a13, sar\n\t" |
403 | "xsr a14, ps\n\t" | 424 | "xsr a14, ps\n\t" |
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S index 68df35f66ce3..82109b42e240 100644 --- a/arch/xtensa/kernel/vectors.S +++ b/arch/xtensa/kernel/vectors.S | |||
@@ -10,7 +10,7 @@ | |||
10 | * Public License. See the file "COPYING" in the main directory of | 10 | * Public License. See the file "COPYING" in the main directory of |
11 | * this archive for more details. | 11 | * this archive for more details. |
12 | * | 12 | * |
13 | * Copyright (C) 2005 Tensilica, Inc. | 13 | * Copyright (C) 2005 - 2008 Tensilica, Inc. |
14 | * | 14 | * |
15 | * Chris Zankel <chris@zankel.net> | 15 | * Chris Zankel <chris@zankel.net> |
16 | * | 16 | * |
@@ -366,6 +366,41 @@ ENTRY(_DebugInterruptVector) | |||
366 | ENDPROC(_DebugInterruptVector) | 366 | ENDPROC(_DebugInterruptVector) |
367 | 367 | ||
368 | 368 | ||
369 | |||
370 | /* | ||
371 | * Medium priority level interrupt vectors | ||
372 | * | ||
373 | * Each takes less than 16 (0x10) bytes, no literals, by placing | ||
374 | * the extra 8 bytes that would otherwise be required in the window | ||
375 | * vectors area where there is space. With relocatable vectors, | ||
376 | * all vectors are within ~ 4 kB range of each other, so we can | ||
377 | * simply jump (J) to another vector without having to use JX. | ||
378 | * | ||
379 | * common_exception code gets current IRQ level in PS.INTLEVEL | ||
380 | * and preserves it for the IRQ handling time. | ||
381 | */ | ||
382 | |||
383 | .macro irq_entry_level level | ||
384 | |||
385 | .if XCHAL_EXCM_LEVEL >= \level | ||
386 | .section .Level\level\()InterruptVector.text, "ax" | ||
387 | ENTRY(_Level\level\()InterruptVector) | ||
388 | wsr a0, epc1 | ||
389 | rsr a0, epc\level | ||
390 | xsr a0, epc1 | ||
391 | # branch to user or kernel vector | ||
392 | j _SimulateUserKernelVectorException | ||
393 | .endif | ||
394 | |||
395 | .endm | ||
396 | |||
397 | irq_entry_level 2 | ||
398 | irq_entry_level 3 | ||
399 | irq_entry_level 4 | ||
400 | irq_entry_level 5 | ||
401 | irq_entry_level 6 | ||
402 | |||
403 | |||
369 | /* Window overflow and underflow handlers. | 404 | /* Window overflow and underflow handlers. |
370 | * The handlers must be 64 bytes apart, first starting with the underflow | 405 | * The handlers must be 64 bytes apart, first starting with the underflow |
371 | * handlers underflow-4 to underflow-12, then the overflow handlers | 406 | * handlers underflow-4 to underflow-12, then the overflow handlers |
@@ -396,6 +431,26 @@ ENTRY_ALIGN64(_WindowOverflow4) | |||
396 | ENDPROC(_WindowOverflow4) | 431 | ENDPROC(_WindowOverflow4) |
397 | 432 | ||
398 | 433 | ||
434 | #if XCHAL_EXCM_LEVEL >= 2 | ||
435 | /* Not a window vector - but a convenient location | ||
436 | * (where we know there's space) for continuation of | ||
437 | * medium priority interrupt dispatch code. | ||
438 | * On entry here, a0 contains PS, and EPC2 contains saved a0: | ||
439 | */ | ||
440 | .align 4 | ||
441 | _SimulateUserKernelVectorException: | ||
442 | wsr a0, excsave2 | ||
443 | movi a0, 4 # LEVEL1_INTERRUPT cause | ||
444 | wsr a0, exccause | ||
445 | rsr a0, ps | ||
446 | bbsi.l a0, PS_UM_BIT, 1f # branch if user mode | ||
447 | rsr a0, excsave2 # restore a0 | ||
448 | j _KernelExceptionVector # simulate kernel vector exception | ||
449 | 1: rsr a0, excsave2 # restore a0 | ||
450 | j _UserExceptionVector # simulate user vector exception | ||
451 | #endif | ||
452 | |||
453 | |||
399 | /* 4-Register Window Underflow Vector (Handler) */ | 454 | /* 4-Register Window Underflow Vector (Handler) */ |
400 | 455 | ||
401 | ENTRY_ALIGN64(_WindowUnderflow4) | 456 | ENTRY_ALIGN64(_WindowUnderflow4) |
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S index 255154f820b7..14695240536d 100644 --- a/arch/xtensa/kernel/vmlinux.lds.S +++ b/arch/xtensa/kernel/vmlinux.lds.S | |||
@@ -7,7 +7,7 @@ | |||
7 | * License. See the file "COPYING" in the main directory of this archive | 7 | * License. See the file "COPYING" in the main directory of this archive |
8 | * for more details. | 8 | * for more details. |
9 | * | 9 | * |
10 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 10 | * Copyright (C) 2001 - 2008 Tensilica Inc. |
11 | * | 11 | * |
12 | * Chris Zankel <chris@zankel.net> | 12 | * Chris Zankel <chris@zankel.net> |
13 | * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> | 13 | * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> |
@@ -134,6 +134,26 @@ SECTIONS | |||
134 | 134 | ||
135 | RELOCATE_ENTRY(_WindowVectors_text, | 135 | RELOCATE_ENTRY(_WindowVectors_text, |
136 | .WindowVectors.text); | 136 | .WindowVectors.text); |
137 | #if XCHAL_EXCM_LEVEL >= 2 | ||
138 | RELOCATE_ENTRY(_Level2InterruptVector_text, | ||
139 | .Level2InterruptVector.text); | ||
140 | #endif | ||
141 | #if XCHAL_EXCM_LEVEL >= 3 | ||
142 | RELOCATE_ENTRY(_Level3InterruptVector_text, | ||
143 | .Level3InterruptVector.text); | ||
144 | #endif | ||
145 | #if XCHAL_EXCM_LEVEL >= 4 | ||
146 | RELOCATE_ENTRY(_Level4InterruptVector_text, | ||
147 | .Level4InterruptVector.text); | ||
148 | #endif | ||
149 | #if XCHAL_EXCM_LEVEL >= 5 | ||
150 | RELOCATE_ENTRY(_Level5InterruptVector_text, | ||
151 | .Level5InterruptVector.text); | ||
152 | #endif | ||
153 | #if XCHAL_EXCM_LEVEL >= 6 | ||
154 | RELOCATE_ENTRY(_Level6InterruptVector_text, | ||
155 | .Level6InterruptVector.text); | ||
156 | #endif | ||
137 | RELOCATE_ENTRY(_KernelExceptionVector_text, | 157 | RELOCATE_ENTRY(_KernelExceptionVector_text, |
138 | .KernelExceptionVector.text); | 158 | .KernelExceptionVector.text); |
139 | RELOCATE_ENTRY(_UserExceptionVector_text, | 159 | RELOCATE_ENTRY(_UserExceptionVector_text, |
@@ -177,11 +197,53 @@ SECTIONS | |||
177 | XCHAL_DEBUG_VECTOR_VADDR, | 197 | XCHAL_DEBUG_VECTOR_VADDR, |
178 | 4, | 198 | 4, |
179 | .DebugInterruptVector.literal) | 199 | .DebugInterruptVector.literal) |
200 | #undef LAST | ||
201 | #define LAST .DebugInterruptVector.text | ||
202 | #if XCHAL_EXCM_LEVEL >= 2 | ||
203 | SECTION_VECTOR (_Level2InterruptVector_text, | ||
204 | .Level2InterruptVector.text, | ||
205 | XCHAL_INTLEVEL2_VECTOR_VADDR, | ||
206 | SIZEOF(LAST), LAST) | ||
207 | # undef LAST | ||
208 | # define LAST .Level2InterruptVector.text | ||
209 | #endif | ||
210 | #if XCHAL_EXCM_LEVEL >= 3 | ||
211 | SECTION_VECTOR (_Level3InterruptVector_text, | ||
212 | .Level3InterruptVector.text, | ||
213 | XCHAL_INTLEVEL3_VECTOR_VADDR, | ||
214 | SIZEOF(LAST), LAST) | ||
215 | # undef LAST | ||
216 | # define LAST .Level3InterruptVector.text | ||
217 | #endif | ||
218 | #if XCHAL_EXCM_LEVEL >= 4 | ||
219 | SECTION_VECTOR (_Level4InterruptVector_text, | ||
220 | .Level4InterruptVector.text, | ||
221 | XCHAL_INTLEVEL4_VECTOR_VADDR, | ||
222 | SIZEOF(LAST), LAST) | ||
223 | # undef LAST | ||
224 | # define LAST .Level4InterruptVector.text | ||
225 | #endif | ||
226 | #if XCHAL_EXCM_LEVEL >= 5 | ||
227 | SECTION_VECTOR (_Level5InterruptVector_text, | ||
228 | .Level5InterruptVector.text, | ||
229 | XCHAL_INTLEVEL5_VECTOR_VADDR, | ||
230 | SIZEOF(LAST), LAST) | ||
231 | # undef LAST | ||
232 | # define LAST .Level5InterruptVector.text | ||
233 | #endif | ||
234 | #if XCHAL_EXCM_LEVEL >= 6 | ||
235 | SECTION_VECTOR (_Level6InterruptVector_text, | ||
236 | .Level6InterruptVector.text, | ||
237 | XCHAL_INTLEVEL6_VECTOR_VADDR, | ||
238 | SIZEOF(LAST), LAST) | ||
239 | # undef LAST | ||
240 | # define LAST .Level6InterruptVector.text | ||
241 | #endif | ||
180 | SECTION_VECTOR (_KernelExceptionVector_literal, | 242 | SECTION_VECTOR (_KernelExceptionVector_literal, |
181 | .KernelExceptionVector.literal, | 243 | .KernelExceptionVector.literal, |
182 | XCHAL_KERNEL_VECTOR_VADDR - 4, | 244 | XCHAL_KERNEL_VECTOR_VADDR - 4, |
183 | SIZEOF(.DebugInterruptVector.text), | 245 | SIZEOF(LAST), LAST) |
184 | .DebugInterruptVector.text) | 246 | #undef LAST |
185 | SECTION_VECTOR (_KernelExceptionVector_text, | 247 | SECTION_VECTOR (_KernelExceptionVector_text, |
186 | .KernelExceptionVector.text, | 248 | .KernelExceptionVector.text, |
187 | XCHAL_KERNEL_VECTOR_VADDR, | 249 | XCHAL_KERNEL_VECTOR_VADDR, |