Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARC: irqflags - Interrupt enabling/disabling at in-core intc

ARC700 has an in-core intc which provides 2 priorities (a.k.a.) "levels"
of interrupts (per IRQ) hencforth referred to as L1/L2 interrupts.

CPU flags register STATUS32 has Interrupt Enable bits per level (E1/E2)
to globally enable (or disable) all IRQs at a level. Hence the
implementation of arch_local_irq_{save,restore,enable,disable}( )

The STATUS32 reg can be r/w only using the AUX Interface of ARC, hence
the use of LR/SR instructions. Further, E1/E2 bits in there can only be
updated using the FLAG insn.

The intc supports 32 interrupts - and per IRQ enabling is controlled by
a bit in the AUX_IENABLE register, hence the implmentation of
arch_{,un}mask_irq( ) routines.

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Thomas Gleixner <tglx@linutronix.de>

+295
+114
arch/arc/include/asm/arcregs.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef _ASM_ARC_ARCREGS_H 10 + #define _ASM_ARC_ARCREGS_H 11 + 12 + #ifdef __KERNEL__ 13 + 14 + /* status32 Bits Positions */ 15 + #define STATUS_H_BIT 0 /* CPU Halted */ 16 + #define STATUS_E1_BIT 1 /* Int 1 enable */ 17 + #define STATUS_E2_BIT 2 /* Int 2 enable */ 18 + #define STATUS_A1_BIT 3 /* Int 1 active */ 19 + #define STATUS_A2_BIT 4 /* Int 2 active */ 20 + #define STATUS_AE_BIT 5 /* Exception active */ 21 + #define STATUS_DE_BIT 6 /* PC is in delay slot */ 22 + #define STATUS_U_BIT 7 /* User/Kernel mode */ 23 + #define STATUS_L_BIT 12 /* Loop inhibit */ 24 + 25 + /* These masks correspond to the status word(STATUS_32) bits */ 26 + #define STATUS_H_MASK (1<<STATUS_H_BIT) 27 + #define STATUS_E1_MASK (1<<STATUS_E1_BIT) 28 + #define STATUS_E2_MASK (1<<STATUS_E2_BIT) 29 + #define STATUS_A1_MASK (1<<STATUS_A1_BIT) 30 + #define STATUS_A2_MASK (1<<STATUS_A2_BIT) 31 + #define STATUS_AE_MASK (1<<STATUS_AE_BIT) 32 + #define STATUS_DE_MASK (1<<STATUS_DE_BIT) 33 + #define STATUS_U_MASK (1<<STATUS_U_BIT) 34 + #define STATUS_L_MASK (1<<STATUS_L_BIT) 35 + 36 + /* Auxiliary registers */ 37 + #define AUX_IDENTITY 4 38 + #define AUX_INTR_VEC_BASE 0x25 39 + #define AUX_IRQ_LEV 0x200 /* IRQ Priority: L1 or L2 */ 40 + #define AUX_IRQ_HINT 0x201 /* For generating Soft Interrupts */ 41 + #define AUX_IRQ_LV12 0x43 /* interrupt level register */ 42 + 43 + #define AUX_IENABLE 0x40c 44 + #define AUX_ITRIGGER 0x40d 45 + #define AUX_IPULSE 0x415 46 + 47 + #ifndef __ASSEMBLY__ 48 + 49 + /* 50 + ****************************************************************** 51 + * Inline ASM macros to read/write AUX Regs 52 + * Essentially invocation of lr/sr insns from "C" 53 + */ 54 + 55 + #if 1 56 + 57 + #define read_aux_reg(reg) __builtin_arc_lr(reg) 58 + 59 + /* gcc builtin sr needs reg param to be long immediate */ 60 + #define write_aux_reg(reg_immed, val) \ 61 + __builtin_arc_sr((unsigned int)val, reg_immed) 62 + 63 + #else 64 + 65 + #define read_aux_reg(reg) \ 66 + ({ \ 67 + unsigned int __ret; \ 68 + __asm__ __volatile__( \ 69 + " lr %0, [%1]" \ 70 + : "=r"(__ret) \ 71 + : "i"(reg)); \ 72 + __ret; \ 73 + }) 74 + 75 + /* 76 + * Aux Reg address is specified as long immediate by caller 77 + * e.g. 78 + * write_aux_reg(0x69, some_val); 79 + * This generates tightest code. 80 + */ 81 + #define write_aux_reg(reg_imm, val) \ 82 + ({ \ 83 + __asm__ __volatile__( \ 84 + " sr %0, [%1] \n" \ 85 + : \ 86 + : "ir"(val), "i"(reg_imm)); \ 87 + }) 88 + 89 + /* 90 + * Aux Reg address is specified in a variable 91 + * * e.g. 92 + * reg_num = 0x69 93 + * write_aux_reg2(reg_num, some_val); 94 + * This has to generate glue code to load the reg num from 95 + * memory to a reg hence not recommended. 96 + */ 97 + #define write_aux_reg2(reg_in_var, val) \ 98 + ({ \ 99 + unsigned int tmp; \ 100 + \ 101 + __asm__ __volatile__( \ 102 + " ld %0, [%2] \n\t" \ 103 + " sr %1, [%0] \n\t" \ 104 + : "=&r"(tmp) \ 105 + : "r"(val), "memory"(&reg_in_var)); \ 106 + }) 107 + 108 + #endif 109 + 110 + #endif /* __ASEMBLY__ */ 111 + 112 + #endif /* __KERNEL__ */ 113 + 114 + #endif /* _ASM_ARC_ARCREGS_H */
+149
arch/arc/include/asm/irqflags.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef __ASM_ARC_IRQFLAGS_H 10 + #define __ASM_ARC_IRQFLAGS_H 11 + 12 + /* vineetg: March 2010 : local_irq_save( ) optimisation 13 + * -Remove explicit mov of current status32 into reg, that is not needed 14 + * -Use BIC insn instead of INVERTED + AND 15 + * -Conditionally disable interrupts (if they are not enabled, don't disable) 16 + */ 17 + 18 + #ifdef __KERNEL__ 19 + 20 + #include <asm/arcregs.h> 21 + 22 + #ifndef __ASSEMBLY__ 23 + 24 + /****************************************************************** 25 + * IRQ Control Macros 26 + ******************************************************************/ 27 + 28 + /* 29 + * Save IRQ state and disable IRQs 30 + */ 31 + static inline long arch_local_irq_save(void) 32 + { 33 + unsigned long temp, flags; 34 + 35 + __asm__ __volatile__( 36 + " lr %1, [status32] \n" 37 + " bic %0, %1, %2 \n" 38 + " and.f 0, %1, %2 \n" 39 + " flag.nz %0 \n" 40 + : "=r"(temp), "=r"(flags) 41 + : "n"((STATUS_E1_MASK | STATUS_E2_MASK)) 42 + : "cc"); 43 + 44 + return flags; 45 + } 46 + 47 + /* 48 + * restore saved IRQ state 49 + */ 50 + static inline void arch_local_irq_restore(unsigned long flags) 51 + { 52 + 53 + __asm__ __volatile__( 54 + " flag %0 \n" 55 + : 56 + : "r"(flags)); 57 + } 58 + 59 + /* 60 + * Unconditionally Enable IRQs 61 + */ 62 + extern void arch_local_irq_enable(void); 63 + 64 + /* 65 + * Unconditionally Disable IRQs 66 + */ 67 + static inline void arch_local_irq_disable(void) 68 + { 69 + unsigned long temp; 70 + 71 + __asm__ __volatile__( 72 + " lr %0, [status32] \n" 73 + " and %0, %0, %1 \n" 74 + " flag %0 \n" 75 + : "=&r"(temp) 76 + : "n"(~(STATUS_E1_MASK | STATUS_E2_MASK))); 77 + } 78 + 79 + /* 80 + * save IRQ state 81 + */ 82 + static inline long arch_local_save_flags(void) 83 + { 84 + unsigned long temp; 85 + 86 + __asm__ __volatile__( 87 + " lr %0, [status32] \n" 88 + : "=&r"(temp)); 89 + 90 + return temp; 91 + } 92 + 93 + /* 94 + * Query IRQ state 95 + */ 96 + static inline int arch_irqs_disabled_flags(unsigned long flags) 97 + { 98 + return !(flags & (STATUS_E1_MASK)); 99 + } 100 + 101 + static inline int arch_irqs_disabled(void) 102 + { 103 + return arch_irqs_disabled_flags(arch_local_save_flags()); 104 + } 105 + 106 + static inline void arch_mask_irq(unsigned int irq) 107 + { 108 + unsigned int ienb; 109 + 110 + ienb = read_aux_reg(AUX_IENABLE); 111 + ienb &= ~(1 << irq); 112 + write_aux_reg(AUX_IENABLE, ienb); 113 + } 114 + 115 + static inline void arch_unmask_irq(unsigned int irq) 116 + { 117 + unsigned int ienb; 118 + 119 + ienb = read_aux_reg(AUX_IENABLE); 120 + ienb |= (1 << irq); 121 + write_aux_reg(AUX_IENABLE, ienb); 122 + } 123 + 124 + #else 125 + 126 + .macro IRQ_DISABLE scratch 127 + lr \scratch, [status32] 128 + bic \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK) 129 + flag \scratch 130 + .endm 131 + 132 + .macro IRQ_DISABLE_SAVE scratch, save 133 + lr \scratch, [status32] 134 + mov \save, \scratch /* Make a copy */ 135 + bic \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK) 136 + flag \scratch 137 + .endm 138 + 139 + .macro IRQ_ENABLE scratch 140 + lr \scratch, [status32] 141 + or \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK) 142 + flag \scratch 143 + .endm 144 + 145 + #endif /* __ASSEMBLY__ */ 146 + 147 + #endif /* KERNEL */ 148 + 149 + #endif
+32
arch/arc/kernel/irq.c
··· 1 + /* 2 + * Copyright (C) 2011-12 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + */ 9 + 10 + #include <linux/interrupt.h> 11 + #include <linux/module.h> 12 + #include <asm/irqflags.h> 13 + #include <asm/arcregs.h> 14 + 15 + void arch_local_irq_enable(void) 16 + { 17 + unsigned long flags; 18 + 19 + /* 20 + * ARC IDE Drivers tries to re-enable interrupts from hard-isr 21 + * context which is simply wrong 22 + */ 23 + if (in_irq()) { 24 + WARN_ONCE(1, "IRQ enabled from hard-isr"); 25 + return; 26 + } 27 + 28 + flags = arch_local_save_flags(); 29 + flags |= (STATUS_E1_MASK | STATUS_E2_MASK); 30 + arch_local_irq_restore(flags); 31 + } 32 + EXPORT_SYMBOL(arch_local_irq_enable);