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:
commit
2451d1e59d
|
@ -138,7 +138,6 @@ extern void lapic_shutdown(void);
|
|||
extern void sync_Arb_IDs(void);
|
||||
extern void init_bsp_APIC(void);
|
||||
extern void apic_intr_mode_init(void);
|
||||
extern void setup_local_APIC(void);
|
||||
extern void init_apic_mappings(void);
|
||||
void register_lapic_address(unsigned long address);
|
||||
extern void setup_boot_APIC_clock(void);
|
||||
|
@ -183,6 +182,7 @@ static inline void disable_local_APIC(void) { }
|
|||
# define setup_boot_APIC_clock x86_init_noop
|
||||
# define setup_secondary_APIC_clock x86_init_noop
|
||||
static inline void lapic_update_tsc_freq(void) { }
|
||||
static inline void init_bsp_APIC(void) { }
|
||||
static inline void apic_intr_mode_init(void) { }
|
||||
static inline void lapic_assign_system_vectors(void) { }
|
||||
static inline void lapic_assign_legacy_vector(unsigned int i, bool r) { }
|
||||
|
@ -304,12 +304,6 @@ struct apic {
|
|||
u32 irq_delivery_mode;
|
||||
u32 irq_dest_mode;
|
||||
|
||||
/* Functions and data related to vector allocation */
|
||||
void (*vector_allocation_domain)(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask);
|
||||
int (*cpu_mask_to_apicid)(const struct cpumask *cpumask,
|
||||
struct irq_data *irqdata,
|
||||
unsigned int *apicid);
|
||||
u32 (*calc_dest_apicid)(unsigned int cpu);
|
||||
|
||||
/* ICR related functions */
|
||||
|
@ -499,17 +493,7 @@ extern void default_setup_apic_routing(void);
|
|||
extern u32 apic_default_calc_apicid(unsigned int cpu);
|
||||
extern u32 apic_flat_calc_apicid(unsigned int cpu);
|
||||
|
||||
extern int flat_cpu_mask_to_apicid(const struct cpumask *cpumask,
|
||||
struct irq_data *irqdata,
|
||||
unsigned int *apicid);
|
||||
extern int default_cpu_mask_to_apicid(const struct cpumask *cpumask,
|
||||
struct irq_data *irqdata,
|
||||
unsigned int *apicid);
|
||||
extern bool default_check_apicid_used(physid_mask_t *map, int apicid);
|
||||
extern void flat_vector_allocation_domain(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask);
|
||||
extern void default_vector_allocation_domain(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask);
|
||||
extern void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap);
|
||||
extern int default_cpu_present_to_apicid(int mps_cpu);
|
||||
extern int default_check_phys_apicid_present(int phys_apicid);
|
||||
|
|
|
@ -183,16 +183,17 @@ extern void disable_ioapic_support(void);
|
|||
|
||||
extern void __init io_apic_init_mappings(void);
|
||||
extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
|
||||
extern void native_disable_io_apic(void);
|
||||
extern void native_restore_boot_irq_mode(void);
|
||||
|
||||
static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
|
||||
{
|
||||
return x86_io_apic_ops.read(apic, reg);
|
||||
return x86_apic_ops.io_apic_read(apic, reg);
|
||||
}
|
||||
|
||||
extern void setup_IO_APIC(void);
|
||||
extern void enable_IO_APIC(void);
|
||||
extern void disable_IO_APIC(void);
|
||||
extern void clear_IO_APIC(void);
|
||||
extern void restore_boot_irq_mode(void);
|
||||
extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin);
|
||||
extern void print_IO_APICs(void);
|
||||
#else /* !CONFIG_X86_IO_APIC */
|
||||
|
@ -228,10 +229,11 @@ static inline void mp_save_irq(struct mpc_intsrc *m) { }
|
|||
static inline void disable_ioapic_support(void) { }
|
||||
static inline void io_apic_init_mappings(void) { }
|
||||
#define native_io_apic_read NULL
|
||||
#define native_disable_io_apic NULL
|
||||
#define native_restore_boot_irq_mode NULL
|
||||
|
||||
static inline void setup_IO_APIC(void) { }
|
||||
static inline void enable_IO_APIC(void) { }
|
||||
static inline void restore_boot_irq_mode(void) { }
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -177,16 +177,6 @@ static inline int wbinvd_on_all_cpus(void)
|
|||
extern unsigned disabled_cpus;
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
|
||||
#ifndef CONFIG_X86_64
|
||||
static inline int logical_smp_processor_id(void)
|
||||
{
|
||||
/* we don't want to mark this access volatile - bad code generation */
|
||||
return GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extern int hard_smp_processor_id(void);
|
||||
|
||||
#else /* CONFIG_X86_LOCAL_APIC */
|
||||
|
|
|
@ -274,16 +274,16 @@ struct x86_msi_ops {
|
|||
void (*restore_msi_irqs)(struct pci_dev *dev);
|
||||
};
|
||||
|
||||
struct x86_io_apic_ops {
|
||||
unsigned int (*read) (unsigned int apic, unsigned int reg);
|
||||
void (*disable)(void);
|
||||
struct x86_apic_ops {
|
||||
unsigned int (*io_apic_read) (unsigned int apic, unsigned int reg);
|
||||
void (*restore)(void);
|
||||
};
|
||||
|
||||
extern struct x86_init_ops x86_init;
|
||||
extern struct x86_cpuinit_ops x86_cpuinit;
|
||||
extern struct x86_platform_ops x86_platform;
|
||||
extern struct x86_msi_ops x86_msi;
|
||||
extern struct x86_io_apic_ops x86_io_apic_ops;
|
||||
extern struct x86_apic_ops x86_apic_ops;
|
||||
|
||||
extern void x86_early_init_platform_quirks(void);
|
||||
extern void x86_init_noop(void);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -587,7 +587,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
|
|||
mpc_ioapic_id(apic), pin);
|
||||
}
|
||||
|
||||
static void clear_IO_APIC (void)
|
||||
void clear_IO_APIC (void)
|
||||
{
|
||||
int apic, pin;
|
||||
|
||||
|
@ -1410,7 +1410,7 @@ void __init enable_IO_APIC(void)
|
|||
clear_IO_APIC();
|
||||
}
|
||||
|
||||
void native_disable_io_apic(void)
|
||||
void native_restore_boot_irq_mode(void)
|
||||
{
|
||||
/*
|
||||
* If the i8259 is routed through an IOAPIC
|
||||
|
@ -1438,20 +1438,12 @@ void native_disable_io_apic(void)
|
|||
disconnect_bsp_APIC(ioapic_i8259.pin != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Not an __init, needed by the reboot code
|
||||
*/
|
||||
void disable_IO_APIC(void)
|
||||
void restore_boot_irq_mode(void)
|
||||
{
|
||||
/*
|
||||
* Clear the IO-APIC before rebooting:
|
||||
*/
|
||||
clear_IO_APIC();
|
||||
|
||||
if (!nr_legacy_irqs())
|
||||
return;
|
||||
|
||||
x86_io_apic_ops.disable();
|
||||
x86_apic_ops.restore();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
|
|
@ -14,7 +14,7 @@ int x2apic_phys;
|
|||
|
||||
static struct apic apic_x2apic_phys;
|
||||
|
||||
static int set_x2apic_phys_mode(char *arg)
|
||||
static int __init set_x2apic_phys_mode(char *arg)
|
||||
{
|
||||
x2apic_phys = 1;
|
||||
return 0;
|
||||
|
|
|
@ -199,9 +199,10 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
|
|||
#ifdef CONFIG_X86_IO_APIC
|
||||
/* Prevent crash_kexec() from deadlocking on ioapic_lock. */
|
||||
ioapic_zap_locks();
|
||||
disable_IO_APIC();
|
||||
clear_IO_APIC();
|
||||
#endif
|
||||
lapic_shutdown();
|
||||
restore_boot_irq_mode();
|
||||
#ifdef CONFIG_HPET_TIMER
|
||||
hpet_disable();
|
||||
#endif
|
||||
|
|
|
@ -61,9 +61,14 @@ void __init init_ISA_irqs(void)
|
|||
struct irq_chip *chip = legacy_pic->chip;
|
||||
int i;
|
||||
|
||||
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
|
||||
/*
|
||||
* Try to set up the through-local-APIC virtual wire mode earlier.
|
||||
*
|
||||
* On some 32-bit UP machines, whose APIC has been disabled by BIOS
|
||||
* and then got re-enabled by "lapic", it hangs at boot time without this.
|
||||
*/
|
||||
init_bsp_APIC();
|
||||
#endif
|
||||
|
||||
legacy_pic->init(0);
|
||||
|
||||
for (i = 0; i < nr_legacy_irqs(); i++)
|
||||
|
|
|
@ -195,11 +195,11 @@ void machine_kexec(struct kimage *image)
|
|||
/*
|
||||
* We need to put APICs in legacy mode so that we can
|
||||
* get timer interrupts in second kernel. kexec/kdump
|
||||
* paths already have calls to disable_IO_APIC() in
|
||||
* one form or other. kexec jump path also need
|
||||
* one.
|
||||
* paths already have calls to restore_boot_irq_mode()
|
||||
* in one form or other. kexec jump path also need one.
|
||||
*/
|
||||
disable_IO_APIC();
|
||||
clear_IO_APIC();
|
||||
restore_boot_irq_mode();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -293,11 +293,11 @@ void machine_kexec(struct kimage *image)
|
|||
/*
|
||||
* We need to put APICs in legacy mode so that we can
|
||||
* get timer interrupts in second kernel. kexec/kdump
|
||||
* paths already have calls to disable_IO_APIC() in
|
||||
* one form or other. kexec jump path also need
|
||||
* one.
|
||||
* paths already have calls to restore_boot_irq_mode()
|
||||
* in one form or other. kexec jump path also need one.
|
||||
*/
|
||||
disable_IO_APIC();
|
||||
clear_IO_APIC();
|
||||
restore_boot_irq_mode();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -666,7 +666,7 @@ void native_machine_shutdown(void)
|
|||
* Even without the erratum, it still makes sense to quiet IO APIC
|
||||
* before disabling Local APIC.
|
||||
*/
|
||||
disable_IO_APIC();
|
||||
clear_IO_APIC();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
@ -680,6 +680,7 @@ void native_machine_shutdown(void)
|
|||
#endif
|
||||
|
||||
lapic_shutdown();
|
||||
restore_boot_irq_mode();
|
||||
|
||||
#ifdef CONFIG_HPET_TIMER
|
||||
hpet_disable();
|
||||
|
|
|
@ -146,7 +146,7 @@ void arch_restore_msi_irqs(struct pci_dev *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
struct x86_io_apic_ops x86_io_apic_ops __ro_after_init = {
|
||||
.read = native_io_apic_read,
|
||||
.disable = native_disable_io_apic,
|
||||
struct x86_apic_ops x86_apic_ops __ro_after_init = {
|
||||
.io_apic_read = native_io_apic_read,
|
||||
.restore = native_restore_boot_irq_mode,
|
||||
};
|
||||
|
|
|
@ -215,7 +215,7 @@ static void __init xen_apic_check(void)
|
|||
}
|
||||
void __init xen_init_apic(void)
|
||||
{
|
||||
x86_io_apic_ops.read = xen_io_apic_read;
|
||||
x86_apic_ops.io_apic_read = xen_io_apic_read;
|
||||
/* On PV guests the APIC CPUID bit is disabled so none of the
|
||||
* routines end up executing. */
|
||||
if (!xen_initial_domain())
|
||||
|
|
|
@ -27,7 +27,7 @@ int disable_irq_post = 0;
|
|||
static int disable_irq_remap;
|
||||
static struct irq_remap_ops *remap_ops;
|
||||
|
||||
static void irq_remapping_disable_io_apic(void)
|
||||
static void irq_remapping_restore_boot_irq_mode(void)
|
||||
{
|
||||
/*
|
||||
* With interrupt-remapping, for now we will use virtual wire A
|
||||
|
@ -42,7 +42,7 @@ static void irq_remapping_disable_io_apic(void)
|
|||
|
||||
static void __init irq_remapping_modify_x86_ops(void)
|
||||
{
|
||||
x86_io_apic_ops.disable = irq_remapping_disable_io_apic;
|
||||
x86_apic_ops.restore = irq_remapping_restore_boot_irq_mode;
|
||||
}
|
||||
|
||||
static __init int setup_nointremap(char *str)
|
||||
|
|
Loading…
Reference in New Issue