LCOV - code coverage report
Current view: top level - arch/x86/kernel - tsc_msr.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 20 0.0 %
Date: 2022-04-01 14:17:54 Functions: 0 1 0.0 %
Branches: 0 4 0.0 %

           Branch data     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                 :            : 
      11                 :            : #include <asm/apic.h>
      12                 :            : #include <asm/cpu_device_id.h>
      13                 :            : #include <asm/intel-family.h>
      14                 :            : #include <asm/msr.h>
      15                 :            : #include <asm/param.h>
      16                 :            : #include <asm/tsc.h>
      17                 :            : 
      18                 :            : #define MAX_NUM_FREQS   9
      19                 :            : 
      20                 :            : /*
      21                 :            :  * If MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
      22                 :            :  * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
      23                 :            :  * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
      24                 :            :  * so we need manually differentiate SoC families. This is what the
      25                 :            :  * field msr_plat does.
      26                 :            :  */
      27                 :            : struct freq_desc {
      28                 :            :         u8 msr_plat;    /* 1: use MSR_PLATFORM_INFO, 0: MSR_IA32_PERF_STATUS */
      29                 :            :         u32 freqs[MAX_NUM_FREQS];
      30                 :            : };
      31                 :            : 
      32                 :            : /*
      33                 :            :  * Penwell and Clovertrail use spread spectrum clock,
      34                 :            :  * so the freq number is not exactly the same as reported
      35                 :            :  * by MSR based on SDM.
      36                 :            :  */
      37                 :            : static const struct freq_desc freq_desc_pnw = {
      38                 :            :         0, { 0, 0, 0, 0, 0, 99840, 0, 83200 }
      39                 :            : };
      40                 :            : 
      41                 :            : static const struct freq_desc freq_desc_clv = {
      42                 :            :         0, { 0, 133200, 0, 0, 0, 99840, 0, 83200 }
      43                 :            : };
      44                 :            : 
      45                 :            : static const struct freq_desc freq_desc_byt = {
      46                 :            :         1, { 83300, 100000, 133300, 116700, 80000, 0, 0, 0 }
      47                 :            : };
      48                 :            : 
      49                 :            : static const struct freq_desc freq_desc_cht = {
      50                 :            :         1, { 83300, 100000, 133300, 116700, 80000, 93300, 90000, 88900, 87500 }
      51                 :            : };
      52                 :            : 
      53                 :            : static const struct freq_desc freq_desc_tng = {
      54                 :            :         1, { 0, 100000, 133300, 0, 0, 0, 0, 0 }
      55                 :            : };
      56                 :            : 
      57                 :            : static const struct freq_desc freq_desc_ann = {
      58                 :            :         1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0 }
      59                 :            : };
      60                 :            : 
      61                 :            : static const struct freq_desc freq_desc_lgm = {
      62                 :            :         1, { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 }
      63                 :            : };
      64                 :            : 
      65                 :            : static const struct x86_cpu_id tsc_msr_cpu_ids[] = {
      66                 :            :         INTEL_CPU_FAM6(ATOM_SALTWELL_MID,       freq_desc_pnw),
      67                 :            :         INTEL_CPU_FAM6(ATOM_SALTWELL_TABLET,    freq_desc_clv),
      68                 :            :         INTEL_CPU_FAM6(ATOM_SILVERMONT,         freq_desc_byt),
      69                 :            :         INTEL_CPU_FAM6(ATOM_SILVERMONT_MID,     freq_desc_tng),
      70                 :            :         INTEL_CPU_FAM6(ATOM_AIRMONT,            freq_desc_cht),
      71                 :            :         INTEL_CPU_FAM6(ATOM_AIRMONT_MID,        freq_desc_ann),
      72                 :            :         INTEL_CPU_FAM6(ATOM_AIRMONT_NP,         freq_desc_lgm),
      73                 :            :         {}
      74                 :            : };
      75                 :            : 
      76                 :            : /*
      77                 :            :  * MSR-based CPU/TSC frequency discovery for certain CPUs.
      78                 :            :  *
      79                 :            :  * Set global "lapic_timer_period" to bus_clock_cycles/jiffy
      80                 :            :  * Return processor base frequency in KHz, or 0 on failure.
      81                 :            :  */
      82                 :          0 : unsigned long cpu_khz_from_msr(void)
      83                 :            : {
      84                 :          0 :         u32 lo, hi, ratio, freq;
      85                 :          0 :         const struct freq_desc *freq_desc;
      86                 :          0 :         const struct x86_cpu_id *id;
      87                 :          0 :         unsigned long res;
      88                 :            : 
      89                 :          0 :         id = x86_match_cpu(tsc_msr_cpu_ids);
      90         [ #  # ]:          0 :         if (!id)
      91                 :            :                 return 0;
      92                 :            : 
      93                 :          0 :         freq_desc = (struct freq_desc *)id->driver_data;
      94         [ #  # ]:          0 :         if (freq_desc->msr_plat) {
      95                 :          0 :                 rdmsr(MSR_PLATFORM_INFO, lo, hi);
      96                 :          0 :                 ratio = (lo >> 8) & 0xff;
      97                 :            :         } else {
      98                 :          0 :                 rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
      99                 :          0 :                 ratio = (hi >> 8) & 0x1f;
     100                 :            :         }
     101                 :            : 
     102                 :            :         /* Get FSB FREQ ID */
     103                 :          0 :         rdmsr(MSR_FSB_FREQ, lo, hi);
     104                 :            : 
     105                 :            :         /* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */
     106                 :          0 :         freq = freq_desc->freqs[lo & 0x7];
     107                 :            : 
     108                 :            :         /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
     109                 :          0 :         res = freq * ratio;
     110                 :            : 
     111                 :            : #ifdef CONFIG_X86_LOCAL_APIC
     112                 :          0 :         lapic_timer_period = (freq * 1000) / HZ;
     113                 :            : #endif
     114                 :            : 
     115                 :            :         /*
     116                 :            :          * TSC frequency determined by MSR is always considered "known"
     117                 :            :          * because it is reported by HW.
     118                 :            :          * Another fact is that on MSR capable platforms, PIT/HPET is
     119                 :            :          * generally not available so calibration won't work at all.
     120                 :            :          */
     121                 :          0 :         setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
     122                 :            : 
     123                 :            :         /*
     124                 :            :          * Unfortunately there is no way for hardware to tell whether the
     125                 :            :          * TSC is reliable.  We were told by silicon design team that TSC
     126                 :            :          * on Atom SoCs are always "reliable". TSC is also the only
     127                 :            :          * reliable clocksource on these SoCs (HPET is either not present
     128                 :            :          * or not functional) so mark TSC reliable which removes the
     129                 :            :          * requirement for a watchdog clocksource.
     130                 :            :          */
     131                 :          0 :         setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
     132                 :            : 
     133                 :          0 :         return res;
     134                 :            : }

Generated by: LCOV version 1.14