Commit 3bbebab1 authored by Dou Liyang's avatar Dou Liyang Committed by Greg Kroah-Hartman

x86/apic: Move pending interrupt check code into it's own function

[ Upstream commit 9b217f33 ]

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: default avatarDou Liyang <douly.fnst@cn.fujitsu.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarAndy 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.comSigned-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 18372c98
...@@ -1281,6 +1281,56 @@ static void lapic_setup_esr(void) ...@@ -1281,6 +1281,56 @@ static void lapic_setup_esr(void)
oldvalue, value); 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 * setup_local_APIC - setup the local APIC
* *
...@@ -1290,13 +1340,11 @@ static void lapic_setup_esr(void) ...@@ -1290,13 +1340,11 @@ static void lapic_setup_esr(void)
void setup_local_APIC(void) void setup_local_APIC(void)
{ {
int cpu = smp_processor_id(); int cpu = smp_processor_id();
unsigned int value, queued; unsigned int value;
int i, j, acked = 0; #ifdef CONFIG_X86_32
unsigned long long tsc = 0, ntsc; int i;
long long max_loops = cpu_khz ? cpu_khz : 1000000; #endif
if (boot_cpu_has(X86_FEATURE_TSC))
tsc = rdtsc();
if (disable_apic) { if (disable_apic) {
disable_ioapic_support(); disable_ioapic_support();
...@@ -1356,45 +1404,7 @@ void setup_local_APIC(void) ...@@ -1356,45 +1404,7 @@ void setup_local_APIC(void)
value &= ~APIC_TPRI_MASK; value &= ~APIC_TPRI_MASK;
apic_write(APIC_TASKPRI, value); apic_write(APIC_TASKPRI, value);
/* apic_pending_intr_clear();
* 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);
/* /*
* Now that we are all set up, enable the APIC * Now that we are all set up, enable the APIC
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment