 0b88f772bd
			
		
	
	
	0b88f772bd
	
	
	
		
			
			In hard_irq_disable(), we accessed the PACA before we hard disabled the interrupts, potentially causing a warning as get_paca() will us debug_smp_processor_id(). Move that to after the disabling, and also use local_paca directly rather than get_paca() to avoid several redundant and useless checks. Signed-off-by: Tiejun Chen <tiejun.chen@windriver.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
		
			
				
	
	
		
			211 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
 | |
|  */
 | |
| #ifndef _ASM_POWERPC_HW_IRQ_H
 | |
| #define _ASM_POWERPC_HW_IRQ_H
 | |
| 
 | |
| #ifdef __KERNEL__
 | |
| 
 | |
| #include <linux/errno.h>
 | |
| #include <linux/compiler.h>
 | |
| #include <asm/ptrace.h>
 | |
| #include <asm/processor.h>
 | |
| 
 | |
| #ifdef CONFIG_PPC64
 | |
| 
 | |
| /*
 | |
|  * PACA flags in paca->irq_happened.
 | |
|  *
 | |
|  * This bits are set when interrupts occur while soft-disabled
 | |
|  * and allow a proper replay. Additionally, PACA_IRQ_HARD_DIS
 | |
|  * is set whenever we manually hard disable.
 | |
|  */
 | |
| #define PACA_IRQ_HARD_DIS	0x01
 | |
| #define PACA_IRQ_DBELL		0x02
 | |
| #define PACA_IRQ_EE		0x04
 | |
| #define PACA_IRQ_DEC		0x08 /* Or FIT */
 | |
| #define PACA_IRQ_EE_EDGE	0x10 /* BookE only */
 | |
| 
 | |
| #endif /* CONFIG_PPC64 */
 | |
| 
 | |
| #ifndef __ASSEMBLY__
 | |
| 
 | |
| extern void __replay_interrupt(unsigned int vector);
 | |
| 
 | |
| extern void timer_interrupt(struct pt_regs *);
 | |
| extern void performance_monitor_exception(struct pt_regs *regs);
 | |
| extern void WatchdogException(struct pt_regs *regs);
 | |
| extern void unknown_exception(struct pt_regs *regs);
 | |
| 
 | |
| #ifdef CONFIG_PPC64
 | |
| #include <asm/paca.h>
 | |
| 
 | |
| static inline unsigned long arch_local_save_flags(void)
 | |
| {
 | |
| 	unsigned long flags;
 | |
| 
 | |
| 	asm volatile(
 | |
| 		"lbz %0,%1(13)"
 | |
| 		: "=r" (flags)
 | |
| 		: "i" (offsetof(struct paca_struct, soft_enabled)));
 | |
| 
 | |
| 	return flags;
 | |
| }
 | |
| 
 | |
| static inline unsigned long arch_local_irq_disable(void)
 | |
| {
 | |
| 	unsigned long flags, zero;
 | |
| 
 | |
| 	asm volatile(
 | |
| 		"li %1,0; lbz %0,%2(13); stb %1,%2(13)"
 | |
| 		: "=r" (flags), "=&r" (zero)
 | |
| 		: "i" (offsetof(struct paca_struct, soft_enabled))
 | |
| 		: "memory");
 | |
| 
 | |
| 	return flags;
 | |
| }
 | |
| 
 | |
| extern void arch_local_irq_restore(unsigned long);
 | |
| 
 | |
| static inline void arch_local_irq_enable(void)
 | |
| {
 | |
| 	arch_local_irq_restore(1);
 | |
| }
 | |
| 
 | |
| static inline unsigned long arch_local_irq_save(void)
 | |
| {
 | |
| 	return arch_local_irq_disable();
 | |
| }
 | |
| 
 | |
| static inline bool arch_irqs_disabled_flags(unsigned long flags)
 | |
| {
 | |
| 	return flags == 0;
 | |
| }
 | |
| 
 | |
| static inline bool arch_irqs_disabled(void)
 | |
| {
 | |
| 	return arch_irqs_disabled_flags(arch_local_save_flags());
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_PPC_BOOK3E
 | |
| #define __hard_irq_enable()	asm volatile("wrteei 1" : : : "memory")
 | |
| #define __hard_irq_disable()	asm volatile("wrteei 0" : : : "memory")
 | |
| #else
 | |
| #define __hard_irq_enable()	__mtmsrd(local_paca->kernel_msr | MSR_EE, 1)
 | |
| #define __hard_irq_disable()	__mtmsrd(local_paca->kernel_msr, 1)
 | |
| #endif
 | |
| 
 | |
| #define hard_irq_disable()	do {			\
 | |
| 	u8 _was_enabled;				\
 | |
| 	__hard_irq_disable();				\
 | |
| 	_was_enabled = local_paca->soft_enabled;	\
 | |
| 	local_paca->soft_enabled = 0;			\
 | |
| 	local_paca->irq_happened |= PACA_IRQ_HARD_DIS;	\
 | |
| 	if (_was_enabled)				\
 | |
| 		trace_hardirqs_off();			\
 | |
| } while(0)
 | |
| 
 | |
| static inline bool lazy_irq_pending(void)
 | |
| {
 | |
| 	return !!(get_paca()->irq_happened & ~PACA_IRQ_HARD_DIS);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * This is called by asynchronous interrupts to conditionally
 | |
|  * re-enable hard interrupts when soft-disabled after having
 | |
|  * cleared the source of the interrupt
 | |
|  */
 | |
| static inline void may_hard_irq_enable(void)
 | |
| {
 | |
| 	get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS;
 | |
| 	if (!(get_paca()->irq_happened & PACA_IRQ_EE))
 | |
| 		__hard_irq_enable();
 | |
| }
 | |
| 
 | |
| static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
 | |
| {
 | |
| 	return !regs->softe;
 | |
| }
 | |
| 
 | |
| extern bool prep_irq_for_idle(void);
 | |
| 
 | |
| #else /* CONFIG_PPC64 */
 | |
| 
 | |
| #define SET_MSR_EE(x)	mtmsr(x)
 | |
| 
 | |
| static inline unsigned long arch_local_save_flags(void)
 | |
| {
 | |
| 	return mfmsr();
 | |
| }
 | |
| 
 | |
| static inline void arch_local_irq_restore(unsigned long flags)
 | |
| {
 | |
| #if defined(CONFIG_BOOKE)
 | |
| 	asm volatile("wrtee %0" : : "r" (flags) : "memory");
 | |
| #else
 | |
| 	mtmsr(flags);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static inline unsigned long arch_local_irq_save(void)
 | |
| {
 | |
| 	unsigned long flags = arch_local_save_flags();
 | |
| #ifdef CONFIG_BOOKE
 | |
| 	asm volatile("wrteei 0" : : : "memory");
 | |
| #else
 | |
| 	SET_MSR_EE(flags & ~MSR_EE);
 | |
| #endif
 | |
| 	return flags;
 | |
| }
 | |
| 
 | |
| static inline void arch_local_irq_disable(void)
 | |
| {
 | |
| #ifdef CONFIG_BOOKE
 | |
| 	asm volatile("wrteei 0" : : : "memory");
 | |
| #else
 | |
| 	arch_local_irq_save();
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static inline void arch_local_irq_enable(void)
 | |
| {
 | |
| #ifdef CONFIG_BOOKE
 | |
| 	asm volatile("wrteei 1" : : : "memory");
 | |
| #else
 | |
| 	unsigned long msr = mfmsr();
 | |
| 	SET_MSR_EE(msr | MSR_EE);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static inline bool arch_irqs_disabled_flags(unsigned long flags)
 | |
| {
 | |
| 	return (flags & MSR_EE) == 0;
 | |
| }
 | |
| 
 | |
| static inline bool arch_irqs_disabled(void)
 | |
| {
 | |
| 	return arch_irqs_disabled_flags(arch_local_save_flags());
 | |
| }
 | |
| 
 | |
| #define hard_irq_disable()		arch_local_irq_disable()
 | |
| 
 | |
| static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
 | |
| {
 | |
| 	return !(regs->msr & MSR_EE);
 | |
| }
 | |
| 
 | |
| static inline void may_hard_irq_enable(void) { }
 | |
| 
 | |
| #endif /* CONFIG_PPC64 */
 | |
| 
 | |
| #define ARCH_IRQ_INIT_FLAGS	IRQ_NOREQUEST
 | |
| 
 | |
| /*
 | |
|  * interrupt-retrigger: should we handle this via lost interrupts and IPIs
 | |
|  * or should we not care like we do now ? --BenH.
 | |
|  */
 | |
| struct irq_chip;
 | |
| 
 | |
| #endif  /* __ASSEMBLY__ */
 | |
| #endif	/* __KERNEL__ */
 | |
| #endif	/* _ASM_POWERPC_HW_IRQ_H */
 |