Pull irq fix from Borislav Petkov: "A single fix for GICv3 to not take an interrupt in an NMI context" * tag 'irq_urgent_for_v5.13_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: irqchip/gic-v3: Workaround inconsistent PMR setting on NMI entry
Unified · Split
| @@ -642,11 +642,45 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs) · 641 unmodified lines | |||
| 642 | nmi_exit(); | 642 | nmi_exit(); |
| 643 | } | 643 | } |
| 644 | 644 | ||
| 645 | static u32 do_read_iar(struct pt_regs *regs) | ||
| 646 | { | ||
| 647 | u32 iar; | ||
| 648 | |||
| 649 | if (gic_supports_nmi() && unlikely(!interrupts_enabled(regs))) { | ||
| 650 | u64 pmr; | ||
| 651 | |||
| 652 | /* | ||
| 653 | * We were in a context with IRQs disabled. However, the | ||
| 654 | * entry code has set PMR to a value that allows any | ||
| 655 | * interrupt to be acknowledged, and not just NMIs. This can | ||
| 656 | * lead to surprising effects if the NMI has been retired in | ||
| 657 | * the meantime, and that there is an IRQ pending. The IRQ | ||
| 658 | * would then be taken in NMI context, something that nobody | ||
| 659 | * wants to debug twice. | ||
| 660 | * | ||
| 661 | * Until we sort this, drop PMR again to a level that will | ||
| 662 | * actually only allow NMIs before reading IAR, and then | ||
| 663 | * restore it to what it was. | ||
| 664 | */ | ||
| 665 | pmr = gic_read_pmr(); | ||
| 666 | gic_pmr_mask_irqs(); | ||
| 667 | isb(); | ||
| 668 | |||
| 669 | iar = gic_read_iar(); | ||
| 670 | |||
| 671 | gic_write_pmr(pmr); | ||
| 672 | } else { | ||
| 673 | iar = gic_read_iar(); | ||
| 674 | } | ||
| 675 | |||
| 676 | return iar; | ||
| 677 | } | ||
| 678 | |||
| 645 | static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) | 679 | static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) |
| 646 | { | 680 | { |
| 647 | u32 irqnr; | 681 | u32 irqnr; |
| 648 | 682 | ||
| 649 | irqnr = gic_read_iar(); | 683 | irqnr = do_read_iar(regs); |
| 650 | 684 | ||
| 651 | /* Check for special IDs first */ | 685 | /* Check for special IDs first */ |
| 652 | if ((irqnr >= 1020 && irqnr <= 1023)) | 686 | if ((irqnr >= 1020 && irqnr <= 1023)) |