Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 apic updates from Ingo Molnar:
 "The main x86 APIC/IOAPIC changes in this cycle were:

   - Robustify kexec support to more carefully restore IRQ hardware
     state before calling into kexec/kdump kernels. (Baoquan He)

   - Clean up the local APIC code a bit (Dou Liyang)

   - Remove unused callbacks (David Rientjes)"

* 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/apic: Finish removing unused callbacks
  x86/apic: Drop logical_smp_processor_id() inline
  x86/apic: Modernize the pending interrupt code
  x86/apic: Move pending interrupt check code into it's own function
  x86/apic: Set up through-local-APIC mode on the boot CPU if 'noapic' specified
  x86/apic: Rename variables and functions related to x86_io_apic_ops
  x86/apic: Remove the (now) unused disable_IO_APIC() function
  x86/apic: Fix restoring boot IRQ mode in reboot and kexec/kdump
  x86/apic: Split disable_IO_APIC() into two functions to fix CONFIG_KEXEC_JUMP=y
  x86/apic: Split out restore_boot_irq_mode() from disable_IO_APIC()
  x86/apic: Make setup_local_APIC() static
  x86/apic: Simplify init_bsp_APIC() usage
  x86/x2apic: Mark set_x2apic_phys_mode() as __init
This commit is contained in:
Linus Torvalds
2018-04-02 13:38:43 -07:00
15 changed files with 101 additions and 117 deletions

View File

@@ -1408,22 +1408,69 @@ 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 queued;
unsigned long value;
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_each_set_bit(j, &value, 32) {
ack_APIC_irq();
acked++;
}
}
if (acked > 256) {
pr_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
*
* Used to setup local APIC while initializing BSP or bringing up APs.
* Always called with preemption disabled.
*/
void setup_local_APIC(void)
static 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 logical_apicid, ldr_apicid;
#endif
if (boot_cpu_has(X86_FEATURE_TSC))
tsc = rdtsc();
if (disable_apic) {
disable_ioapic_support();
@@ -1460,11 +1507,11 @@ void setup_local_APIC(void)
* initialized during get_smp_config(), make sure it matches the
* actual value.
*/
i = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
WARN_ON(i != BAD_APICID && i != logical_smp_processor_id());
logical_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
ldr_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
WARN_ON(logical_apicid != BAD_APICID && logical_apicid != ldr_apicid);
/* always use the value from LDR */
early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
logical_smp_processor_id();
early_per_cpu(x86_cpu_to_logical_apicid, cpu) = ldr_apicid;
#endif
/*
@@ -1475,45 +1522,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
@@ -1570,7 +1579,7 @@ void setup_local_APIC(void)
* TODO: set up through-local-APIC from through-I/O-APIC? --macro
*/
value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
if (!cpu && (pic_mode || !value)) {
if (!cpu && (pic_mode || !value || skip_ioapic_setup)) {
value = APIC_DM_EXTINT;
apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", cpu);
} else {