Skip to content

Commit

Permalink
x86/tsc_msr: Fix MSR_FSB_FREQ mask for Cherry Trail devices
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Hans de Goede authored and Thomas Gleixner committed Mar 11, 2020
1 parent 812c2d7 commit c8810e2
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions arch/x86/kernel/tsc_msr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -27,6 +27,7 @@
struct freq_desc {
bool use_msr_plat;
u32 freqs[MAX_NUM_FREQS];
u32 mask;
};

/*
Expand All @@ -37,37 +38,44 @@ 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 freq_desc freq_desc_lgm = {
.use_msr_plat = true,
.freqs = { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 },
.mask = 0x0f,
};

static const struct x86_cpu_id tsc_msr_cpu_ids[] = {
Expand All @@ -93,6 +101,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)
Expand All @@ -109,13 +118,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
Expand Down

0 comments on commit c8810e2

Please sign in to comment.