Commit 2451d1e5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 67dbfc14 e25283bf
Loading
Loading
Loading
Loading
+1 −17
Original line number Diff line number Diff line
@@ -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);
+6 −4
Original line number Diff line number Diff line
@@ -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

+0 −10
Original line number Diff line number Diff line
@@ -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 */
+4 −4
Original line number Diff line number Diff line
@@ -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);
+60 −51
Original line number Diff line number Diff line
@@ -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 {
Loading