| From 43c5bc86ff3b972a87131762fb963f10ce81981b Mon Sep 17 00:00:00 2001 |
| From: Hans de Goede <hdegoede@redhat.com> |
| Date: Sun, 23 Feb 2020 15:06:09 +0100 |
| Subject: [PATCH] x86/tsc_msr: Fix MSR_FSB_FREQ mask for Cherry Trail devices |
| |
| commit c8810e2ffc30c7e1577f9c057c4b85d984bbc35a upstream. |
| |
| According to the "Intel 64 and IA-32 Architectures Software Developer's |
| Manual Volume 4: Model-Specific Registers" on Cherry Trail (Airmont) |
| devices the 4 lowest bits of the MSR_FSB_FREQ mask indicate the bus freq |
| unlike on e.g. Bay Trail where only the lowest 3 bits are used. |
| |
| This is also the reason why MAX_NUM_FREQS is defined as 9, since Cherry |
| Trail SoCs have 9 possible frequencies, so the lo value from the MSR needs |
| to be masked with 0x0f, not with 0x07 otherwise the 9th frequency will get |
| interpreted as the 1st. |
| |
| Bump MAX_NUM_FREQS to 16 to avoid any possibility of addressing the array |
| out of bounds and makes the mask part of the cpufreq struct so it can be |
| set it per model. |
| |
| While at it also log an error when the index points to an uninitialized |
| part of the freqs lookup-table. |
| |
| Signed-off-by: Hans de Goede <hdegoede@redhat.com> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Cc: stable@vger.kernel.org |
| Link: https://lkml.kernel.org/r/20200223140610.59612-2-hdegoede@redhat.com |
| [PG: no freq_desc_lgm in older v5.2.x code base.] |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c |
| index 5b4672f86c27..e843ad2b92ad 100644 |
| --- a/arch/x86/kernel/tsc_msr.c |
| +++ b/arch/x86/kernel/tsc_msr.c |
| @@ -15,7 +15,7 @@ |
| #include <asm/param.h> |
| #include <asm/tsc.h> |
| |
| -#define MAX_NUM_FREQS 9 |
| +#define MAX_NUM_FREQS 16 /* 4 bits to select the frequency */ |
| |
| /* |
| * If MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be |
| @@ -27,6 +27,7 @@ |
| struct freq_desc { |
| bool use_msr_plat; |
| u32 freqs[MAX_NUM_FREQS]; |
| + u32 mask; |
| }; |
| |
| /* |
| @@ -37,32 +38,38 @@ struct freq_desc { |
| static const struct freq_desc freq_desc_pnw = { |
| .use_msr_plat = false, |
| .freqs = { 0, 0, 0, 0, 0, 99840, 0, 83200 }, |
| + .mask = 0x07, |
| }; |
| |
| static const struct freq_desc freq_desc_clv = { |
| .use_msr_plat = false, |
| .freqs = { 0, 133200, 0, 0, 0, 99840, 0, 83200 }, |
| + .mask = 0x07, |
| }; |
| |
| static const struct freq_desc freq_desc_byt = { |
| .use_msr_plat = true, |
| .freqs = { 83300, 100000, 133300, 116700, 80000, 0, 0, 0 }, |
| + .mask = 0x07, |
| }; |
| |
| static const struct freq_desc freq_desc_cht = { |
| .use_msr_plat = true, |
| .freqs = { 83300, 100000, 133300, 116700, 80000, 93300, 90000, |
| 88900, 87500 }, |
| + .mask = 0x0f, |
| }; |
| |
| static const struct freq_desc freq_desc_tng = { |
| .use_msr_plat = true, |
| .freqs = { 0, 100000, 133300, 0, 0, 0, 0, 0 }, |
| + .mask = 0x07, |
| }; |
| |
| static const struct freq_desc freq_desc_ann = { |
| .use_msr_plat = true, |
| .freqs = { 83300, 100000, 133300, 100000, 0, 0, 0, 0 }, |
| + .mask = 0x0f, |
| }; |
| |
| static const struct x86_cpu_id tsc_msr_cpu_ids[] = { |
| @@ -87,6 +94,7 @@ unsigned long cpu_khz_from_msr(void) |
| const struct freq_desc *freq_desc; |
| const struct x86_cpu_id *id; |
| unsigned long res; |
| + int index; |
| |
| id = x86_match_cpu(tsc_msr_cpu_ids); |
| if (!id) |
| @@ -103,13 +111,17 @@ unsigned long cpu_khz_from_msr(void) |
| |
| /* Get FSB FREQ ID */ |
| rdmsr(MSR_FSB_FREQ, lo, hi); |
| + index = lo & freq_desc->mask; |
| |
| /* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */ |
| - freq = freq_desc->freqs[lo & 0x7]; |
| + freq = freq_desc->freqs[index]; |
| |
| /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */ |
| res = freq * ratio; |
| |
| + if (freq == 0) |
| + pr_err("Error MSR_FSB_FREQ index %d is unknown\n", index); |
| + |
| #ifdef CONFIG_X86_LOCAL_APIC |
| lapic_timer_period = (freq * 1000) / HZ; |
| #endif |
| -- |
| 2.7.4 |
| |