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

Commit b47dcbdc authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Thomas Gleixner
Browse files

x86, apic: Handle a bad TSC more gracefully



If the TSC is unusable or disabled, then this patch fixes:

 - Confusion while trying to clear old APIC interrupts.
 - Division by zero and incorrect programming of the TSC deadline
   timer.

This fixes boot if the CPU has a TSC deadline timer but a missing or
broken TSC.  The failure to boot can be observed with qemu using
-cpu qemu64,-tsc,+tsc-deadline

This also happens to me in nested KVM for unknown reasons.
With this patch, I can boot cleanly (although without a TSC).

Signed-off-by: default avatarAndy Lutomirski <luto@amacapital.net>
Cc: Bandan Das <bsd@redhat.com>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/e2fa274e498c33988efac0ba8b7e3120f7f92d78.1413393027.git.luto@amacapital.net


Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 961b6a70
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -1297,7 +1297,7 @@ void setup_local_APIC(void)
	unsigned int value, queued;
	unsigned int value, queued;
	int i, j, acked = 0;
	int i, j, acked = 0;
	unsigned long long tsc = 0, ntsc;
	unsigned long long tsc = 0, ntsc;
	long long max_loops = cpu_khz;
	long long max_loops = cpu_khz ? cpu_khz : 1000000;


	if (cpu_has_tsc)
	if (cpu_has_tsc)
		rdtscll(tsc);
		rdtscll(tsc);
@@ -1383,7 +1383,7 @@ void setup_local_APIC(void)
			break;
			break;
		}
		}
		if (queued) {
		if (queued) {
			if (cpu_has_tsc) {
			if (cpu_has_tsc && cpu_khz) {
				rdtscll(ntsc);
				rdtscll(ntsc);
				max_loops = (cpu_khz << 10) - (ntsc - tsc);
				max_loops = (cpu_khz << 10) - (ntsc - tsc);
			} else
			} else
+4 −1
Original line number Original line Diff line number Diff line
@@ -1166,14 +1166,17 @@ void __init tsc_init(void)


	x86_init.timers.tsc_pre_init();
	x86_init.timers.tsc_pre_init();


	if (!cpu_has_tsc)
	if (!cpu_has_tsc) {
		setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
		return;
		return;
	}


	tsc_khz = x86_platform.calibrate_tsc();
	tsc_khz = x86_platform.calibrate_tsc();
	cpu_khz = tsc_khz;
	cpu_khz = tsc_khz;


	if (!tsc_khz) {
	if (!tsc_khz) {
		mark_tsc_unstable("could not calculate TSC khz");
		mark_tsc_unstable("could not calculate TSC khz");
		setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
		return;
		return;
	}
	}