[prev in list] [next in list] [prev in thread] [next in thread] 

List:       git-commits-head
Subject:    x86/ioapic: Unbreak check_timer()
From:       Linux Kernel Mailing List <linux-kernel () vger ! kernel ! org>
Date:       2020-09-27 19:34:09
Message-ID: git-mailbomb-linux-master-86a82ae0b5095ea24c55898a3f025791e7958b21 () kernel ! org
[Download RAW message or body]

Commit:     86a82ae0b5095ea24c55898a3f025791e7958b21
Parent:     a7b3474cbb2864d5500d5e4f48dd57c903975cab
Refname:    refs/heads/master
Web:        https://git.kernel.org/torvalds/c/86a82ae0b5095ea24c55898a3f025791e7958b21
Author:     Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Wed Sep 23 17:46:20 2020 +0200
Committer:  Thomas Gleixner <tglx@linutronix.de>
CommitDate: Wed Sep 23 22:44:56 2020 +0200

    x86/ioapic: Unbreak check_timer()
    
    Several people reported in the kernel bugzilla that between v4.12 and v4.13
    the magic which works around broken hardware and BIOSes to find the proper
    timer interrupt delivery mode stopped working for some older affected
    platforms which need to fall back to ExtINT delivery mode.
    
    The reason is that the core code changed to keep track of the masked and
    disabled state of an interrupt line more accurately to avoid the expensive
    hardware operations.
    
    That broke an assumption in i8259_make_irq() which invokes
    
         disable_irq_nosync();
         irq_set_chip_and_handler();
         enable_irq();
    
    Up to v4.12 this worked because enable_irq() unconditionally unmasked the
    interrupt line, but after the state tracking improvements this is not
    longer the case because the IO/APIC uses lazy disabling. So the line state
    is unmasked which means that enable_irq() does not call into the new irq
    chip to unmask it.
    
    In principle this is a shortcoming of the core code, but it's more than
    unclear whether the core code should try to reset state. At least this
    cannot be done unconditionally as that would break other existing use cases
    where the chip type is changed, e.g. when changing the trigger type, but
    the callers expect the state to be preserved.
    
    As the way how check_timer() is switching the delivery modes is truly
    unique, the obvious fix is to simply unmask the i8259 manually after
    changing the mode to ExtINT delivery and switching the irq chip to the
    legacy PIC.
    
    Note, that the fixes tag is not really precise, but identifies the commit
    which broke the assumptions in the IO/APIC and i8259 code and that's the
    kernel version to which this needs to be backported.
    
    Fixes: bf22ff45bed6 ("genirq: Avoid unnecessary low level irq function calls")
    Reported-by: p_c_chan@hotmail.com
    Reported-by: ecm4@mail.com
    Reported-by: perdigao1@yahoo.com
    Reported-by: matzes@users.sourceforge.net
    Reported-by: rvelascog@gmail.com
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Tested-by: p_c_chan@hotmail.com
    Tested-by: matzes@users.sourceforge.net
    Cc: stable@vger.kernel.org
    Link: https://bugzilla.kernel.org/show_bug.cgi?id=197769
---
 arch/x86/kernel/apic/io_apic.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 779a89e31c4c..21f9c7f11779 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -2243,6 +2243,7 @@ static inline void __init check_timer(void)
 	legacy_pic->init(0);
 	legacy_pic->make_irq(0);
 	apic_write(APIC_LVT0, APIC_DM_EXTINT);
+	legacy_pic->unmask(0);
 
 	unlock_ExtINT_logic();
 
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic