0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #undef DEBUG
0020
0021 #include <linux/export.h>
0022 #include <linux/threads.h>
0023 #include <linux/kernel_stat.h>
0024 #include <linux/signal.h>
0025 #include <linux/sched.h>
0026 #include <linux/ptrace.h>
0027 #include <linux/ioport.h>
0028 #include <linux/interrupt.h>
0029 #include <linux/timex.h>
0030 #include <linux/init.h>
0031 #include <linux/slab.h>
0032 #include <linux/delay.h>
0033 #include <linux/irq.h>
0034 #include <linux/seq_file.h>
0035 #include <linux/cpumask.h>
0036 #include <linux/profile.h>
0037 #include <linux/bitops.h>
0038 #include <linux/list.h>
0039 #include <linux/radix-tree.h>
0040 #include <linux/mutex.h>
0041 #include <linux/pci.h>
0042 #include <linux/debugfs.h>
0043 #include <linux/of.h>
0044 #include <linux/of_irq.h>
0045 #include <linux/vmalloc.h>
0046 #include <linux/pgtable.h>
0047 #include <linux/static_call.h>
0048
0049 #include <linux/uaccess.h>
0050 #include <asm/interrupt.h>
0051 #include <asm/io.h>
0052 #include <asm/irq.h>
0053 #include <asm/cache.h>
0054 #include <asm/ptrace.h>
0055 #include <asm/machdep.h>
0056 #include <asm/udbg.h>
0057 #include <asm/smp.h>
0058 #include <asm/hw_irq.h>
0059 #include <asm/softirq_stack.h>
0060 #include <asm/ppc_asm.h>
0061
0062 #include <asm/paca.h>
0063 #include <asm/firmware.h>
0064 #include <asm/lv1call.h>
0065 #include <asm/dbell.h>
0066 #include <asm/trace.h>
0067 #include <asm/cpu_has_feature.h>
0068
0069 int distribute_irqs = 1;
0070
0071 void replay_soft_interrupts(void)
0072 {
0073 struct pt_regs regs;
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 ppc_save_regs(®s);
0087 regs.softe = IRQS_ENABLED;
0088 regs.msr |= MSR_EE;
0089
0090 again:
0091 if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
0092 WARN_ON_ONCE(mfmsr() & MSR_EE);
0093
0094
0095
0096
0097
0098 if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
0099 u64 tmp, tmp2;
0100 lv1_get_version_info(&tmp, &tmp2);
0101 }
0102
0103
0104
0105
0106
0107
0108 if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_HMI)) {
0109 local_paca->irq_happened &= ~PACA_IRQ_HMI;
0110 regs.trap = INTERRUPT_HMI;
0111 handle_hmi_exception(®s);
0112 if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
0113 hard_irq_disable();
0114 }
0115
0116 if (local_paca->irq_happened & PACA_IRQ_DEC) {
0117 local_paca->irq_happened &= ~PACA_IRQ_DEC;
0118 regs.trap = INTERRUPT_DECREMENTER;
0119 timer_interrupt(®s);
0120 if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
0121 hard_irq_disable();
0122 }
0123
0124 if (local_paca->irq_happened & PACA_IRQ_EE) {
0125 local_paca->irq_happened &= ~PACA_IRQ_EE;
0126 regs.trap = INTERRUPT_EXTERNAL;
0127 do_IRQ(®s);
0128 if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
0129 hard_irq_disable();
0130 }
0131
0132 if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (local_paca->irq_happened & PACA_IRQ_DBELL)) {
0133 local_paca->irq_happened &= ~PACA_IRQ_DBELL;
0134 regs.trap = INTERRUPT_DOORBELL;
0135 doorbell_exception(®s);
0136 if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
0137 hard_irq_disable();
0138 }
0139
0140
0141 if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_PMI)) {
0142 local_paca->irq_happened &= ~PACA_IRQ_PMI;
0143 regs.trap = INTERRUPT_PERFMON;
0144 performance_monitor_exception(®s);
0145 if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
0146 hard_irq_disable();
0147 }
0148
0149 if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS) {
0150
0151
0152
0153
0154 trace_hardirqs_on();
0155 trace_hardirqs_off();
0156 goto again;
0157 }
0158 }
0159
0160 #if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_KUAP)
0161 static inline void replay_soft_interrupts_irqrestore(void)
0162 {
0163 unsigned long kuap_state = get_kuap();
0164
0165
0166
0167
0168
0169
0170
0171 kuap_assert_locked();
0172
0173 if (kuap_state != AMR_KUAP_BLOCKED)
0174 set_kuap(AMR_KUAP_BLOCKED);
0175
0176 replay_soft_interrupts();
0177
0178 if (kuap_state != AMR_KUAP_BLOCKED)
0179 set_kuap(kuap_state);
0180 }
0181 #else
0182 #define replay_soft_interrupts_irqrestore() replay_soft_interrupts()
0183 #endif
0184
0185 notrace void arch_local_irq_restore(unsigned long mask)
0186 {
0187 unsigned char irq_happened;
0188
0189
0190 if (mask) {
0191 irq_soft_mask_set(mask);
0192 return;
0193 }
0194
0195 if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
0196 WARN_ON_ONCE(in_nmi() || in_hardirq());
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208 asm_volatile_goto(
0209 "1: \n"
0210 " lbz 9,%0(13) \n"
0211 " cmpwi 9,0 \n"
0212 " bne %l[happened] \n"
0213 " stb 9,%1(13) \n"
0214 "2: \n"
0215 RESTART_TABLE(1b, 2b, 1b)
0216 : : "i" (offsetof(struct paca_struct, irq_happened)),
0217 "i" (offsetof(struct paca_struct, irq_soft_mask))
0218 : "cr0", "r9"
0219 : happened);
0220
0221 if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
0222 WARN_ON_ONCE(!(mfmsr() & MSR_EE));
0223
0224 return;
0225
0226 happened:
0227 irq_happened = READ_ONCE(local_paca->irq_happened);
0228 if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
0229 WARN_ON_ONCE(!irq_happened);
0230
0231 if (irq_happened == PACA_IRQ_HARD_DIS) {
0232 if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
0233 WARN_ON_ONCE(mfmsr() & MSR_EE);
0234 irq_soft_mask_set(IRQS_ENABLED);
0235 local_paca->irq_happened = 0;
0236 __hard_irq_enable();
0237 return;
0238 }
0239
0240
0241 if (!(irq_happened & PACA_IRQ_HARD_DIS)) {
0242 if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
0243 if (!(mfmsr() & MSR_EE)) {
0244
0245
0246
0247
0248
0249
0250 irq_happened = READ_ONCE(local_paca->irq_happened);
0251 WARN_ON_ONCE(!(irq_happened & PACA_IRQ_HARD_DIS));
0252 }
0253 }
0254 __hard_irq_disable();
0255 local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
0256 } else {
0257 if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
0258 if (WARN_ON_ONCE(mfmsr() & MSR_EE))
0259 __hard_irq_disable();
0260 }
0261 }
0262
0263
0264
0265
0266
0267
0268 preempt_disable();
0269 irq_soft_mask_set(IRQS_ALL_DISABLED);
0270 trace_hardirqs_off();
0271
0272 replay_soft_interrupts_irqrestore();
0273 local_paca->irq_happened = 0;
0274
0275 trace_hardirqs_on();
0276 irq_soft_mask_set(IRQS_ENABLED);
0277 __hard_irq_enable();
0278 preempt_enable();
0279 }
0280 EXPORT_SYMBOL(arch_local_irq_restore);
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297 bool prep_irq_for_idle(void)
0298 {
0299
0300
0301
0302
0303 __hard_irq_disable();
0304 local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
0305
0306
0307
0308
0309
0310 if (lazy_irq_pending())
0311 return false;
0312
0313
0314 trace_hardirqs_on();
0315
0316
0317
0318
0319
0320
0321
0322 local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
0323 irq_soft_mask_set(IRQS_ENABLED);
0324
0325
0326 return true;
0327 }
0328
0329 #ifdef CONFIG_PPC_BOOK3S
0330
0331
0332
0333
0334
0335
0336 bool prep_irq_for_idle_irqsoff(void)
0337 {
0338 WARN_ON(!irqs_disabled());
0339
0340
0341
0342
0343
0344 __hard_irq_disable();
0345 local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
0346
0347
0348
0349
0350
0351 if (lazy_irq_pending())
0352 return false;
0353
0354
0355 trace_hardirqs_on();
0356
0357 return true;
0358 }
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370 #define IRQ_SYSTEM_RESET 0xff
0371
0372 static const u8 srr1_to_lazyirq[0x10] = {
0373 0, 0, 0,
0374 PACA_IRQ_DBELL,
0375 IRQ_SYSTEM_RESET,
0376 PACA_IRQ_DBELL,
0377 PACA_IRQ_DEC,
0378 0,
0379 PACA_IRQ_EE,
0380 PACA_IRQ_EE,
0381 PACA_IRQ_HMI,
0382 0, 0, 0, 0, 0 };
0383
0384 void replay_system_reset(void)
0385 {
0386 struct pt_regs regs;
0387
0388 ppc_save_regs(®s);
0389 regs.trap = 0x100;
0390 get_paca()->in_nmi = 1;
0391 system_reset_exception(®s);
0392 get_paca()->in_nmi = 0;
0393 }
0394 EXPORT_SYMBOL_GPL(replay_system_reset);
0395
0396 void irq_set_pending_from_srr1(unsigned long srr1)
0397 {
0398 unsigned int idx = (srr1 & SRR1_WAKEMASK_P8) >> 18;
0399 u8 reason = srr1_to_lazyirq[idx];
0400
0401
0402
0403
0404
0405
0406 if (unlikely(reason == IRQ_SYSTEM_RESET)) {
0407 replay_system_reset();
0408 return;
0409 }
0410
0411 if (reason == PACA_IRQ_DBELL) {
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421 ppc_msgclr(PPC_DBELL_MSGTYPE);
0422 }
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433 local_paca->irq_happened |= reason;
0434 }
0435 #endif
0436
0437
0438
0439
0440 void force_external_irq_replay(void)
0441 {
0442
0443
0444
0445
0446 WARN_ON(!arch_irqs_disabled());
0447
0448
0449
0450
0451
0452
0453 __hard_irq_disable();
0454 local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
0455
0456
0457 local_paca->irq_happened |= PACA_IRQ_EE;
0458 }
0459
0460 static int __init setup_noirqdistrib(char *str)
0461 {
0462 distribute_irqs = 0;
0463 return 1;
0464 }
0465
0466 __setup("noirqdistrib", setup_noirqdistrib);