| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License version 2 as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef __ASM_ARC_IRQFLAGS_H
 | 
					
						
							|  |  |  | #define __ASM_ARC_IRQFLAGS_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* vineetg: March 2010 : local_irq_save( ) optimisation
 | 
					
						
							|  |  |  |  *  -Remove explicit mov of current status32 into reg, that is not needed | 
					
						
							|  |  |  |  *  -Use BIC  insn instead of INVERTED + AND | 
					
						
							|  |  |  |  *  -Conditionally disable interrupts (if they are not enabled, don't disable) | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef __KERNEL__
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/arcregs.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-14 13:28:17 +05:30
										 |  |  | /* status32 Reg bits related to Interrupt Handling */ | 
					
						
							|  |  |  | #define STATUS_E1_BIT		1	/* Int 1 enable */
 | 
					
						
							|  |  |  | #define STATUS_E2_BIT		2	/* Int 2 enable */
 | 
					
						
							|  |  |  | #define STATUS_A1_BIT		3	/* Int 1 active */
 | 
					
						
							|  |  |  | #define STATUS_A2_BIT		4	/* Int 2 active */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define STATUS_E1_MASK		(1<<STATUS_E1_BIT)
 | 
					
						
							|  |  |  | #define STATUS_E2_MASK		(1<<STATUS_E2_BIT)
 | 
					
						
							|  |  |  | #define STATUS_A1_MASK		(1<<STATUS_A1_BIT)
 | 
					
						
							|  |  |  | #define STATUS_A2_MASK		(1<<STATUS_A2_BIT)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Other Interrupt Handling related Aux regs */ | 
					
						
							|  |  |  | #define AUX_IRQ_LEV		0x200	/* IRQ Priority: L1 or L2 */
 | 
					
						
							|  |  |  | #define AUX_IRQ_HINT		0x201	/* For generating Soft Interrupts */
 | 
					
						
							|  |  |  | #define AUX_IRQ_LV12		0x43	/* interrupt level register */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define AUX_IENABLE		0x40c
 | 
					
						
							|  |  |  | #define AUX_ITRIGGER		0x40d
 | 
					
						
							|  |  |  | #define AUX_IPULSE		0x415
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | #ifndef __ASSEMBLY__
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /******************************************************************
 | 
					
						
							|  |  |  |  * IRQ Control Macros | 
					
						
							|  |  |  |  ******************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Save IRQ state and disable IRQs | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline long arch_local_irq_save(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long temp, flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__asm__ __volatile__( | 
					
						
							|  |  |  | 	"	lr  %1, [status32]	\n" | 
					
						
							|  |  |  | 	"	bic %0, %1, %2		\n" | 
					
						
							|  |  |  | 	"	and.f 0, %1, %2	\n" | 
					
						
							|  |  |  | 	"	flag.nz %0		\n" | 
					
						
							|  |  |  | 	: "=r"(temp), "=r"(flags) | 
					
						
							|  |  |  | 	: "n"((STATUS_E1_MASK | STATUS_E2_MASK)) | 
					
						
							| 
									
										
											  
											
												ARC: Add implicit compiler barrier to raw_local_irq* functions
ARC irqsave/restore macros were missing the compiler barrier, causing a
stale load in irq-enabled region be used in irq-safe region, despite
being changed, because the register holding the value was still live.
The problem manifested as random crashes in timer code when stress
testing ARCLinux (3.9-rc3) on a !SMP && !PREEMPT_COUNT
Here's the exact sequence which caused this:
 (0). tv1[x] <----> t1 <---> t2
 (1). mod_timer(t1) interrupted after it calls timer_pending()
 (2). mod_timer(t2) completes
 (3). mod_timer(t1) resumes but messes up the list
 (4). __runt_timers( ) uses bogus timer_list entry / crashes in
      timer->function
Essentially mod_timer() was racing against itself and while the spinlock
serialized the tv1[] timer link list, timer_pending() called outside the
spinlock, cached timer link list element in a register.
With low register pressure (and a deep register file), lack of barrier
in raw_local_irqsave() as well as preempt_disable (!PREEMPT_COUNT
version), there was nothing to force gcc to reload across the spinlock,
causing a stale value in reg be used for link list manipulation - ensuing
a corruption.
ARcompact disassembly which shows the culprit generated code:
mod_timer:
    push_s blink
    mov_s r13,r0	# timer, timer
..
    ###### timer_pending( )
    ld_s r3,[r13]       # <------ <variable>.entry.next LOADED
    brne r3, 0, @.L163
.L163:
..
    ###### spin_lock_irq( )
    lr  r5, [status32]  # flags
    bic r4, r5, 6       # temp, flags,
    and.f 0, r5, 6      # flags,
    flag.nz r4
    ###### detach_if_pending( ) begins
    tst_s r3,r3  <--------------
			# timer_pending( ) checks timer->entry.next
                        # r3 is NOT reloaded by gcc, using stale value
    beq.d @.L169
    mov.eq r0,0
    #####  detach_timer( ): __list_del( )
    ld r4,[r13,4]    	# <variable>.entry.prev, D.31439
    st r4,[r3,4]     	# <variable>.prev, D.31439
    st r3,[r4]       	# <variable>.next, D.30246
We initially tried to fix this by adding barrier() to preempt_* macros
for !PREEMPT_COUNT but Linus clarified that it was anything but wrong.
http://www.spinics.net/lists/kernel/msg1512709.html
[vgupta: updated commitlog]
Reported-by/Signed-off-by: Christian Ruppert <christian.ruppert@abilis.com>
Cc: Christian Ruppert <christian.ruppert@abilis.com>
Cc: Pierrick Hascoet <pierrick.hascoet@abilis.com>
Debugged-by/Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
											
										 
											2013-04-08 13:05:30 +05:30
										 |  |  | 	: "memory", "cc"); | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | 	return flags; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * restore saved IRQ state | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline void arch_local_irq_restore(unsigned long flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__asm__ __volatile__( | 
					
						
							|  |  |  | 	"	flag %0			\n" | 
					
						
							|  |  |  | 	: | 
					
						
							| 
									
										
											  
											
												ARC: Add implicit compiler barrier to raw_local_irq* functions
ARC irqsave/restore macros were missing the compiler barrier, causing a
stale load in irq-enabled region be used in irq-safe region, despite
being changed, because the register holding the value was still live.
The problem manifested as random crashes in timer code when stress
testing ARCLinux (3.9-rc3) on a !SMP && !PREEMPT_COUNT
Here's the exact sequence which caused this:
 (0). tv1[x] <----> t1 <---> t2
 (1). mod_timer(t1) interrupted after it calls timer_pending()
 (2). mod_timer(t2) completes
 (3). mod_timer(t1) resumes but messes up the list
 (4). __runt_timers( ) uses bogus timer_list entry / crashes in
      timer->function
Essentially mod_timer() was racing against itself and while the spinlock
serialized the tv1[] timer link list, timer_pending() called outside the
spinlock, cached timer link list element in a register.
With low register pressure (and a deep register file), lack of barrier
in raw_local_irqsave() as well as preempt_disable (!PREEMPT_COUNT
version), there was nothing to force gcc to reload across the spinlock,
causing a stale value in reg be used for link list manipulation - ensuing
a corruption.
ARcompact disassembly which shows the culprit generated code:
mod_timer:
    push_s blink
    mov_s r13,r0	# timer, timer
..
    ###### timer_pending( )
    ld_s r3,[r13]       # <------ <variable>.entry.next LOADED
    brne r3, 0, @.L163
.L163:
..
    ###### spin_lock_irq( )
    lr  r5, [status32]  # flags
    bic r4, r5, 6       # temp, flags,
    and.f 0, r5, 6      # flags,
    flag.nz r4
    ###### detach_if_pending( ) begins
    tst_s r3,r3  <--------------
			# timer_pending( ) checks timer->entry.next
                        # r3 is NOT reloaded by gcc, using stale value
    beq.d @.L169
    mov.eq r0,0
    #####  detach_timer( ): __list_del( )
    ld r4,[r13,4]    	# <variable>.entry.prev, D.31439
    st r4,[r3,4]     	# <variable>.prev, D.31439
    st r3,[r4]       	# <variable>.next, D.30246
We initially tried to fix this by adding barrier() to preempt_* macros
for !PREEMPT_COUNT but Linus clarified that it was anything but wrong.
http://www.spinics.net/lists/kernel/msg1512709.html
[vgupta: updated commitlog]
Reported-by/Signed-off-by: Christian Ruppert <christian.ruppert@abilis.com>
Cc: Christian Ruppert <christian.ruppert@abilis.com>
Cc: Pierrick Hascoet <pierrick.hascoet@abilis.com>
Debugged-by/Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
											
										 
											2013-04-08 13:05:30 +05:30
										 |  |  | 	: "r"(flags) | 
					
						
							|  |  |  | 	: "memory"); | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Unconditionally Enable IRQs | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | extern void arch_local_irq_enable(void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Unconditionally Disable IRQs | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline void arch_local_irq_disable(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long temp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__asm__ __volatile__( | 
					
						
							|  |  |  | 	"	lr  %0, [status32]	\n" | 
					
						
							|  |  |  | 	"	and %0, %0, %1		\n" | 
					
						
							|  |  |  | 	"	flag %0			\n" | 
					
						
							|  |  |  | 	: "=&r"(temp) | 
					
						
							| 
									
										
											  
											
												ARC: Add implicit compiler barrier to raw_local_irq* functions
ARC irqsave/restore macros were missing the compiler barrier, causing a
stale load in irq-enabled region be used in irq-safe region, despite
being changed, because the register holding the value was still live.
The problem manifested as random crashes in timer code when stress
testing ARCLinux (3.9-rc3) on a !SMP && !PREEMPT_COUNT
Here's the exact sequence which caused this:
 (0). tv1[x] <----> t1 <---> t2
 (1). mod_timer(t1) interrupted after it calls timer_pending()
 (2). mod_timer(t2) completes
 (3). mod_timer(t1) resumes but messes up the list
 (4). __runt_timers( ) uses bogus timer_list entry / crashes in
      timer->function
Essentially mod_timer() was racing against itself and while the spinlock
serialized the tv1[] timer link list, timer_pending() called outside the
spinlock, cached timer link list element in a register.
With low register pressure (and a deep register file), lack of barrier
in raw_local_irqsave() as well as preempt_disable (!PREEMPT_COUNT
version), there was nothing to force gcc to reload across the spinlock,
causing a stale value in reg be used for link list manipulation - ensuing
a corruption.
ARcompact disassembly which shows the culprit generated code:
mod_timer:
    push_s blink
    mov_s r13,r0	# timer, timer
..
    ###### timer_pending( )
    ld_s r3,[r13]       # <------ <variable>.entry.next LOADED
    brne r3, 0, @.L163
.L163:
..
    ###### spin_lock_irq( )
    lr  r5, [status32]  # flags
    bic r4, r5, 6       # temp, flags,
    and.f 0, r5, 6      # flags,
    flag.nz r4
    ###### detach_if_pending( ) begins
    tst_s r3,r3  <--------------
			# timer_pending( ) checks timer->entry.next
                        # r3 is NOT reloaded by gcc, using stale value
    beq.d @.L169
    mov.eq r0,0
    #####  detach_timer( ): __list_del( )
    ld r4,[r13,4]    	# <variable>.entry.prev, D.31439
    st r4,[r3,4]     	# <variable>.prev, D.31439
    st r3,[r4]       	# <variable>.next, D.30246
We initially tried to fix this by adding barrier() to preempt_* macros
for !PREEMPT_COUNT but Linus clarified that it was anything but wrong.
http://www.spinics.net/lists/kernel/msg1512709.html
[vgupta: updated commitlog]
Reported-by/Signed-off-by: Christian Ruppert <christian.ruppert@abilis.com>
Cc: Christian Ruppert <christian.ruppert@abilis.com>
Cc: Pierrick Hascoet <pierrick.hascoet@abilis.com>
Debugged-by/Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
											
										 
											2013-04-08 13:05:30 +05:30
										 |  |  | 	: "n"(~(STATUS_E1_MASK | STATUS_E2_MASK)) | 
					
						
							|  |  |  | 	: "memory"); | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * save IRQ state | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline long arch_local_save_flags(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long temp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__asm__ __volatile__( | 
					
						
							|  |  |  | 	"	lr  %0, [status32]	\n" | 
					
						
							| 
									
										
											  
											
												ARC: Add implicit compiler barrier to raw_local_irq* functions
ARC irqsave/restore macros were missing the compiler barrier, causing a
stale load in irq-enabled region be used in irq-safe region, despite
being changed, because the register holding the value was still live.
The problem manifested as random crashes in timer code when stress
testing ARCLinux (3.9-rc3) on a !SMP && !PREEMPT_COUNT
Here's the exact sequence which caused this:
 (0). tv1[x] <----> t1 <---> t2
 (1). mod_timer(t1) interrupted after it calls timer_pending()
 (2). mod_timer(t2) completes
 (3). mod_timer(t1) resumes but messes up the list
 (4). __runt_timers( ) uses bogus timer_list entry / crashes in
      timer->function
Essentially mod_timer() was racing against itself and while the spinlock
serialized the tv1[] timer link list, timer_pending() called outside the
spinlock, cached timer link list element in a register.
With low register pressure (and a deep register file), lack of barrier
in raw_local_irqsave() as well as preempt_disable (!PREEMPT_COUNT
version), there was nothing to force gcc to reload across the spinlock,
causing a stale value in reg be used for link list manipulation - ensuing
a corruption.
ARcompact disassembly which shows the culprit generated code:
mod_timer:
    push_s blink
    mov_s r13,r0	# timer, timer
..
    ###### timer_pending( )
    ld_s r3,[r13]       # <------ <variable>.entry.next LOADED
    brne r3, 0, @.L163
.L163:
..
    ###### spin_lock_irq( )
    lr  r5, [status32]  # flags
    bic r4, r5, 6       # temp, flags,
    and.f 0, r5, 6      # flags,
    flag.nz r4
    ###### detach_if_pending( ) begins
    tst_s r3,r3  <--------------
			# timer_pending( ) checks timer->entry.next
                        # r3 is NOT reloaded by gcc, using stale value
    beq.d @.L169
    mov.eq r0,0
    #####  detach_timer( ): __list_del( )
    ld r4,[r13,4]    	# <variable>.entry.prev, D.31439
    st r4,[r3,4]     	# <variable>.prev, D.31439
    st r3,[r4]       	# <variable>.next, D.30246
We initially tried to fix this by adding barrier() to preempt_* macros
for !PREEMPT_COUNT but Linus clarified that it was anything but wrong.
http://www.spinics.net/lists/kernel/msg1512709.html
[vgupta: updated commitlog]
Reported-by/Signed-off-by: Christian Ruppert <christian.ruppert@abilis.com>
Cc: Christian Ruppert <christian.ruppert@abilis.com>
Cc: Pierrick Hascoet <pierrick.hascoet@abilis.com>
Debugged-by/Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
											
										 
											2013-04-08 13:05:30 +05:30
										 |  |  | 	: "=&r"(temp) | 
					
						
							|  |  |  | 	: | 
					
						
							|  |  |  | 	: "memory"); | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | 	return temp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Query IRQ state | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline int arch_irqs_disabled_flags(unsigned long flags) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:22 +05:30
										 |  |  | 	return !(flags & (STATUS_E1_MASK | 
					
						
							|  |  |  | #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
 | 
					
						
							|  |  |  | 			| STATUS_E2_MASK | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		)); | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int arch_irqs_disabled(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return arch_irqs_disabled_flags(arch_local_save_flags()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void arch_mask_irq(unsigned int irq) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int ienb; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ienb = read_aux_reg(AUX_IENABLE); | 
					
						
							|  |  |  | 	ienb &= ~(1 << irq); | 
					
						
							|  |  |  | 	write_aux_reg(AUX_IENABLE, ienb); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void arch_unmask_irq(unsigned int irq) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int ienb; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ienb = read_aux_reg(AUX_IENABLE); | 
					
						
							|  |  |  | 	ienb |= (1 << irq); | 
					
						
							|  |  |  | 	write_aux_reg(AUX_IENABLE, ienb); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-06 14:18:17 +05:30
										 |  |  | #ifdef CONFIG_TRACE_IRQFLAGS
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .macro TRACE_ASM_IRQ_DISABLE | 
					
						
							|  |  |  | 	bl	trace_hardirqs_off | 
					
						
							|  |  |  | .endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .macro TRACE_ASM_IRQ_ENABLE | 
					
						
							|  |  |  | 	bl	trace_hardirqs_on | 
					
						
							|  |  |  | .endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .macro TRACE_ASM_IRQ_DISABLE | 
					
						
							|  |  |  | .endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .macro TRACE_ASM_IRQ_ENABLE | 
					
						
							|  |  |  | .endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | .macro IRQ_DISABLE  scratch | 
					
						
							|  |  |  | 	lr	\scratch, [status32] | 
					
						
							|  |  |  | 	bic	\scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK) | 
					
						
							|  |  |  | 	flag	\scratch | 
					
						
							| 
									
										
										
										
											2013-09-06 14:18:17 +05:30
										 |  |  | 	TRACE_ASM_IRQ_DISABLE | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | .endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .macro IRQ_ENABLE  scratch | 
					
						
							|  |  |  | 	lr	\scratch, [status32] | 
					
						
							|  |  |  | 	or	\scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK) | 
					
						
							|  |  |  | 	flag	\scratch | 
					
						
							| 
									
										
										
										
											2013-09-06 14:18:17 +05:30
										 |  |  | 	TRACE_ASM_IRQ_ENABLE | 
					
						
							| 
									
										
										
										
											2013-01-18 15:12:16 +05:30
										 |  |  | .endm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif	/* __ASSEMBLY__ */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif	/* KERNEL */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 |