> Date: Sat, 22 Oct 2022 13:43:23 -0500
> From: Scott Cheloha <scottchel...@gmail.com>
> 
> On Fri, Oct 07, 2022 at 12:38:24PM -0500, Scott Cheloha wrote:
> > On Fri, Oct 07, 2022 at 11:27:45AM -0500, Scott Cheloha wrote:
> > > On Fri, Oct 07, 2022 at 09:34:46AM -0500, Scott Cheloha wrote:
> > > > On Thu, Sep 29, 2022 at 09:14:51AM -0500, Scott Cheloha wrote:
> > > > > This patch computes the TSC frequency for AMD family 17h and 19h CPUs
> > > > > (Zen microarchitecture and up) from AMD-specific MSRs.  Computing the
> > > > > TSC frequency is faster than calibrating with a separate timer and
> > > > > introduces no error.
> > > > > 
> > > > > We already do this for Intel CPUs in tsc_freq_cpuid().
> > > > > 
> > > > > I got several successful test reports on family 17h and 19h CPUs in
> > > > > response to this mail:
> > > > > 
> > > > > https://marc.info/?l=openbsd-tech&m=166394236029484&w=2
> > > > > 
> > > > > The details for computing the frequency are in the PPR for 17h and
> > > > > 19h, found here (page numbers are cited in the patch):
> > > > > 
> > > > > https://www.amd.com/system/files/TechDocs/55570-B1-PUB.zip
> > > > > https://www.amd.com/system/files/TechDocs/56214-B0-PUB.zip
> > > > > 
> > > > > The process is slightly more complicated on AMD CPU families 10h-16h.
> > > > > I will deal with them in a separate commit.
> > > > > 
> > > > > ok?
> > > > 
> > > > 1 week bump.
> > > 
> > > Whoops, forgot the patch, my mistake.
> > 
> > ... and sent the wrong patch.
> > 
> > This is patch I meant to send.  Sorry for the noise.
> 
> 3 week bump.
> 
> Is this patch ok?
> 
> I have the following tests.  Obviously the calibrated frequencies
> change from boot to boot, but I imagine they are usually in the
> ballpark of the given value.
> 
> TESTER                CALIBRATE       MSR             MACHINE
> hrovje                2994383812      3000000000      AMD EPYC 7313P 16-Core 
> Processor, 2994.38 MHz, 19-01-01
> hrovje                2650006089      2650000000      AMD EPYC 7413 24-Core 
> Processor, 2650.06 MHz, 19-01-01
> hrovje                1996256074      2000000000      AMD EPYC 7702P 64-Core 
> Processor, 1996.28 MHz, 17-31-00
> hrovje                2370556228      2375000000      AMD Ryzen 5 4500U with 
> Radeon Graphics, 2370.59 MHz, 17-60-01
> jmc           1996260074      2000000000      AMD Ryzen 7 4700U with Radeon 
> Graphics, 2000.00 MHz, 17-60-01
> Masato Asou   3593266153      3600000000      AMD Ryzen 7 3700X 8-Core 
> Processor, 3593.49 MHz, 17-71-00
> Masato Asou   2295691309      2300000000      AMD Ryzen 5 5625U with Radeon 
> Graphics, 2295.73 MHz, 19-50-00
> robert                3892696616      3900000000      AMD Ryzen 7 3800XT 
> 8-Core Processor, 3892.77 MHz, 17-71-00
> Timo Myyra    1996264149      2000000000      AMD Ryzen 5 2500U with Radeon 
> Vega Mobile Gfx, 1996.30 MHz, 17-11-00
> 
> In every case, the MSR math arrives at a frequency similar to but
> rounder than the calibrated frequency.

So the biggest change is ~800 ppm, whereas our NTP code can handle
5000 ppm.  So that's probably fine.

ok kettenis@

> Index: include/specialreg.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/include/specialreg.h,v
> retrieving revision 1.94
> diff -u -p -r1.94 specialreg.h
> --- include/specialreg.h      30 Aug 2022 17:09:21 -0000      1.94
> +++ include/specialreg.h      22 Oct 2022 18:39:57 -0000
> @@ -540,6 +540,10 @@
>   */
>  #define      MSR_HWCR        0xc0010015
>  #define              HWCR_FFDIS              0x00000040
> +#define              HWCR_TSCFREQSEL         0x01000000
> +
> +#define      MSR_PSTATEDEF(_n)       (0xc0010064 + (_n))
> +#define              PSTATEDEF_EN            0x8000000000000000ULL
>  
>  #define      MSR_NB_CFG      0xc001001f
>  #define              NB_CFG_DISIOREQLOCK     0x0000000000000004ULL
> Index: amd64/tsc.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/amd64/tsc.c,v
> retrieving revision 1.29
> diff -u -p -r1.29 tsc.c
> --- amd64/tsc.c       22 Sep 2022 04:57:08 -0000      1.29
> +++ amd64/tsc.c       22 Oct 2022 18:39:57 -0000
> @@ -100,6 +100,67 @@ tsc_freq_cpuid(struct cpu_info *ci)
>       return (0);
>  }
>  
> +uint64_t
> +tsc_freq_msr(struct cpu_info *ci)
> +{
> +     uint64_t base, def, divisor, multiplier;
> +
> +     if (strcmp(cpu_vendor, "AuthenticAMD") != 0)
> +             return 0;
> +
> +     /*
> +      * All 10h+ CPUs have Core::X86::Msr:HWCR and the TscFreqSel
> +      * bit.  If TscFreqSel hasn't been set, the TSC isn't advancing
> +      * at the core P0 frequency and we need to calibrate by hand.
> +      */
> +     if (ci->ci_family < 0x10)
> +             return 0;
> +     if (!ISSET(rdmsr(MSR_HWCR), HWCR_TSCFREQSEL))
> +             return 0;
> +
> +     /*
> +      * In 10h+ CPUs, Core::X86::Msr::PStateDef defines the voltage
> +      * and frequency for each core P-state.  We want the P0 frequency.
> +      * If the En bit isn't set, the register doesn't define a valid
> +      * P-state.
> +      */
> +     def = rdmsr(MSR_PSTATEDEF(0));
> +     if (!ISSET(def, PSTATEDEF_EN))
> +             return 0;
> +
> +     switch (ci->ci_family) {
> +     case 0x17:
> +     case 0x19:
> +             /*
> +              * PPR for AMD Family 17h [...]:
> +              * Models 01h,08h B2, Rev 3.03, pp. 33, 139-140
> +              * Model 18h B1, Rev 3.16, pp. 36, 143-144
> +              * Model 60h A1, Rev 3.06, pp. 33, 155-157
> +              * Model 71h B0, Rev 3.06, pp. 28, 150-151
> +              *
> +              * PPR for AMD Family 19h [...]:
> +              * Model 21h B0, Rev 3.05, pp. 33, 166-167
> +              *
> +              * OSRR for AMD Family 17h processors,
> +              * Models 00h-2Fh, Rev 3.03, pp. 130-131
> +              */
> +             base = 200000000;                       /* 200.0 MHz */
> +             divisor = (def >> 8) & 0x3f;
> +             if (divisor <= 0x07 || divisor >= 0x2d)
> +                     return 0;                       /* reserved */
> +             if (divisor >= 0x1b && divisor % 2 == 1)
> +                     return 0;                       /* reserved */
> +             multiplier = def & 0xff;
> +             if (multiplier <= 0x0f)
> +                     return 0;                       /* reserved */
> +             break;
> +     default:
> +             return 0;
> +     }
> +
> +     return base * multiplier / divisor;
> +}
> +
>  void
>  tsc_identify(struct cpu_info *ci)
>  {
> @@ -118,6 +179,8 @@ tsc_identify(struct cpu_info *ci)
>       tsc_is_invariant = 1;
>  
>       tsc_frequency = tsc_freq_cpuid(ci);
> +     if (tsc_frequency == 0)
> +             tsc_frequency = tsc_freq_msr(ci);
>       if (tsc_frequency > 0)
>               delay_init(tsc_delay, 5000);
>  }
> 
> 

Reply via email to