x86/apic: Move pending interrupt check code into it's own function
[ Upstream commit 9b217f33017715903d0956dfc58f82d2a2d00e63 ] The pending interrupt check code is mixed with the local APIC setup code, that looks messy. Extract the related code, move it into a new function named apic_pending_intr_clear(). Signed-off-by: Dou Liyang <douly.fnst@cn.fujitsu.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Cc: bhe@redhat.com Cc: ebiederm@xmission.com Link: https://lkml.kernel.org/r/20180301055930.2396-2-douly.fnst@cn.fujitsu.com Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
f69f2d6119
commit
fe241fe90a
@ -1362,6 +1362,56 @@ static void lapic_setup_esr(void)
|
||||
oldvalue, value);
|
||||
}
|
||||
|
||||
static void apic_pending_intr_clear(void)
|
||||
{
|
||||
long long max_loops = cpu_khz ? cpu_khz : 1000000;
|
||||
unsigned long long tsc = 0, ntsc;
|
||||
unsigned int value, queued;
|
||||
int i, j, acked = 0;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_TSC))
|
||||
tsc = rdtsc();
|
||||
/*
|
||||
* After a crash, we no longer service the interrupts and a pending
|
||||
* interrupt from previous kernel might still have ISR bit set.
|
||||
*
|
||||
* Most probably by now CPU has serviced that pending interrupt and
|
||||
* it might not have done the ack_APIC_irq() because it thought,
|
||||
* interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
|
||||
* does not clear the ISR bit and cpu thinks it has already serivced
|
||||
* the interrupt. Hence a vector might get locked. It was noticed
|
||||
* for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
|
||||
*/
|
||||
do {
|
||||
queued = 0;
|
||||
for (i = APIC_ISR_NR - 1; i >= 0; i--)
|
||||
queued |= apic_read(APIC_IRR + i*0x10);
|
||||
|
||||
for (i = APIC_ISR_NR - 1; i >= 0; i--) {
|
||||
value = apic_read(APIC_ISR + i*0x10);
|
||||
for (j = 31; j >= 0; j--) {
|
||||
if (value & (1<<j)) {
|
||||
ack_APIC_irq();
|
||||
acked++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (acked > 256) {
|
||||
printk(KERN_ERR "LAPIC pending interrupts after %d EOI\n",
|
||||
acked);
|
||||
break;
|
||||
}
|
||||
if (queued) {
|
||||
if (boot_cpu_has(X86_FEATURE_TSC) && cpu_khz) {
|
||||
ntsc = rdtsc();
|
||||
max_loops = (cpu_khz << 10) - (ntsc - tsc);
|
||||
} else
|
||||
max_loops--;
|
||||
}
|
||||
} while (queued && max_loops > 0);
|
||||
WARN_ON(max_loops <= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* setup_local_APIC - setup the local APIC
|
||||
*
|
||||
@ -1371,13 +1421,11 @@ static void lapic_setup_esr(void)
|
||||
void setup_local_APIC(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
unsigned int value, queued;
|
||||
int i, j, acked = 0;
|
||||
unsigned long long tsc = 0, ntsc;
|
||||
long long max_loops = cpu_khz ? cpu_khz : 1000000;
|
||||
unsigned int value;
|
||||
#ifdef CONFIG_X86_32
|
||||
int i;
|
||||
#endif
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_TSC))
|
||||
tsc = rdtsc();
|
||||
|
||||
if (disable_apic) {
|
||||
disable_ioapic_support();
|
||||
@ -1437,45 +1485,7 @@ void setup_local_APIC(void)
|
||||
value &= ~APIC_TPRI_MASK;
|
||||
apic_write(APIC_TASKPRI, value);
|
||||
|
||||
/*
|
||||
* After a crash, we no longer service the interrupts and a pending
|
||||
* interrupt from previous kernel might still have ISR bit set.
|
||||
*
|
||||
* Most probably by now CPU has serviced that pending interrupt and
|
||||
* it might not have done the ack_APIC_irq() because it thought,
|
||||
* interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
|
||||
* does not clear the ISR bit and cpu thinks it has already serivced
|
||||
* the interrupt. Hence a vector might get locked. It was noticed
|
||||
* for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
|
||||
*/
|
||||
do {
|
||||
queued = 0;
|
||||
for (i = APIC_ISR_NR - 1; i >= 0; i--)
|
||||
queued |= apic_read(APIC_IRR + i*0x10);
|
||||
|
||||
for (i = APIC_ISR_NR - 1; i >= 0; i--) {
|
||||
value = apic_read(APIC_ISR + i*0x10);
|
||||
for (j = 31; j >= 0; j--) {
|
||||
if (value & (1<<j)) {
|
||||
ack_APIC_irq();
|
||||
acked++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (acked > 256) {
|
||||
printk(KERN_ERR "LAPIC pending interrupts after %d EOI\n",
|
||||
acked);
|
||||
break;
|
||||
}
|
||||
if (queued) {
|
||||
if (boot_cpu_has(X86_FEATURE_TSC) && cpu_khz) {
|
||||
ntsc = rdtsc();
|
||||
max_loops = (cpu_khz << 10) - (ntsc - tsc);
|
||||
} else
|
||||
max_loops--;
|
||||
}
|
||||
} while (queued && max_loops > 0);
|
||||
WARN_ON(max_loops <= 0);
|
||||
apic_pending_intr_clear();
|
||||
|
||||
/*
|
||||
* Now that we are all set up, enable the APIC
|
||||
|
Loading…
x
Reference in New Issue
Block a user