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

Commit 453c1404 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'x86/apic' into x86/x2apic



Conflicts:

	arch/x86/kernel/paravirt.c
	arch/x86/kernel/smpboot.c
	arch/x86/kernel/vmi_32.c
	arch/x86/lguest/boot.c
	arch/x86/xen/enlighten.c
	include/asm-x86/apic.h
	include/asm-x86/paravirt.h

Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parents a208f37a 35b68055
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -362,10 +362,6 @@ config X86_ALIGNMENT_16
	def_bool y
	depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1

config X86_GOOD_APIC
	def_bool y
	depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON || MCORE2 || MVIAC7 || X86_64

config X86_INTEL_USERCOPY
	def_bool y
	depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2
+87 −83
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE};
/*
 * Debug level, exported for io_apic.c
 */
int apic_verbosity;
unsigned int apic_verbosity;

int pic_mode;

@@ -211,7 +211,7 @@ void __cpuinit enable_NMI_through_LVT0(void)
	/* Level triggered for 82489DX */
	if (!lapic_is_integrated())
		v |= APIC_LVT_LEVEL_TRIGGER;
	apic_write_around(APIC_LVT0, v);
	apic_write(APIC_LVT0, v);
}

/**
@@ -246,9 +246,6 @@ int lapic_get_maxlvt(void)
 * this function twice on the boot CPU, once with a bogus timeout
 * value, second time for real. The other (noncalibrating) CPUs
 * call this function only once, with the real, calibrated value.
 *
 * We do reads before writes even if unnecessary, to get around the
 * P5 APIC double write bug.
 */
static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
{
@@ -263,18 +260,18 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
	if (!irqen)
		lvtt_value |= APIC_LVT_MASKED;

	apic_write_around(APIC_LVTT, lvtt_value);
	apic_write(APIC_LVTT, lvtt_value);

	/*
	 * Divide PICLK by 16
	 */
	tmp_value = apic_read(APIC_TDCR);
	apic_write_around(APIC_TDCR, (tmp_value
				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
				| APIC_TDR_DIV_16);
	apic_write(APIC_TDCR,
		   (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
		   APIC_TDR_DIV_16);

	if (!oneshot)
		apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
		apic_write(APIC_TMICT, clocks / APIC_DIVISOR);
}

/*
@@ -283,7 +280,7 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
static int lapic_next_event(unsigned long delta,
			    struct clock_event_device *evt)
{
	apic_write_around(APIC_TMICT, delta);
	apic_write(APIC_TMICT, delta);
	return 0;
}

@@ -312,7 +309,7 @@ static void lapic_timer_setup(enum clock_event_mode mode,
	case CLOCK_EVT_MODE_SHUTDOWN:
		v = apic_read(APIC_LVTT);
		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
		apic_write_around(APIC_LVTT, v);
		apic_write(APIC_LVTT, v);
		break;
	case CLOCK_EVT_MODE_RESUME:
		/* Nothing to do here */
@@ -406,12 +403,7 @@ static void __init lapic_cal_handler(struct clock_event_device *dev)
	}
}

/*
 * Setup the boot APIC
 *
 * Calibrate and verify the result.
 */
void __init setup_boot_APIC_clock(void)
static int __init calibrate_APIC_clock(void)
{
	struct clock_event_device *levt = &__get_cpu_var(lapic_events);
	const long pm_100ms = PMTMR_TICKS_PER_SEC/10;
@@ -421,24 +413,6 @@ void __init setup_boot_APIC_clock(void)
	long delta, deltapm;
	int pm_referenced = 0;

	/*
	 * The local apic timer can be disabled via the kernel
	 * commandline or from the CPU detection code. Register the lapic
	 * timer as a dummy clock event source on SMP systems, so the
	 * broadcast mechanism is used. On UP systems simply ignore it.
	 */
	if (local_apic_timer_disabled) {
		/* No broadcast on UP ! */
		if (num_possible_cpus() > 1) {
			lapic_clockevent.mult = 1;
			setup_APIC_timer();
		}
		return;
	}

	apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
		    "calibrating APIC timer ...\n");

	local_irq_disable();

	/* Replace the global interrupt handler */
@@ -523,8 +497,6 @@ void __init setup_boot_APIC_clock(void)
		    calibration_result / (1000000 / HZ),
		    calibration_result % (1000000 / HZ));

	local_apic_timer_verify_ok = 1;

	/*
	 * Do a sanity check on the APIC calibration result
	 */
@@ -532,12 +504,11 @@ void __init setup_boot_APIC_clock(void)
		local_irq_enable();
		printk(KERN_WARNING
		       "APIC frequency too slow, disabling apic timer\n");
		/* No broadcast on UP ! */
		if (num_possible_cpus() > 1)
			setup_APIC_timer();
		return;
		return -1;
	}

	local_apic_timer_verify_ok = 1;

	/* We trust the pm timer based calibration */
	if (!pm_referenced) {
		apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
@@ -577,10 +548,44 @@ void __init setup_boot_APIC_clock(void)
	if (!local_apic_timer_verify_ok) {
		printk(KERN_WARNING
		       "APIC timer disabled due to verification failure.\n");
			return -1;
	}

	return 0;
}

/*
 * Setup the boot APIC
 *
 * Calibrate and verify the result.
 */
void __init setup_boot_APIC_clock(void)
{
	/*
	 * The local apic timer can be disabled via the kernel
	 * commandline or from the CPU detection code. Register the lapic
	 * timer as a dummy clock event source on SMP systems, so the
	 * broadcast mechanism is used. On UP systems simply ignore it.
	 */
	if (local_apic_timer_disabled) {
		/* No broadcast on UP ! */
		if (num_possible_cpus() == 1)
		if (num_possible_cpus() > 1) {
			lapic_clockevent.mult = 1;
			setup_APIC_timer();
		}
		return;
	} else {
	}

	apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
		    "calibrating APIC timer ...\n");

	if (calibrate_APIC_clock()) {
		/* No broadcast on UP ! */
		if (num_possible_cpus() > 1)
			setup_APIC_timer();
		return;
	}

	/*
	 * If nmi_watchdog is set to IO_APIC, we need the
	 * PIT/HPET going.  Otherwise register lapic as a dummy
@@ -591,7 +596,6 @@ void __init setup_boot_APIC_clock(void)
	else
		printk(KERN_WARNING "APIC timer registered as dummy,"
			" due to nmi_watchdog=%d!\n", nmi_watchdog);
	}

	/* Setup the lapic or request the broadcast */
	setup_APIC_timer();
@@ -727,44 +731,44 @@ void clear_local_APIC(void)
	 */
	if (maxlvt >= 3) {
		v = ERROR_APIC_VECTOR; /* any non-zero vector will do */
		apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
		apic_write(APIC_LVTERR, v | APIC_LVT_MASKED);
	}
	/*
	 * Careful: we have to set masks only first to deassert
	 * any level-triggered sources.
	 */
	v = apic_read(APIC_LVTT);
	apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
	apic_write(APIC_LVTT, v | APIC_LVT_MASKED);
	v = apic_read(APIC_LVT0);
	apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
	apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
	v = apic_read(APIC_LVT1);
	apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);
	apic_write(APIC_LVT1, v | APIC_LVT_MASKED);
	if (maxlvt >= 4) {
		v = apic_read(APIC_LVTPC);
		apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
		apic_write(APIC_LVTPC, v | APIC_LVT_MASKED);
	}

	/* lets not touch this if we didn't frob it */
#ifdef CONFIG_X86_MCE_P4THERMAL
	if (maxlvt >= 5) {
		v = apic_read(APIC_LVTTHMR);
		apic_write_around(APIC_LVTTHMR, v | APIC_LVT_MASKED);
		apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
	}
#endif
	/*
	 * Clean APIC state for other OSs:
	 */
	apic_write_around(APIC_LVTT, APIC_LVT_MASKED);
	apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
	apic_write_around(APIC_LVT1, APIC_LVT_MASKED);
	apic_write(APIC_LVTT, APIC_LVT_MASKED);
	apic_write(APIC_LVT0, APIC_LVT_MASKED);
	apic_write(APIC_LVT1, APIC_LVT_MASKED);
	if (maxlvt >= 3)
		apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
		apic_write(APIC_LVTERR, APIC_LVT_MASKED);
	if (maxlvt >= 4)
		apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
		apic_write(APIC_LVTPC, APIC_LVT_MASKED);

#ifdef CONFIG_X86_MCE_P4THERMAL
	if (maxlvt >= 5)
		apic_write_around(APIC_LVTTHMR, APIC_LVT_MASKED);
		apic_write(APIC_LVTTHMR, APIC_LVT_MASKED);
#endif
	/* Integrated APIC (!82489DX) ? */
	if (lapic_is_integrated()) {
@@ -790,7 +794,7 @@ void disable_local_APIC(void)
	 */
	value = apic_read(APIC_SPIV);
	value &= ~APIC_SPIV_APIC_ENABLED;
	apic_write_around(APIC_SPIV, value);
	apic_write(APIC_SPIV, value);

	/*
	 * When LAPIC was disabled by the BIOS and enabled by the kernel,
@@ -899,8 +903,8 @@ void __init sync_Arb_IDs(void)
	apic_wait_icr_idle();

	apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");
	apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG
				| APIC_DM_INIT);
	apic_write(APIC_ICR,
		   APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT);
}

/*
@@ -936,16 +940,16 @@ void __init init_bsp_APIC(void)
	else
		value |= APIC_SPIV_FOCUS_DISABLED;
	value |= SPURIOUS_APIC_VECTOR;
	apic_write_around(APIC_SPIV, value);
	apic_write(APIC_SPIV, value);

	/*
	 * Set up the virtual wire mode.
	 */
	apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
	apic_write(APIC_LVT0, APIC_DM_EXTINT);
	value = APIC_DM_NMI;
	if (!lapic_is_integrated())		/* 82489DX */
		value |= APIC_LVT_LEVEL_TRIGGER;
	apic_write_around(APIC_LVT1, value);
	apic_write(APIC_LVT1, value);
}

static void __cpuinit lapic_setup_esr(void)
@@ -960,7 +964,7 @@ static void __cpuinit lapic_setup_esr(void)

		/* enables sending errors */
		value = ERROR_APIC_VECTOR;
		apic_write_around(APIC_LVTERR, value);
		apic_write(APIC_LVTERR, value);
		/*
		 * spec says clear errors after enabling vector.
		 */
@@ -1023,7 +1027,7 @@ void __cpuinit setup_local_APIC(void)
	 */
	value = apic_read(APIC_TASKPRI);
	value &= ~APIC_TPRI_MASK;
	apic_write_around(APIC_TASKPRI, value);
	apic_write(APIC_TASKPRI, value);

	/*
	 * After a crash, we no longer service the interrupts and a pending
@@ -1081,7 +1085,7 @@ void __cpuinit setup_local_APIC(void)
	 * Set spurious IRQ vector
	 */
	value |= SPURIOUS_APIC_VECTOR;
	apic_write_around(APIC_SPIV, value);
	apic_write(APIC_SPIV, value);

	/*
	 * Set up LVT0, LVT1:
@@ -1103,7 +1107,7 @@ void __cpuinit setup_local_APIC(void)
		apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n",
				smp_processor_id());
	}
	apic_write_around(APIC_LVT0, value);
	apic_write(APIC_LVT0, value);

	/*
	 * only the BP should see the LINT1 NMI signal, obviously.
@@ -1114,7 +1118,7 @@ void __cpuinit setup_local_APIC(void)
		value = APIC_DM_NMI | APIC_LVT_MASKED;
	if (!integrated)		/* 82489DX */
		value |= APIC_LVT_LEVEL_TRIGGER;
	apic_write_around(APIC_LVT1, value);
	apic_write(APIC_LVT1, value);
}

void __cpuinit end_local_APIC_setup(void)
@@ -1125,7 +1129,7 @@ void __cpuinit end_local_APIC_setup(void)
	/* Disable the local apic timer */
	value = apic_read(APIC_LVTT);
	value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
	apic_write_around(APIC_LVTT, value);
	apic_write(APIC_LVTT, value);

	setup_apic_nmi_watchdog(NULL);
	apic_pm_activate();
@@ -1453,7 +1457,7 @@ void disconnect_bsp_APIC(int virt_wire_setup)
		value &= ~APIC_VECTOR_MASK;
		value |= APIC_SPIV_APIC_ENABLED;
		value |= 0xf;
		apic_write_around(APIC_SPIV, value);
		apic_write(APIC_SPIV, value);

		if (!virt_wire_setup) {
			/*
@@ -1466,10 +1470,10 @@ void disconnect_bsp_APIC(int virt_wire_setup)
				APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
			value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
			value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
			apic_write_around(APIC_LVT0, value);
			apic_write(APIC_LVT0, value);
		} else {
			/* Disable LVT0 */
			apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
			apic_write(APIC_LVT0, APIC_LVT_MASKED);
		}

		/*
@@ -1483,7 +1487,7 @@ void disconnect_bsp_APIC(int virt_wire_setup)
			APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
		value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
		value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
		apic_write_around(APIC_LVT1, value);
		apic_write(APIC_LVT1, value);
	}
}

+14 −10
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
/*
 * Debug level, exported for io_apic.c
 */
int apic_verbosity;
unsigned int apic_verbosity;

/* Have we found an MP table */
int smp_found_config;
@@ -386,7 +386,7 @@ static void setup_APIC_timer(void)

#define TICK_COUNT 100000000

static void __init calibrate_APIC_clock(void)
static int __init calibrate_APIC_clock(void)
{
	unsigned apic, apic_start;
	unsigned long tsc, tsc_start;
@@ -440,6 +440,17 @@ static void __init calibrate_APIC_clock(void)
		clockevent_delta2ns(0xF, &lapic_clockevent);

	calibration_result = result / HZ;

	/*
	 * Do a sanity check on the APIC calibration result
	 */
	if (calibration_result < (1000000 / HZ)) {
		printk(KERN_WARNING
			"APIC frequency too slow, disabling apic timer\n");
		return -1;
	}

	return 0;
}

/*
@@ -466,14 +477,7 @@ void __init setup_boot_APIC_clock(void)
	}

	printk(KERN_INFO "Using local APIC timer interrupts.\n");
	calibrate_APIC_clock();

	/*
	 * Do a sanity check on the APIC calibration result
	 */
	if (calibration_result < (1000000 / HZ)) {
		printk(KERN_WARNING
		       "APIC frequency too slow, disabling apic timer\n");
	if (calibrate_APIC_clock()) {
		/* No broadcast on UP ! */
		if (num_possible_cpus() > 1)
			setup_APIC_timer();
+1 −22
Original line number Diff line number Diff line
@@ -131,12 +131,6 @@ static void __init check_popad(void)
 *   (for due to lack of "invlpg" and working WP on a i386)
 * - In order to run on anything without a TSC, we need to be
 *   compiled for a i486.
 * - In order to support the local APIC on a buggy Pentium machine,
 *   we need to be compiled with CONFIG_X86_GOOD_APIC disabled,
 *   which happens implicitly if compiled for a Pentium or lower
 *   (unless an advanced selection of CPU features is used) as an
 *   otherwise config implies a properly working local APIC without
 *   the need to do extra reads from the APIC.
 */

static void __init check_config(void)
@@ -151,21 +145,6 @@ static void __init check_config(void)
	if (boot_cpu_data.x86 == 3)
		panic("Kernel requires i486+ for 'invlpg' and other features");
#endif

/*
 * If we were told we had a good local APIC, check for buggy Pentia,
 * i.e. all B steppings and the C2 stepping of P54C when using their
 * integrated APIC (see 11AP erratum in "Pentium Processor
 * Specification Update").
 */
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
	    && cpu_has_apic
	    && boot_cpu_data.x86 == 5
	    && boot_cpu_data.x86_model == 2
	    && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
		panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!");
#endif
}


+10 −0
Original line number Diff line number Diff line
@@ -227,6 +227,16 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
	if (cpu_has_bts)
		ds_init_intel(c);

	/*
	 * See if we have a good local APIC by checking for buggy Pentia,
	 * i.e. all B steppings and the C2 stepping of P54C when using their
	 * integrated APIC (see 11AP erratum in "Pentium Processor
	 * Specification Update").
	 */
	if (cpu_has_apic && (c->x86<<8 | c->x86_model<<4) == 0x520 &&
	    (c->x86_mask < 0x6 || c->x86_mask == 0xb))
		set_cpu_cap(c, X86_FEATURE_11AP);

#ifdef CONFIG_X86_NUMAQ
	numaq_tsc_disable();
#endif
Loading