LCOV - code coverage report
Current view: top level - arch/x86/kernel - tsc_msr.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 30 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 1 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * TSC frequency enumeration via MSR
       4             :  *
       5             :  * Copyright (C) 2013, 2018 Intel Corporation
       6             :  * Author: Bin Gao <bin.gao@intel.com>
       7             :  */
       8             : 
       9             : #include <linux/kernel.h>
      10             : #include <linux/thread_info.h>
      11             : 
      12             : #include <asm/apic.h>
      13             : #include <asm/cpu_device_id.h>
      14             : #include <asm/intel-family.h>
      15             : #include <asm/msr.h>
      16             : #include <asm/param.h>
      17             : #include <asm/tsc.h>
      18             : 
      19             : #define MAX_NUM_FREQS   16 /* 4 bits to select the frequency */
      20             : 
      21             : /*
      22             :  * The frequency numbers in the SDM are e.g. 83.3 MHz, which does not contain a
      23             :  * lot of accuracy which leads to clock drift. As far as we know Bay Trail SoCs
      24             :  * use a 25 MHz crystal and Cherry Trail uses a 19.2 MHz crystal, the crystal
      25             :  * is the source clk for a root PLL which outputs 1600 and 100 MHz. It is
      26             :  * unclear if the root PLL outputs are used directly by the CPU clock PLL or
      27             :  * if there is another PLL in between.
      28             :  * This does not matter though, we can model the chain of PLLs as a single PLL
      29             :  * with a quotient equal to the quotients of all PLLs in the chain multiplied.
      30             :  * So we can create a simplified model of the CPU clock setup using a reference
      31             :  * clock of 100 MHz plus a quotient which gets us as close to the frequency
      32             :  * from the SDM as possible.
      33             :  * For the 83.3 MHz example from above this would give us 100 MHz * 5 / 6 =
      34             :  * 83 and 1/3 MHz, which matches exactly what has been measured on actual hw.
      35             :  */
      36             : #define TSC_REFERENCE_KHZ 100000
      37             : 
      38             : struct muldiv {
      39             :         u32 multiplier;
      40             :         u32 divider;
      41             : };
      42             : 
      43             : /*
      44             :  * If MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
      45             :  * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
      46             :  * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
      47             :  * so we need manually differentiate SoC families. This is what the
      48             :  * field use_msr_plat does.
      49             :  */
      50             : struct freq_desc {
      51             :         bool use_msr_plat;
      52             :         struct muldiv muldiv[MAX_NUM_FREQS];
      53             :         /*
      54             :          * Some CPU frequencies in the SDM do not map to known PLL freqs, in
      55             :          * that case the muldiv array is empty and the freqs array is used.
      56             :          */
      57             :         u32 freqs[MAX_NUM_FREQS];
      58             :         u32 mask;
      59             : };
      60             : 
      61             : /*
      62             :  * Penwell and Clovertrail use spread spectrum clock,
      63             :  * so the freq number is not exactly the same as reported
      64             :  * by MSR based on SDM.
      65             :  */
      66             : static const struct freq_desc freq_desc_pnw = {
      67             :         .use_msr_plat = false,
      68             :         .freqs = { 0, 0, 0, 0, 0, 99840, 0, 83200 },
      69             :         .mask = 0x07,
      70             : };
      71             : 
      72             : static const struct freq_desc freq_desc_clv = {
      73             :         .use_msr_plat = false,
      74             :         .freqs = { 0, 133200, 0, 0, 0, 99840, 0, 83200 },
      75             :         .mask = 0x07,
      76             : };
      77             : 
      78             : /*
      79             :  * Bay Trail SDM MSR_FSB_FREQ frequencies simplified PLL model:
      80             :  *  000:   100 *  5 /  6  =  83.3333 MHz
      81             :  *  001:   100 *  1 /  1  = 100.0000 MHz
      82             :  *  010:   100 *  4 /  3  = 133.3333 MHz
      83             :  *  011:   100 *  7 /  6  = 116.6667 MHz
      84             :  *  100:   100 *  4 /  5  =  80.0000 MHz
      85             :  */
      86             : static const struct freq_desc freq_desc_byt = {
      87             :         .use_msr_plat = true,
      88             :         .muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 7, 6 },
      89             :                     { 4, 5 } },
      90             :         .mask = 0x07,
      91             : };
      92             : 
      93             : /*
      94             :  * Cherry Trail SDM MSR_FSB_FREQ frequencies simplified PLL model:
      95             :  * 0000:   100 *  5 /  6  =  83.3333 MHz
      96             :  * 0001:   100 *  1 /  1  = 100.0000 MHz
      97             :  * 0010:   100 *  4 /  3  = 133.3333 MHz
      98             :  * 0011:   100 *  7 /  6  = 116.6667 MHz
      99             :  * 0100:   100 *  4 /  5  =  80.0000 MHz
     100             :  * 0101:   100 * 14 / 15  =  93.3333 MHz
     101             :  * 0110:   100 *  9 / 10  =  90.0000 MHz
     102             :  * 0111:   100 *  8 /  9  =  88.8889 MHz
     103             :  * 1000:   100 *  7 /  8  =  87.5000 MHz
     104             :  */
     105             : static const struct freq_desc freq_desc_cht = {
     106             :         .use_msr_plat = true,
     107             :         .muldiv = { { 5, 6 }, {  1,  1 }, { 4,  3 }, { 7, 6 },
     108             :                     { 4, 5 }, { 14, 15 }, { 9, 10 }, { 8, 9 },
     109             :                     { 7, 8 } },
     110             :         .mask = 0x0f,
     111             : };
     112             : 
     113             : /*
     114             :  * Merriefield SDM MSR_FSB_FREQ frequencies simplified PLL model:
     115             :  * 0001:   100 *  1 /  1  = 100.0000 MHz
     116             :  * 0010:   100 *  4 /  3  = 133.3333 MHz
     117             :  */
     118             : static const struct freq_desc freq_desc_tng = {
     119             :         .use_msr_plat = true,
     120             :         .muldiv = { { 0, 0 }, { 1, 1 }, { 4, 3 } },
     121             :         .mask = 0x07,
     122             : };
     123             : 
     124             : /*
     125             :  * Moorefield SDM MSR_FSB_FREQ frequencies simplified PLL model:
     126             :  * 0000:   100 *  5 /  6  =  83.3333 MHz
     127             :  * 0001:   100 *  1 /  1  = 100.0000 MHz
     128             :  * 0010:   100 *  4 /  3  = 133.3333 MHz
     129             :  * 0011:   100 *  1 /  1  = 100.0000 MHz
     130             :  */
     131             : static const struct freq_desc freq_desc_ann = {
     132             :         .use_msr_plat = true,
     133             :         .muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 1, 1 } },
     134             :         .mask = 0x0f,
     135             : };
     136             : 
     137             : /*
     138             :  * 24 MHz crystal? : 24 * 13 / 4 = 78 MHz
     139             :  * Frequency step for Lightning Mountain SoC is fixed to 78 MHz,
     140             :  * so all the frequency entries are 78000.
     141             :  */
     142             : static const struct freq_desc freq_desc_lgm = {
     143             :         .use_msr_plat = true,
     144             :         .freqs = { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000,
     145             :                    78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 },
     146             :         .mask = 0x0f,
     147             : };
     148             : 
     149             : static const struct x86_cpu_id tsc_msr_cpu_ids[] = {
     150             :         X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL_MID,   &freq_desc_pnw),
     151             :         X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL_TABLET,&freq_desc_clv),
     152             :         X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,     &freq_desc_byt),
     153             :         X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &freq_desc_tng),
     154             :         X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        &freq_desc_cht),
     155             :         X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT_MID,    &freq_desc_ann),
     156             :         X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT_NP,     &freq_desc_lgm),
     157             :         {}
     158             : };
     159             : 
     160             : /*
     161             :  * MSR-based CPU/TSC frequency discovery for certain CPUs.
     162             :  *
     163             :  * Set global "lapic_timer_period" to bus_clock_cycles/jiffy
     164             :  * Return processor base frequency in KHz, or 0 on failure.
     165             :  */
     166           0 : unsigned long cpu_khz_from_msr(void)
     167             : {
     168           0 :         u32 lo, hi, ratio, freq, tscref;
     169           0 :         const struct freq_desc *freq_desc;
     170           0 :         const struct x86_cpu_id *id;
     171           0 :         const struct muldiv *md;
     172           0 :         unsigned long res;
     173           0 :         int index;
     174             : 
     175           0 :         id = x86_match_cpu(tsc_msr_cpu_ids);
     176           0 :         if (!id)
     177             :                 return 0;
     178             : 
     179           0 :         freq_desc = (struct freq_desc *)id->driver_data;
     180           0 :         if (freq_desc->use_msr_plat) {
     181           0 :                 rdmsr(MSR_PLATFORM_INFO, lo, hi);
     182           0 :                 ratio = (lo >> 8) & 0xff;
     183             :         } else {
     184           0 :                 rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
     185           0 :                 ratio = (hi >> 8) & 0x1f;
     186             :         }
     187             : 
     188             :         /* Get FSB FREQ ID */
     189           0 :         rdmsr(MSR_FSB_FREQ, lo, hi);
     190           0 :         index = lo & freq_desc->mask;
     191           0 :         md = &freq_desc->muldiv[index];
     192             : 
     193             :         /*
     194             :          * Note this also catches cases where the index points to an unpopulated
     195             :          * part of muldiv, in that case the else will set freq and res to 0.
     196             :          */
     197           0 :         if (md->divider) {
     198           0 :                 tscref = TSC_REFERENCE_KHZ * md->multiplier;
     199           0 :                 freq = DIV_ROUND_CLOSEST(tscref, md->divider);
     200             :                 /*
     201             :                  * Multiplying by ratio before the division has better
     202             :                  * accuracy than just calculating freq * ratio.
     203             :                  */
     204           0 :                 res = DIV_ROUND_CLOSEST(tscref * ratio, md->divider);
     205             :         } else {
     206           0 :                 freq = freq_desc->freqs[index];
     207           0 :                 res = freq * ratio;
     208             :         }
     209             : 
     210           0 :         if (freq == 0)
     211           0 :                 pr_err("Error MSR_FSB_FREQ index %d is unknown\n", index);
     212             : 
     213             : #ifdef CONFIG_X86_LOCAL_APIC
     214           0 :         lapic_timer_period = (freq * 1000) / HZ;
     215             : #endif
     216             : 
     217             :         /*
     218             :          * TSC frequency determined by MSR is always considered "known"
     219             :          * because it is reported by HW.
     220             :          * Another fact is that on MSR capable platforms, PIT/HPET is
     221             :          * generally not available so calibration won't work at all.
     222             :          */
     223           0 :         setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
     224             : 
     225             :         /*
     226             :          * Unfortunately there is no way for hardware to tell whether the
     227             :          * TSC is reliable.  We were told by silicon design team that TSC
     228             :          * on Atom SoCs are always "reliable". TSC is also the only
     229             :          * reliable clocksource on these SoCs (HPET is either not present
     230             :          * or not functional) so mark TSC reliable which removes the
     231             :          * requirement for a watchdog clocksource.
     232             :          */
     233           0 :         setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
     234             : 
     235           0 :         return res;
     236             : }

Generated by: LCOV version 1.14