Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2b36db6 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by Linus Torvalds
Browse files

[PATCH] i386: move apic init in init_IRQs



All kinds of ugliness exists because we don't initialize
the apics during init_IRQs.
- We calibrate jiffies in non apic mode even when we are using apics.
- We have to have special code to initialize the apics when non-smp.
- The legacy i8259 must exist and be setup correctly, even
  when we won't use it past initialization.
- The kexec on panic code must restore the state of the io_apics.
- init/main.c needs a special case for !smp smp_init on x86

In addition to pure code movement I needed a couple
of non-obvious changes:
- Move setup_boot_APIC_clock into APIC_late_time_init for
  simplicity.
- Use cpu_khz to generate a better approximation of loops_per_jiffies
  so I can verify the timer interrupt is working.
- Call setup_apic_nmi_watchdog again after cpu_khz is initialized on
  the boot cpu.

Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 29b70081
Loading
Loading
Loading
Loading
+64 −17
Original line number Diff line number Diff line
@@ -803,6 +803,7 @@ static int __init detect_init_APIC (void)

void __init init_apic_mappings(void)
{
	unsigned int orig_apicid;
	unsigned long apic_phys;

	/*
@@ -824,8 +825,11 @@ void __init init_apic_mappings(void)
	 * Fetch the APIC ID of the BSP in case we have a
	 * default configuration (or the MP table is broken).
	 */
	if (boot_cpu_physical_apicid == -1U)
	orig_apicid = boot_cpu_physical_apicid;
	boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
	if ((orig_apicid != -1U) && (orig_apicid != boot_cpu_physical_apicid))
		printk(KERN_WARNING "Boot APIC ID in local APIC unexpected (%d vs %d)",
			orig_apicid, boot_cpu_physical_apicid);

#ifdef CONFIG_X86_IO_APIC
	{
@@ -1046,9 +1050,11 @@ static unsigned int calibration_result;

void __init setup_boot_APIC_clock(void)
{
	unsigned long flags;
	apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n");
	using_apic_timer = 1;

	local_irq_save(flags);
	local_irq_disable();

	calibration_result = calibrate_APIC_clock();
@@ -1057,7 +1063,7 @@ void __init setup_boot_APIC_clock(void)
	 */
	setup_APIC_timer(calibration_result);

	local_irq_enable();
	local_irq_restore(flags);
}

void __devinit setup_secondary_APIC_clock(void)
@@ -1254,40 +1260,81 @@ fastcall void smp_error_interrupt(struct pt_regs *regs)
}

/*
 * This initializes the IO-APIC and APIC hardware if this is
 * a UP kernel.
 * This initializes the IO-APIC and APIC hardware.
 */
int __init APIC_init_uniprocessor (void)
int __init APIC_init(void)
{
	if (enable_local_apic < 0)
		clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
	if (enable_local_apic < 0) {
		printk(KERN_INFO "APIC disabled\n");
		return -1;
	}

	if (!smp_found_config && !cpu_has_apic)
	/* See if we have a SMP configuration or have forced enabled
	 * the local apic.
	 */
	if (!smp_found_config && !acpi_lapic && !cpu_has_apic) {
		enable_local_apic = -1;
		return -1;
	}

	/*
	 * Complain if the BIOS pretends there is one.
	 * Complain if the BIOS pretends there is an apic.
	 * Then get out because we don't have an a local apic.
	 */
	if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
			boot_cpu_physical_apicid);
		printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
		enable_local_apic = -1;
		return -1;
	}

	verify_local_APIC();

	connect_bsp_APIC();

	phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
	/*
	 * Should not be necessary because the MP table should list the boot
	 * CPU too, but we do it for the sake of robustness anyway.
	 * Makes no sense to do this check in clustered apic mode, so skip it
	 */
	if (!check_phys_apicid_present(boot_cpu_physical_apicid)) {
		printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
				boot_cpu_physical_apicid);
		physid_set(hard_smp_processor_id(), phys_cpu_present_map);
	}

	/*
	 * Switch from PIC to APIC mode.
	 */
	connect_bsp_APIC();
	setup_local_APIC();

#ifdef CONFIG_X86_IO_APIC
	if (smp_found_config)
		if (!skip_ioapic_setup && nr_ioapics)
	/*
	 * Now start the IO-APICs
	 */
	if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
		setup_IO_APIC();
#endif
	setup_boot_APIC_clock();

	return 0;
}

void __init APIC_late_time_init(void)
{
	/* Improve our loops per jiffy estimate */
	loops_per_jiffy = ((1000 + HZ - 1)/HZ)*cpu_khz;
	boot_cpu_data.loops_per_jiffy = loops_per_jiffy;
	cpu_data[0].loops_per_jiffy = loops_per_jiffy;

	/* setup_apic_nmi_watchdog doesn't work properly before cpu_khz is
	 * initialized.  So redo it here to ensure the boot cpu is setup
	 * properly.
	 */
	if (nmi_watchdog == NMI_LOCAL_APIC)
		setup_apic_nmi_watchdog();

#ifdef CONFIG_X86_IO_APIC
	if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
		IO_APIC_late_time_init();
#endif
	setup_boot_APIC_clock();
}
+4 −0
Original line number Diff line number Diff line
@@ -435,4 +435,8 @@ void __init init_IRQ(void)
		setup_irq(FPU_IRQ, &fpu_irq);

	irq_ctx_init(smp_processor_id());

#ifdef CONFIG_X86_LOCAL_APIC
	APIC_init();
#endif
}
+5 −1
Original line number Diff line number Diff line
@@ -2387,11 +2387,15 @@ void __init setup_IO_APIC(void)
	sync_Arb_IDs();
	setup_IO_APIC_irqs();
	init_IO_APIC_traps();
	check_timer();
	if (!acpi_ioapic)
		print_IO_APIC();
}

void __init IO_APIC_late_time_init(void)
{
	check_timer();
}

/*
 *	Called after all the initialization is done. If we didnt find any
 *	APIC bugs then we can allow the modify fast path
+16 −52
Original line number Diff line number Diff line
@@ -1078,6 +1078,16 @@ void *xquad_portio;
EXPORT_SYMBOL(xquad_portio);
#endif

/*
 * Fall back to non SMP mode after errors.
 *
 */
static __init void disable_smp(void)
{
	cpu_set(0, cpu_sibling_map[0]);
	cpu_set(0, cpu_core_map[0]);
}

static void __init smp_boot_cpus(unsigned int max_cpus)
{
	int apicid, cpu, bit, kicked;
@@ -1090,7 +1100,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
	printk("CPU%d: ", 0);
	print_cpu_info(&cpu_data[0]);

	boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
	boot_cpu_logical_apicid = logical_smp_processor_id();
	x86_cpu_to_apicid[0] = boot_cpu_physical_apicid;

@@ -1102,68 +1111,27 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
	cpus_clear(cpu_core_map[0]);
	cpu_set(0, cpu_core_map[0]);

	map_cpu_to_logical_apicid();

	/*
	 * If we couldn't find an SMP configuration at boot time,
	 * get out of here now!
	 */
	if (!smp_found_config && !acpi_lapic) {
		printk(KERN_NOTICE "SMP motherboard not detected.\n");
		smpboot_clear_io_apic_irqs();
		phys_cpu_present_map = physid_mask_of_physid(0);
		if (APIC_init_uniprocessor())
			printk(KERN_NOTICE "Local APIC not detected."
					   " Using dummy APIC emulation.\n");
		map_cpu_to_logical_apicid();
		cpu_set(0, cpu_sibling_map[0]);
		cpu_set(0, cpu_core_map[0]);
		disable_smp();
		return;
	}

	/*
	 * Should not be necessary because the MP table should list the boot
	 * CPU too, but we do it for the sake of robustness anyway.
	 * Makes no sense to do this check in clustered apic mode, so skip it
	 */
	if (!check_phys_apicid_present(boot_cpu_physical_apicid)) {
		printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
				boot_cpu_physical_apicid);
		physid_set(hard_smp_processor_id(), phys_cpu_present_map);
	}

	/*
	 * If we couldn't find a local APIC, then get out of here now!
	 */
	if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) {
		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
			boot_cpu_physical_apicid);
		printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
		smpboot_clear_io_apic_irqs();
		phys_cpu_present_map = physid_mask_of_physid(0);
		cpu_set(0, cpu_sibling_map[0]);
		cpu_set(0, cpu_core_map[0]);
		return;
	}

	verify_local_APIC();

	/*
	 * If SMP should be disabled, then really disable it!
	 */
	if (!max_cpus) {
		smp_found_config = 0;
		printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
		smpboot_clear_io_apic_irqs();
		phys_cpu_present_map = physid_mask_of_physid(0);
		cpu_set(0, cpu_sibling_map[0]);
		cpu_set(0, cpu_core_map[0]);
	if (!max_cpus || (enable_local_apic < 0)) {
		printk(KERN_INFO "SMP mode deactivated.\n");
		disable_smp();
		return;
	}

	connect_bsp_APIC();
	setup_local_APIC();
	map_cpu_to_logical_apicid();


	setup_portio_remap();

	/*
@@ -1244,10 +1212,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
	cpu_set(0, cpu_sibling_map[0]);
	cpu_set(0, cpu_core_map[0]);

	smpboot_setup_io_apic();

	setup_boot_APIC_clock();

	/*
	 * Synchronize the TSC with the AP
	 */
+11 −1
Original line number Diff line number Diff line
@@ -444,8 +444,8 @@ static int time_init_device(void)

device_initcall(time_init_device);

#ifdef CONFIG_HPET_TIMER
extern void (*late_time_init)(void);
#ifdef CONFIG_HPET_TIMER
/* Duplicate of time_init() below, with hpet_enable part added */
static void __init hpet_time_init(void)
{
@@ -462,6 +462,11 @@ static void __init hpet_time_init(void)
	printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);

	time_init_hook();

#ifdef CONFIG_X86_LOCAL_APIC
	if (enable_local_apic >= 0)
		APIC_late_time_init();
#endif
}
#endif

@@ -486,4 +491,9 @@ void __init time_init(void)
	printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);

	time_init_hook();

#ifdef CONFIG_X86_LOCAL_APIC
	if (enable_local_apic >= 0)
		late_time_init = APIC_late_time_init;
#endif
}
Loading