Re: [U-Boot] [PATCH v2 2/4] x86: Do TSC MSR calibration only for known/supported CPUs

2014-11-12 Thread Simon Glass
Hi Bin,

On 11 November 2014 18:16, Bin Meng bmeng...@gmail.com wrote:
 Hi Simon,

 On Wed, Nov 12, 2014 at 12:10 AM, Simon Glass s...@chromium.org wrote:
 Hi Bin,

 On 11 November 2014 01:25, Bin Meng bmeng...@gmail.com wrote:
 Hi Simon,

 On Tue, Nov 11, 2014 at 2:54 AM, Simon Glass s...@chromium.org wrote:
 Hi Bin,

 On 9 November 2014 07:19, Bin Meng bmeng...@gmail.com wrote:
 Using MSR_PLATFORM_INFO (0xCE) to calibrate TSR will cause #GP on
 processors which do not have this MSR. Instead only doing the MSR
 calibration for known/supported CPUs.

 Signed-off-by: Bin Meng bmeng...@gmail.com
 Acked-by: Simon Glass s...@chromium.org
 Tested-by: Simon Glass s...@chromium.org
 ---
  arch/x86/lib/tsc_timer.c | 116 
 ---
  1 file changed, 109 insertions(+), 7 deletions(-)

 Applied to u-boot-x86/master, thanks!

 (Please see note below)


 diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
 index 8b38702..fafbbfc 100644
 --- a/arch/x86/lib/tsc_timer.c
 +++ b/arch/x86/lib/tsc_timer.c
 @@ -1,6 +1,9 @@
  /*
   * Copyright (c) 2012 The Chromium OS Authors.
   *
 + * TSC calibration codes are adapted from Linux kernel
 + * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c
 + *
   * SPDX-License-Identifier:GPL-2.0+
   */

 @@ -12,8 +15,108 @@
  #include asm/msr.h
  #include asm/u-boot-x86.h

 +/* CPU reference clock frequency: in KHz */
 +#define FREQ_8383200
 +#define FREQ_100   99840
 +#define FREQ_133   133200
 +#define FREQ_166   166400
 +
 +#define MAX_NUM_FREQS  8
 +
  DECLARE_GLOBAL_DATA_PTR;

 +/*
 + * According to Intel 64 and IA-32 System Programming Guide,
 + * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
 + * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
 + * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
 + * so we need manually differentiate SoC families. This is what the
 + * field msr_plat does.
 + */
 +struct freq_desc {
 +   u8 x86_family;  /* CPU family */
 +   u8 x86_model;   /* model */
 +   u8 msr_plat;/* 1: use MSR_PLATFORM_INFO, 0: 
 MSR_IA32_PERF_STATUS */
 +   u32 freqs[MAX_NUM_FREQS];
 +};
 +
 +static struct freq_desc freq_desc_tables[] = {
 +   /* PNW */
 +   { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* CLV+ */
 +   { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* TNG */
 +   { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
 +   /* VLV2 */
 +   { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 
 } },
 +   /* ANN */
 +   { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 
 } },
 +};
 +
 +static int match_cpu(u8 family, u8 model)
 +{
 +   int i;
 +
 +   for (i = 0; i  ARRAY_SIZE(freq_desc_tables); i++) {
 +   if ((family == freq_desc_tables[i].x86_family) 
 +   (model == freq_desc_tables[i].x86_model))
 +   return i;
 +   }
 +
 +   return -1;
 +}
 +
 +/* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) 
 */
 +#define id_to_freq(cpu_index, freq_id) \
 +   (freq_desc_tables[cpu_index].freqs[freq_id])
 +
 +/*
 + * Do MSR calibration only for known/supported CPUs.
 + *
 + * Returns the calibration value or 0 if MSR calibration failed.
 + */
 +static unsigned long try_msr_calibrate_tsc(void)
 +{
 +   u32 lo, hi, ratio, freq_id, freq;
 +   unsigned long res;
 +   int cpu_index;
 +
 +   cpu_index = match_cpu(gd-arch.x86, gd-arch.x86_model);
 +   if (cpu_index  0)
 +   return 0;
 +
 +   if (freq_desc_tables[cpu_index].msr_plat) {
 +   rdmsr(MSR_PLATFORM_INFO, lo, hi);
 +   ratio = (lo  8)  0x1f;
 +   } else {
 +   rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +   ratio = (hi  8)  0x1f;
 +   }
 +   debug(Maximum core-clock to bus-clock ratio: 0x%x\n, ratio);
 +
 +   if (!ratio)
 +   goto fail;
 +
 +   /* Get FSB FREQ ID */
 +   rdmsr(MSR_FSB_FREQ, lo, hi);
 +   freq_id = lo  0x7;
 +   freq = id_to_freq(cpu_index, freq_id);
 +   debug(Resolved frequency ID: %u, frequency: %u KHz\n,
 +   freq_id, freq);
 +   if (!freq)
 +   goto fail;
 +
 +   /* TSC frequency = maximum resolved freq * maximum resolved bus 
 ratio */
 +   res = freq * ratio / 1000;
 +   debug(TSC runs at %lu MHz\n, res);
 +
 +   return res;
 +
 +fail:
 +   debug(Fast TSC calibration using MSR failed\n);
 +   return 0;
 +}
 +
  void timer_set_base(u64 base)
  {
 gd-arch.tsc_base = base;
 @@ -34,17 +137,16 @@ u64 __attribute__((no_instrument_function)) 
 get_ticks(void)
 return now_tick - gd-arch.tsc_base;
  }

 -#define PLATFORM_INFO_MSR 0xce
 -
  /* Get the speed of the TSC timer in MHz */
  unsigned __attribute__((no_instrument_function)) long 

Re: [U-Boot] [PATCH v2 2/4] x86: Do TSC MSR calibration only for known/supported CPUs

2014-11-11 Thread Bin Meng
Hi Simon,

On Tue, Nov 11, 2014 at 2:54 AM, Simon Glass s...@chromium.org wrote:
 Hi Bin,

 On 9 November 2014 07:19, Bin Meng bmeng...@gmail.com wrote:
 Using MSR_PLATFORM_INFO (0xCE) to calibrate TSR will cause #GP on
 processors which do not have this MSR. Instead only doing the MSR
 calibration for known/supported CPUs.

 Signed-off-by: Bin Meng bmeng...@gmail.com
 Acked-by: Simon Glass s...@chromium.org
 Tested-by: Simon Glass s...@chromium.org
 ---
  arch/x86/lib/tsc_timer.c | 116 
 ---
  1 file changed, 109 insertions(+), 7 deletions(-)

 Applied to u-boot-x86/master, thanks!

 (Please see note below)


 diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
 index 8b38702..fafbbfc 100644
 --- a/arch/x86/lib/tsc_timer.c
 +++ b/arch/x86/lib/tsc_timer.c
 @@ -1,6 +1,9 @@
  /*
   * Copyright (c) 2012 The Chromium OS Authors.
   *
 + * TSC calibration codes are adapted from Linux kernel
 + * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c
 + *
   * SPDX-License-Identifier:GPL-2.0+
   */

 @@ -12,8 +15,108 @@
  #include asm/msr.h
  #include asm/u-boot-x86.h

 +/* CPU reference clock frequency: in KHz */
 +#define FREQ_8383200
 +#define FREQ_100   99840
 +#define FREQ_133   133200
 +#define FREQ_166   166400
 +
 +#define MAX_NUM_FREQS  8
 +
  DECLARE_GLOBAL_DATA_PTR;

 +/*
 + * According to Intel 64 and IA-32 System Programming Guide,
 + * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
 + * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
 + * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
 + * so we need manually differentiate SoC families. This is what the
 + * field msr_plat does.
 + */
 +struct freq_desc {
 +   u8 x86_family;  /* CPU family */
 +   u8 x86_model;   /* model */
 +   u8 msr_plat;/* 1: use MSR_PLATFORM_INFO, 0: MSR_IA32_PERF_STATUS 
 */
 +   u32 freqs[MAX_NUM_FREQS];
 +};
 +
 +static struct freq_desc freq_desc_tables[] = {
 +   /* PNW */
 +   { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* CLV+ */
 +   { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* TNG */
 +   { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
 +   /* VLV2 */
 +   { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } 
 },
 +   /* ANN */
 +   { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } 
 },
 +};
 +
 +static int match_cpu(u8 family, u8 model)
 +{
 +   int i;
 +
 +   for (i = 0; i  ARRAY_SIZE(freq_desc_tables); i++) {
 +   if ((family == freq_desc_tables[i].x86_family) 
 +   (model == freq_desc_tables[i].x86_model))
 +   return i;
 +   }
 +
 +   return -1;
 +}
 +
 +/* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */
 +#define id_to_freq(cpu_index, freq_id) \
 +   (freq_desc_tables[cpu_index].freqs[freq_id])
 +
 +/*
 + * Do MSR calibration only for known/supported CPUs.
 + *
 + * Returns the calibration value or 0 if MSR calibration failed.
 + */
 +static unsigned long try_msr_calibrate_tsc(void)
 +{
 +   u32 lo, hi, ratio, freq_id, freq;
 +   unsigned long res;
 +   int cpu_index;
 +
 +   cpu_index = match_cpu(gd-arch.x86, gd-arch.x86_model);
 +   if (cpu_index  0)
 +   return 0;
 +
 +   if (freq_desc_tables[cpu_index].msr_plat) {
 +   rdmsr(MSR_PLATFORM_INFO, lo, hi);
 +   ratio = (lo  8)  0x1f;
 +   } else {
 +   rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +   ratio = (hi  8)  0x1f;
 +   }
 +   debug(Maximum core-clock to bus-clock ratio: 0x%x\n, ratio);
 +
 +   if (!ratio)
 +   goto fail;
 +
 +   /* Get FSB FREQ ID */
 +   rdmsr(MSR_FSB_FREQ, lo, hi);
 +   freq_id = lo  0x7;
 +   freq = id_to_freq(cpu_index, freq_id);
 +   debug(Resolved frequency ID: %u, frequency: %u KHz\n,
 +   freq_id, freq);
 +   if (!freq)
 +   goto fail;
 +
 +   /* TSC frequency = maximum resolved freq * maximum resolved bus 
 ratio */
 +   res = freq * ratio / 1000;
 +   debug(TSC runs at %lu MHz\n, res);
 +
 +   return res;
 +
 +fail:
 +   debug(Fast TSC calibration using MSR failed\n);
 +   return 0;
 +}
 +
  void timer_set_base(u64 base)
  {
 gd-arch.tsc_base = base;
 @@ -34,17 +137,16 @@ u64 __attribute__((no_instrument_function)) 
 get_ticks(void)
 return now_tick - gd-arch.tsc_base;
  }

 -#define PLATFORM_INFO_MSR 0xce
 -
  /* Get the speed of the TSC timer in MHz */
  unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void)
  {
 -   u32 ratio;
 -   u64 platform_info = native_read_msr(PLATFORM_INFO_MSR);
 +   unsigned long fast_calibrate;
 +
 +   fast_calibrate = try_msr_calibrate_tsc();
 +   if (!fast_calibrate)
 + 

Re: [U-Boot] [PATCH v2 2/4] x86: Do TSC MSR calibration only for known/supported CPUs

2014-11-11 Thread Simon Glass
Hi Bin,

On 11 November 2014 01:25, Bin Meng bmeng...@gmail.com wrote:
 Hi Simon,

 On Tue, Nov 11, 2014 at 2:54 AM, Simon Glass s...@chromium.org wrote:
 Hi Bin,

 On 9 November 2014 07:19, Bin Meng bmeng...@gmail.com wrote:
 Using MSR_PLATFORM_INFO (0xCE) to calibrate TSR will cause #GP on
 processors which do not have this MSR. Instead only doing the MSR
 calibration for known/supported CPUs.

 Signed-off-by: Bin Meng bmeng...@gmail.com
 Acked-by: Simon Glass s...@chromium.org
 Tested-by: Simon Glass s...@chromium.org
 ---
  arch/x86/lib/tsc_timer.c | 116 
 ---
  1 file changed, 109 insertions(+), 7 deletions(-)

 Applied to u-boot-x86/master, thanks!

 (Please see note below)


 diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
 index 8b38702..fafbbfc 100644
 --- a/arch/x86/lib/tsc_timer.c
 +++ b/arch/x86/lib/tsc_timer.c
 @@ -1,6 +1,9 @@
  /*
   * Copyright (c) 2012 The Chromium OS Authors.
   *
 + * TSC calibration codes are adapted from Linux kernel
 + * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c
 + *
   * SPDX-License-Identifier:GPL-2.0+
   */

 @@ -12,8 +15,108 @@
  #include asm/msr.h
  #include asm/u-boot-x86.h

 +/* CPU reference clock frequency: in KHz */
 +#define FREQ_8383200
 +#define FREQ_100   99840
 +#define FREQ_133   133200
 +#define FREQ_166   166400
 +
 +#define MAX_NUM_FREQS  8
 +
  DECLARE_GLOBAL_DATA_PTR;

 +/*
 + * According to Intel 64 and IA-32 System Programming Guide,
 + * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
 + * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
 + * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
 + * so we need manually differentiate SoC families. This is what the
 + * field msr_plat does.
 + */
 +struct freq_desc {
 +   u8 x86_family;  /* CPU family */
 +   u8 x86_model;   /* model */
 +   u8 msr_plat;/* 1: use MSR_PLATFORM_INFO, 0: 
 MSR_IA32_PERF_STATUS */
 +   u32 freqs[MAX_NUM_FREQS];
 +};
 +
 +static struct freq_desc freq_desc_tables[] = {
 +   /* PNW */
 +   { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* CLV+ */
 +   { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* TNG */
 +   { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
 +   /* VLV2 */
 +   { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } 
 },
 +   /* ANN */
 +   { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } 
 },
 +};
 +
 +static int match_cpu(u8 family, u8 model)
 +{
 +   int i;
 +
 +   for (i = 0; i  ARRAY_SIZE(freq_desc_tables); i++) {
 +   if ((family == freq_desc_tables[i].x86_family) 
 +   (model == freq_desc_tables[i].x86_model))
 +   return i;
 +   }
 +
 +   return -1;
 +}
 +
 +/* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */
 +#define id_to_freq(cpu_index, freq_id) \
 +   (freq_desc_tables[cpu_index].freqs[freq_id])
 +
 +/*
 + * Do MSR calibration only for known/supported CPUs.
 + *
 + * Returns the calibration value or 0 if MSR calibration failed.
 + */
 +static unsigned long try_msr_calibrate_tsc(void)
 +{
 +   u32 lo, hi, ratio, freq_id, freq;
 +   unsigned long res;
 +   int cpu_index;
 +
 +   cpu_index = match_cpu(gd-arch.x86, gd-arch.x86_model);
 +   if (cpu_index  0)
 +   return 0;
 +
 +   if (freq_desc_tables[cpu_index].msr_plat) {
 +   rdmsr(MSR_PLATFORM_INFO, lo, hi);
 +   ratio = (lo  8)  0x1f;
 +   } else {
 +   rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +   ratio = (hi  8)  0x1f;
 +   }
 +   debug(Maximum core-clock to bus-clock ratio: 0x%x\n, ratio);
 +
 +   if (!ratio)
 +   goto fail;
 +
 +   /* Get FSB FREQ ID */
 +   rdmsr(MSR_FSB_FREQ, lo, hi);
 +   freq_id = lo  0x7;
 +   freq = id_to_freq(cpu_index, freq_id);
 +   debug(Resolved frequency ID: %u, frequency: %u KHz\n,
 +   freq_id, freq);
 +   if (!freq)
 +   goto fail;
 +
 +   /* TSC frequency = maximum resolved freq * maximum resolved bus 
 ratio */
 +   res = freq * ratio / 1000;
 +   debug(TSC runs at %lu MHz\n, res);
 +
 +   return res;
 +
 +fail:
 +   debug(Fast TSC calibration using MSR failed\n);
 +   return 0;
 +}
 +
  void timer_set_base(u64 base)
  {
 gd-arch.tsc_base = base;
 @@ -34,17 +137,16 @@ u64 __attribute__((no_instrument_function)) 
 get_ticks(void)
 return now_tick - gd-arch.tsc_base;
  }

 -#define PLATFORM_INFO_MSR 0xce
 -
  /* Get the speed of the TSC timer in MHz */
  unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void)
  {
 -   u32 ratio;
 -   u64 platform_info = native_read_msr(PLATFORM_INFO_MSR);
 +   unsigned long fast_calibrate;
 +
 +   

Re: [U-Boot] [PATCH v2 2/4] x86: Do TSC MSR calibration only for known/supported CPUs

2014-11-11 Thread Bin Meng
Hi Simon,

On Wed, Nov 12, 2014 at 12:10 AM, Simon Glass s...@chromium.org wrote:
 Hi Bin,

 On 11 November 2014 01:25, Bin Meng bmeng...@gmail.com wrote:
 Hi Simon,

 On Tue, Nov 11, 2014 at 2:54 AM, Simon Glass s...@chromium.org wrote:
 Hi Bin,

 On 9 November 2014 07:19, Bin Meng bmeng...@gmail.com wrote:
 Using MSR_PLATFORM_INFO (0xCE) to calibrate TSR will cause #GP on
 processors which do not have this MSR. Instead only doing the MSR
 calibration for known/supported CPUs.

 Signed-off-by: Bin Meng bmeng...@gmail.com
 Acked-by: Simon Glass s...@chromium.org
 Tested-by: Simon Glass s...@chromium.org
 ---
  arch/x86/lib/tsc_timer.c | 116 
 ---
  1 file changed, 109 insertions(+), 7 deletions(-)

 Applied to u-boot-x86/master, thanks!

 (Please see note below)


 diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
 index 8b38702..fafbbfc 100644
 --- a/arch/x86/lib/tsc_timer.c
 +++ b/arch/x86/lib/tsc_timer.c
 @@ -1,6 +1,9 @@
  /*
   * Copyright (c) 2012 The Chromium OS Authors.
   *
 + * TSC calibration codes are adapted from Linux kernel
 + * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c
 + *
   * SPDX-License-Identifier:GPL-2.0+
   */

 @@ -12,8 +15,108 @@
  #include asm/msr.h
  #include asm/u-boot-x86.h

 +/* CPU reference clock frequency: in KHz */
 +#define FREQ_8383200
 +#define FREQ_100   99840
 +#define FREQ_133   133200
 +#define FREQ_166   166400
 +
 +#define MAX_NUM_FREQS  8
 +
  DECLARE_GLOBAL_DATA_PTR;

 +/*
 + * According to Intel 64 and IA-32 System Programming Guide,
 + * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
 + * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
 + * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
 + * so we need manually differentiate SoC families. This is what the
 + * field msr_plat does.
 + */
 +struct freq_desc {
 +   u8 x86_family;  /* CPU family */
 +   u8 x86_model;   /* model */
 +   u8 msr_plat;/* 1: use MSR_PLATFORM_INFO, 0: 
 MSR_IA32_PERF_STATUS */
 +   u32 freqs[MAX_NUM_FREQS];
 +};
 +
 +static struct freq_desc freq_desc_tables[] = {
 +   /* PNW */
 +   { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* CLV+ */
 +   { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* TNG */
 +   { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
 +   /* VLV2 */
 +   { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 
 } },
 +   /* ANN */
 +   { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 
 } },
 +};
 +
 +static int match_cpu(u8 family, u8 model)
 +{
 +   int i;
 +
 +   for (i = 0; i  ARRAY_SIZE(freq_desc_tables); i++) {
 +   if ((family == freq_desc_tables[i].x86_family) 
 +   (model == freq_desc_tables[i].x86_model))
 +   return i;
 +   }
 +
 +   return -1;
 +}
 +
 +/* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) 
 */
 +#define id_to_freq(cpu_index, freq_id) \
 +   (freq_desc_tables[cpu_index].freqs[freq_id])
 +
 +/*
 + * Do MSR calibration only for known/supported CPUs.
 + *
 + * Returns the calibration value or 0 if MSR calibration failed.
 + */
 +static unsigned long try_msr_calibrate_tsc(void)
 +{
 +   u32 lo, hi, ratio, freq_id, freq;
 +   unsigned long res;
 +   int cpu_index;
 +
 +   cpu_index = match_cpu(gd-arch.x86, gd-arch.x86_model);
 +   if (cpu_index  0)
 +   return 0;
 +
 +   if (freq_desc_tables[cpu_index].msr_plat) {
 +   rdmsr(MSR_PLATFORM_INFO, lo, hi);
 +   ratio = (lo  8)  0x1f;
 +   } else {
 +   rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +   ratio = (hi  8)  0x1f;
 +   }
 +   debug(Maximum core-clock to bus-clock ratio: 0x%x\n, ratio);
 +
 +   if (!ratio)
 +   goto fail;
 +
 +   /* Get FSB FREQ ID */
 +   rdmsr(MSR_FSB_FREQ, lo, hi);
 +   freq_id = lo  0x7;
 +   freq = id_to_freq(cpu_index, freq_id);
 +   debug(Resolved frequency ID: %u, frequency: %u KHz\n,
 +   freq_id, freq);
 +   if (!freq)
 +   goto fail;
 +
 +   /* TSC frequency = maximum resolved freq * maximum resolved bus 
 ratio */
 +   res = freq * ratio / 1000;
 +   debug(TSC runs at %lu MHz\n, res);
 +
 +   return res;
 +
 +fail:
 +   debug(Fast TSC calibration using MSR failed\n);
 +   return 0;
 +}
 +
  void timer_set_base(u64 base)
  {
 gd-arch.tsc_base = base;
 @@ -34,17 +137,16 @@ u64 __attribute__((no_instrument_function)) 
 get_ticks(void)
 return now_tick - gd-arch.tsc_base;
  }

 -#define PLATFORM_INFO_MSR 0xce
 -
  /* Get the speed of the TSC timer in MHz */
  unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void)
  {
 -   u32 ratio;
 -   u64 platform_info = 

Re: [U-Boot] [PATCH v2 2/4] x86: Do TSC MSR calibration only for known/supported CPUs

2014-11-10 Thread Simon Glass
Hi Bin,

On 9 November 2014 07:19, Bin Meng bmeng...@gmail.com wrote:
 Using MSR_PLATFORM_INFO (0xCE) to calibrate TSR will cause #GP on
 processors which do not have this MSR. Instead only doing the MSR
 calibration for known/supported CPUs.

 Signed-off-by: Bin Meng bmeng...@gmail.com
 Acked-by: Simon Glass s...@chromium.org
 Tested-by: Simon Glass s...@chromium.org
 ---
  arch/x86/lib/tsc_timer.c | 116 
 ---
  1 file changed, 109 insertions(+), 7 deletions(-)

Applied to u-boot-x86/master, thanks!

(Please see note below)


 diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
 index 8b38702..fafbbfc 100644
 --- a/arch/x86/lib/tsc_timer.c
 +++ b/arch/x86/lib/tsc_timer.c
 @@ -1,6 +1,9 @@
  /*
   * Copyright (c) 2012 The Chromium OS Authors.
   *
 + * TSC calibration codes are adapted from Linux kernel
 + * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c
 + *
   * SPDX-License-Identifier:GPL-2.0+
   */

 @@ -12,8 +15,108 @@
  #include asm/msr.h
  #include asm/u-boot-x86.h

 +/* CPU reference clock frequency: in KHz */
 +#define FREQ_8383200
 +#define FREQ_100   99840
 +#define FREQ_133   133200
 +#define FREQ_166   166400
 +
 +#define MAX_NUM_FREQS  8
 +
  DECLARE_GLOBAL_DATA_PTR;

 +/*
 + * According to Intel 64 and IA-32 System Programming Guide,
 + * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
 + * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
 + * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
 + * so we need manually differentiate SoC families. This is what the
 + * field msr_plat does.
 + */
 +struct freq_desc {
 +   u8 x86_family;  /* CPU family */
 +   u8 x86_model;   /* model */
 +   u8 msr_plat;/* 1: use MSR_PLATFORM_INFO, 0: MSR_IA32_PERF_STATUS 
 */
 +   u32 freqs[MAX_NUM_FREQS];
 +};
 +
 +static struct freq_desc freq_desc_tables[] = {
 +   /* PNW */
 +   { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* CLV+ */
 +   { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
 +   /* TNG */
 +   { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
 +   /* VLV2 */
 +   { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
 +   /* ANN */
 +   { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } },
 +};
 +
 +static int match_cpu(u8 family, u8 model)
 +{
 +   int i;
 +
 +   for (i = 0; i  ARRAY_SIZE(freq_desc_tables); i++) {
 +   if ((family == freq_desc_tables[i].x86_family) 
 +   (model == freq_desc_tables[i].x86_model))
 +   return i;
 +   }
 +
 +   return -1;
 +}
 +
 +/* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */
 +#define id_to_freq(cpu_index, freq_id) \
 +   (freq_desc_tables[cpu_index].freqs[freq_id])
 +
 +/*
 + * Do MSR calibration only for known/supported CPUs.
 + *
 + * Returns the calibration value or 0 if MSR calibration failed.
 + */
 +static unsigned long try_msr_calibrate_tsc(void)
 +{
 +   u32 lo, hi, ratio, freq_id, freq;
 +   unsigned long res;
 +   int cpu_index;
 +
 +   cpu_index = match_cpu(gd-arch.x86, gd-arch.x86_model);
 +   if (cpu_index  0)
 +   return 0;
 +
 +   if (freq_desc_tables[cpu_index].msr_plat) {
 +   rdmsr(MSR_PLATFORM_INFO, lo, hi);
 +   ratio = (lo  8)  0x1f;
 +   } else {
 +   rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
 +   ratio = (hi  8)  0x1f;
 +   }
 +   debug(Maximum core-clock to bus-clock ratio: 0x%x\n, ratio);
 +
 +   if (!ratio)
 +   goto fail;
 +
 +   /* Get FSB FREQ ID */
 +   rdmsr(MSR_FSB_FREQ, lo, hi);
 +   freq_id = lo  0x7;
 +   freq = id_to_freq(cpu_index, freq_id);
 +   debug(Resolved frequency ID: %u, frequency: %u KHz\n,
 +   freq_id, freq);
 +   if (!freq)
 +   goto fail;
 +
 +   /* TSC frequency = maximum resolved freq * maximum resolved bus ratio 
 */
 +   res = freq * ratio / 1000;
 +   debug(TSC runs at %lu MHz\n, res);
 +
 +   return res;
 +
 +fail:
 +   debug(Fast TSC calibration using MSR failed\n);
 +   return 0;
 +}
 +
  void timer_set_base(u64 base)
  {
 gd-arch.tsc_base = base;
 @@ -34,17 +137,16 @@ u64 __attribute__((no_instrument_function)) 
 get_ticks(void)
 return now_tick - gd-arch.tsc_base;
  }

 -#define PLATFORM_INFO_MSR 0xce
 -
  /* Get the speed of the TSC timer in MHz */
  unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void)
  {
 -   u32 ratio;
 -   u64 platform_info = native_read_msr(PLATFORM_INFO_MSR);
 +   unsigned long fast_calibrate;
 +
 +   fast_calibrate = try_msr_calibrate_tsc();
 +   if (!fast_calibrate)
 +   panic(TSC frequency is ZERO);

 -   /* 100MHz times Max Non Turbo 

[U-Boot] [PATCH v2 2/4] x86: Do TSC MSR calibration only for known/supported CPUs

2014-11-09 Thread Bin Meng
Using MSR_PLATFORM_INFO (0xCE) to calibrate TSR will cause #GP on
processors which do not have this MSR. Instead only doing the MSR
calibration for known/supported CPUs.

Signed-off-by: Bin Meng bmeng...@gmail.com
Acked-by: Simon Glass s...@chromium.org
Tested-by: Simon Glass s...@chromium.org
---
 arch/x86/lib/tsc_timer.c | 116 ---
 1 file changed, 109 insertions(+), 7 deletions(-)

diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
index 8b38702..fafbbfc 100644
--- a/arch/x86/lib/tsc_timer.c
+++ b/arch/x86/lib/tsc_timer.c
@@ -1,6 +1,9 @@
 /*
  * Copyright (c) 2012 The Chromium OS Authors.
  *
+ * TSC calibration codes are adapted from Linux kernel
+ * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c
+ *
  * SPDX-License-Identifier:GPL-2.0+
  */
 
@@ -12,8 +15,108 @@
 #include asm/msr.h
 #include asm/u-boot-x86.h
 
+/* CPU reference clock frequency: in KHz */
+#define FREQ_8383200
+#define FREQ_100   99840
+#define FREQ_133   133200
+#define FREQ_166   166400
+
+#define MAX_NUM_FREQS  8
+
 DECLARE_GLOBAL_DATA_PTR;
 
+/*
+ * According to Intel 64 and IA-32 System Programming Guide,
+ * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
+ * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
+ * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
+ * so we need manually differentiate SoC families. This is what the
+ * field msr_plat does.
+ */
+struct freq_desc {
+   u8 x86_family;  /* CPU family */
+   u8 x86_model;   /* model */
+   u8 msr_plat;/* 1: use MSR_PLATFORM_INFO, 0: MSR_IA32_PERF_STATUS */
+   u32 freqs[MAX_NUM_FREQS];
+};
+
+static struct freq_desc freq_desc_tables[] = {
+   /* PNW */
+   { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
+   /* CLV+ */
+   { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
+   /* TNG */
+   { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
+   /* VLV2 */
+   { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
+   /* ANN */
+   { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } },
+};
+
+static int match_cpu(u8 family, u8 model)
+{
+   int i;
+
+   for (i = 0; i  ARRAY_SIZE(freq_desc_tables); i++) {
+   if ((family == freq_desc_tables[i].x86_family) 
+   (model == freq_desc_tables[i].x86_model))
+   return i;
+   }
+
+   return -1;
+}
+
+/* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */
+#define id_to_freq(cpu_index, freq_id) \
+   (freq_desc_tables[cpu_index].freqs[freq_id])
+
+/*
+ * Do MSR calibration only for known/supported CPUs.
+ *
+ * Returns the calibration value or 0 if MSR calibration failed.
+ */
+static unsigned long try_msr_calibrate_tsc(void)
+{
+   u32 lo, hi, ratio, freq_id, freq;
+   unsigned long res;
+   int cpu_index;
+
+   cpu_index = match_cpu(gd-arch.x86, gd-arch.x86_model);
+   if (cpu_index  0)
+   return 0;
+
+   if (freq_desc_tables[cpu_index].msr_plat) {
+   rdmsr(MSR_PLATFORM_INFO, lo, hi);
+   ratio = (lo  8)  0x1f;
+   } else {
+   rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
+   ratio = (hi  8)  0x1f;
+   }
+   debug(Maximum core-clock to bus-clock ratio: 0x%x\n, ratio);
+
+   if (!ratio)
+   goto fail;
+
+   /* Get FSB FREQ ID */
+   rdmsr(MSR_FSB_FREQ, lo, hi);
+   freq_id = lo  0x7;
+   freq = id_to_freq(cpu_index, freq_id);
+   debug(Resolved frequency ID: %u, frequency: %u KHz\n,
+   freq_id, freq);
+   if (!freq)
+   goto fail;
+
+   /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
+   res = freq * ratio / 1000;
+   debug(TSC runs at %lu MHz\n, res);
+
+   return res;
+
+fail:
+   debug(Fast TSC calibration using MSR failed\n);
+   return 0;
+}
+
 void timer_set_base(u64 base)
 {
gd-arch.tsc_base = base;
@@ -34,17 +137,16 @@ u64 __attribute__((no_instrument_function)) get_ticks(void)
return now_tick - gd-arch.tsc_base;
 }
 
-#define PLATFORM_INFO_MSR 0xce
-
 /* Get the speed of the TSC timer in MHz */
 unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void)
 {
-   u32 ratio;
-   u64 platform_info = native_read_msr(PLATFORM_INFO_MSR);
+   unsigned long fast_calibrate;
+
+   fast_calibrate = try_msr_calibrate_tsc();
+   if (!fast_calibrate)
+   panic(TSC frequency is ZERO);
 
-   /* 100MHz times Max Non Turbo ratio */
-   ratio = (platform_info  8)  0xff;
-   return 100 * ratio;
+   return fast_calibrate;
 }
 
 unsigned long get_tbclk(void)
-- 
1.8.2.1

___
U-Boot mailing list
U-Boot@lists.denx.de