1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> 4 */ 5 #ifndef _ASM_POWERPC_HW_IRQ_H 6 #define _ASM_POWERPC_HW_IRQ_H 7 8 #ifdef __KERNEL__ 9 10 #include <linux/errno.h> 11 #include <linux/compiler.h> 12 #include <asm/ptrace.h> 13 #include <asm/processor.h> 14 15 #ifdef CONFIG_PPC64 16 17 /* 18 * PACA flags in paca->irq_happened. 19 * 20 * This bits are set when interrupts occur while soft-disabled 21 * and allow a proper replay. Additionally, PACA_IRQ_HARD_DIS 22 * is set whenever we manually hard disable. 23 */ 24 #define PACA_IRQ_HARD_DIS 0x01 25 #define PACA_IRQ_DBELL 0x02 26 #define PACA_IRQ_EE 0x04 27 #define PACA_IRQ_DEC 0x08 /* Or FIT */ 28 #define PACA_IRQ_EE_EDGE 0x10 /* BookE only */ 29 #define PACA_IRQ_HMI 0x20 30 31 #endif /* CONFIG_PPC64 */ 32 33 #ifndef __ASSEMBLY__ 34 35 extern void __replay_interrupt(unsigned int vector); 36 37 extern void timer_interrupt(struct pt_regs *); 38 extern void performance_monitor_exception(struct pt_regs *regs); 39 extern void WatchdogException(struct pt_regs *regs); 40 extern void unknown_exception(struct pt_regs *regs); 41 42 #ifdef CONFIG_PPC64 43 #include <asm/paca.h> 44 45 static inline unsigned long arch_local_save_flags(void) 46 { 47 unsigned long flags; 48 49 asm volatile( 50 "lbz %0,%1(13)" 51 : "=r" (flags) 52 : "i" (offsetof(struct paca_struct, soft_enabled))); 53 54 return flags; 55 } 56 57 static inline unsigned long arch_local_irq_disable(void) 58 { 59 unsigned long flags, zero; 60 61 asm volatile( 62 "li %1,0; lbz %0,%2(13); stb %1,%2(13)" 63 : "=r" (flags), "=&r" (zero) 64 : "i" (offsetof(struct paca_struct, soft_enabled)) 65 : "memory"); 66 67 return flags; 68 } 69 70 extern void arch_local_irq_restore(unsigned long); 71 72 static inline void arch_local_irq_enable(void) 73 { 74 arch_local_irq_restore(1); 75 } 76 77 static inline unsigned long arch_local_irq_save(void) 78 { 79 return arch_local_irq_disable(); 80 } 81 82 static inline bool arch_irqs_disabled_flags(unsigned long flags) 83 { 84 return flags == 0; 85 } 86 87 static inline bool arch_irqs_disabled(void) 88 { 89 return arch_irqs_disabled_flags(arch_local_save_flags()); 90 } 91 92 #ifdef CONFIG_PPC_BOOK3E 93 #define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory") 94 #define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory") 95 #else 96 #define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1) 97 #define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1) 98 #endif 99 100 #define hard_irq_disable() do { \ 101 u8 _was_enabled; \ 102 __hard_irq_disable(); \ 103 _was_enabled = local_paca->soft_enabled; \ 104 local_paca->soft_enabled = 0; \ 105 local_paca->irq_happened |= PACA_IRQ_HARD_DIS; \ 106 if (_was_enabled) \ 107 trace_hardirqs_off(); \ 108 } while(0) 109 110 static inline bool lazy_irq_pending(void) 111 { 112 return !!(get_paca()->irq_happened & ~PACA_IRQ_HARD_DIS); 113 } 114 115 /* 116 * This is called by asynchronous interrupts to conditionally 117 * re-enable hard interrupts when soft-disabled after having 118 * cleared the source of the interrupt 119 */ 120 static inline void may_hard_irq_enable(void) 121 { 122 get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS; 123 if (!(get_paca()->irq_happened & PACA_IRQ_EE)) 124 __hard_irq_enable(); 125 } 126 127 static inline bool arch_irq_disabled_regs(struct pt_regs *regs) 128 { 129 return !regs->softe; 130 } 131 132 extern bool prep_irq_for_idle(void); 133 extern bool prep_irq_for_idle_irqsoff(void); 134 extern void irq_set_pending_from_srr1(unsigned long srr1); 135 136 #define fini_irq_for_idle_irqsoff() trace_hardirqs_off(); 137 138 extern void force_external_irq_replay(void); 139 140 #else /* CONFIG_PPC64 */ 141 142 #define SET_MSR_EE(x) mtmsr(x) 143 144 static inline unsigned long arch_local_save_flags(void) 145 { 146 return mfmsr(); 147 } 148 149 static inline void arch_local_irq_restore(unsigned long flags) 150 { 151 #if defined(CONFIG_BOOKE) 152 asm volatile("wrtee %0" : : "r" (flags) : "memory"); 153 #else 154 mtmsr(flags); 155 #endif 156 } 157 158 static inline unsigned long arch_local_irq_save(void) 159 { 160 unsigned long flags = arch_local_save_flags(); 161 #ifdef CONFIG_BOOKE 162 asm volatile("wrteei 0" : : : "memory"); 163 #elif defined(CONFIG_PPC_8xx) 164 wrtspr(SPRN_EID); 165 #else 166 SET_MSR_EE(flags & ~MSR_EE); 167 #endif 168 return flags; 169 } 170 171 static inline void arch_local_irq_disable(void) 172 { 173 #ifdef CONFIG_BOOKE 174 asm volatile("wrteei 0" : : : "memory"); 175 #elif defined(CONFIG_PPC_8xx) 176 wrtspr(SPRN_EID); 177 #else 178 arch_local_irq_save(); 179 #endif 180 } 181 182 static inline void arch_local_irq_enable(void) 183 { 184 #ifdef CONFIG_BOOKE 185 asm volatile("wrteei 1" : : : "memory"); 186 #elif defined(CONFIG_PPC_8xx) 187 wrtspr(SPRN_EIE); 188 #else 189 unsigned long msr = mfmsr(); 190 SET_MSR_EE(msr | MSR_EE); 191 #endif 192 } 193 194 static inline bool arch_irqs_disabled_flags(unsigned long flags) 195 { 196 return (flags & MSR_EE) == 0; 197 } 198 199 static inline bool arch_irqs_disabled(void) 200 { 201 return arch_irqs_disabled_flags(arch_local_save_flags()); 202 } 203 204 #define hard_irq_disable() arch_local_irq_disable() 205 206 static inline bool arch_irq_disabled_regs(struct pt_regs *regs) 207 { 208 return !(regs->msr & MSR_EE); 209 } 210 211 static inline void may_hard_irq_enable(void) { } 212 213 #endif /* CONFIG_PPC64 */ 214 215 #define ARCH_IRQ_INIT_FLAGS IRQ_NOREQUEST 216 217 /* 218 * interrupt-retrigger: should we handle this via lost interrupts and IPIs 219 * or should we not care like we do now ? --BenH. 220 */ 221 struct irq_chip; 222 223 #endif /* __ASSEMBLY__ */ 224 #endif /* __KERNEL__ */ 225 #endif /* _ASM_POWERPC_HW_IRQ_H */ 226