Added AMD family 17h (Ryzen) CPU support.

This commit is contained in:
Michael Möller 2020-02-08 00:36:51 +01:00
parent f659aa0f60
commit 5748e67bf4
4 changed files with 362 additions and 10 deletions

342
Hardware/CPU/AMD17CPU.cs Normal file
View File

@ -0,0 +1,342 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
Copyright (C) 2020 Michael Möller <mmoeller@openhardwaremonitor.org>
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace OpenHardwareMonitor.Hardware.CPU {
internal sealed class AMD17CPU : AMDCPU {
private readonly Core[] cores;
private readonly Sensor coreTemperature;
private readonly Sensor tctlTemperature;
private readonly Sensor ccdMaxTemperature;
private readonly Sensor ccdAvgTemperature;
private readonly Sensor[] ccdTemperatures;
private readonly Sensor packagePowerSensor;
private readonly Sensor coresPowerSensor;
private readonly Sensor busClock;
private const uint FAMILY_17H_M01H_THM_TCON_TEMP = 0x00059800;
private const uint FAMILY_17H_M01H_THM_TCON_TEMP_RANGE_SEL = 0x80000;
private uint FAMILY_17H_M70H_CCD_TEMP(uint i) { return 0x00059954 + i * 4; }
private const uint FAMILY_17H_M70H_CCD_TEMP_VALID = 0x800;
private const uint MAX_CCD_COUNT = 8;
private const uint MSR_RAPL_PWR_UNIT = 0xC0010299;
private const uint MSR_CORE_ENERGY_STAT = 0xC001029A;
private const uint MSR_PKG_ENERGY_STAT = 0xC001029B;
private const uint MSR_P_STATE_0 = 0xC0010064;
private const uint MSR_FAMILY_17H_P_STATE = 0xc0010293;
private float energyUnitMultiplier = 0;
private uint lastEnergyConsumed;
private DateTime lastEnergyTime;
private readonly double timeStampCounterMultiplier;
private struct TctlOffsetItem {
public string Name { get; set; }
public float Offset { get; set; }
}
private IEnumerable<TctlOffsetItem> tctlOffsetItems = new[] {
new TctlOffsetItem { Name = "AMD Ryzen 5 1600X", Offset = 20.0f },
new TctlOffsetItem { Name = "AMD Ryzen 7 1700X", Offset = 20.0f },
new TctlOffsetItem { Name = "AMD Ryzen 7 1800X", Offset = 20.0f },
new TctlOffsetItem { Name = "AMD Ryzen 7 2700X", Offset = 10.0f },
new TctlOffsetItem { Name = "AMD Ryzen Threadripper 19", Offset = 27.0f },
new TctlOffsetItem { Name = "AMD Ryzen Threadripper 29", Offset = 27.0f }
};
private readonly float tctlOffset = 0.0f;
public AMD17CPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
: base(processorIndex, cpuid, settings)
{
string cpuName = cpuid[0][0].BrandString;
if (!string.IsNullOrEmpty(cpuName)) {
foreach (var item in tctlOffsetItems) {
if (cpuName.StartsWith(item.Name)) {
tctlOffset = item.Offset;
break;
}
}
}
coreTemperature = new Sensor(
"CPU Package", 0, SensorType.Temperature, this, new[] {
new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
}, this.settings);
if (tctlOffset != 0.0f)
tctlTemperature = new Sensor(
"CPU Tctl", 1, true, SensorType.Temperature, this, new[] {
new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
}, this.settings);
ccdMaxTemperature = new Sensor(
"CPU CCD Max", 2, SensorType.Temperature, this, this.settings);
ccdAvgTemperature = new Sensor(
"CPU CCD Average", 3, SensorType.Temperature, this, this.settings);
ccdTemperatures = new Sensor[MAX_CCD_COUNT];
for (int i = 0; i < MAX_CCD_COUNT; i++) {
ccdTemperatures[i] = new Sensor(
"CPU CCD #" + (i + 1), i + 4, SensorType.Temperature, this,
new[] {
new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
}, this.settings);
}
if (Ring0.Rdmsr(MSR_RAPL_PWR_UNIT, out uint eax, out _)) {
energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1F));
}
if (energyUnitMultiplier != 0) {
if (Ring0.Rdmsr(MSR_PKG_ENERGY_STAT, out uint energyConsumed, out _)) {
lastEnergyTime = DateTime.UtcNow;
lastEnergyConsumed = energyConsumed;
packagePowerSensor = new Sensor(
"CPU Package", 0, SensorType.Power, this, settings);
ActivateSensor(packagePowerSensor);
}
coresPowerSensor = new Sensor("CPU Cores", 1, SensorType.Power, this,
settings);
}
busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
timeStampCounterMultiplier = GetTimeStampCounterMultiplier();
if (timeStampCounterMultiplier > 0) {
busClock.Value = (float)(TimeStampCounterFrequency /
timeStampCounterMultiplier);
ActivateSensor(busClock);
}
this.cores = new Core[coreCount];
for (int i = 0; i < this.cores.Length; i++) {
this.cores[i] = new Core(i, cpuid[i], this, settings);
}
}
protected override uint[] GetMSRs() {
return new uint[] { MSR_P_STATE_0, MSR_FAMILY_17H_P_STATE,
MSR_RAPL_PWR_UNIT, MSR_CORE_ENERGY_STAT, MSR_PKG_ENERGY_STAT };
}
private IList<uint> GetSmnRegisters() {
var registers = new List<uint>();
registers.Add(FAMILY_17H_M01H_THM_TCON_TEMP);
for (uint i = 0; i < MAX_CCD_COUNT; i++) {
registers.Add(FAMILY_17H_M70H_CCD_TEMP(i));
}
return registers;
}
public override string GetReport() {
StringBuilder r = new StringBuilder();
r.Append(base.GetReport());
r.Append("Time Stamp Counter Multiplier: ");
r.AppendLine(timeStampCounterMultiplier.ToString(
CultureInfo.InvariantCulture));
r.AppendLine();
r.AppendLine("SMN Registers");
r.AppendLine();
r.AppendLine(" Register Value");
var registers = GetSmnRegisters();
for (int i = 0; i < registers.Count; i++)
if (ReadSmnRegister(registers[i], out uint value)) {
r.Append(" ");
r.Append(registers[i].ToString("X8", CultureInfo.InvariantCulture));
r.Append(" ");
r.Append(value.ToString("X8", CultureInfo.InvariantCulture));
r.AppendLine();
}
r.AppendLine();
return r.ToString();
}
private double GetTimeStampCounterMultiplier() {
Ring0.Rdmsr(MSR_P_STATE_0, out uint eax, out _);
uint cpuDfsId = (eax >> 8) & 0x3f;
uint cpuFid = eax & 0xff;
return 2.0 * cpuFid / cpuDfsId;
}
private bool ReadSmnRegister(uint address, out uint value) {
if (!Ring0.WritePciConfig(0, 0x60, address)) {
value = 0;
return false;
}
return Ring0.ReadPciConfig(0, 0x64, out value);
}
public override void Update() {
base.Update();
uint value;
if (ReadSmnRegister(FAMILY_17H_M01H_THM_TCON_TEMP, out value)) {
float temperature = ((value >> 21) & 0x7FF) / 8.0f;
if ((value & FAMILY_17H_M01H_THM_TCON_TEMP_RANGE_SEL) != 0)
temperature -= 49;
if (tctlTemperature != null) {
tctlTemperature.Value = temperature +
tctlTemperature.Parameters[0].Value;
ActivateSensor(tctlTemperature);
}
temperature -= tctlOffset;
coreTemperature.Value = temperature +
coreTemperature.Parameters[0].Value;
ActivateSensor(coreTemperature);
}
float maxTemperature = float.MinValue;
int ccdCount = 0;
float ccdTemperatureSum = 0;
for (uint i = 0; i < MAX_CCD_COUNT; i++) {
if (ReadSmnRegister(FAMILY_17H_M70H_CCD_TEMP(i), out value)) {
if ((value & FAMILY_17H_M70H_CCD_TEMP_VALID) == 0)
continue;
float temperature = (value & 0x7FF) / 8.0f - 49;
temperature += ccdTemperatures[i].Parameters[0].Value;
if (temperature > maxTemperature)
maxTemperature = temperature;
ccdCount++;
ccdTemperatureSum += temperature;
ccdTemperatures[i].Value = temperature;
ActivateSensor(ccdTemperatures[i]);
}
}
if (ccdCount > 1) {
ccdMaxTemperature.Value = maxTemperature;
ActivateSensor(ccdMaxTemperature);
ccdAvgTemperature.Value = ccdTemperatureSum / ccdCount;
ActivateSensor(ccdAvgTemperature);
}
if (Ring0.Rdmsr(MSR_PKG_ENERGY_STAT, out uint energyConsumed, out _)) {
DateTime time = DateTime.UtcNow;
float deltaTime = (float)(time - lastEnergyTime).TotalSeconds;
if (deltaTime > 0.01) {
packagePowerSensor.Value = energyUnitMultiplier * unchecked(
energyConsumed - lastEnergyConsumed) / deltaTime;
lastEnergyTime = time;
lastEnergyConsumed = energyConsumed;
}
}
float? coresPower = 0f;
for (int i = 0; i < cores.Length; i++) {
cores[i].Update();
coresPower += cores[i].Power;
}
coresPowerSensor.Value = coresPower;
if (coresPower.HasValue) {
ActivateSensor(coresPowerSensor);
}
}
private class Core {
private readonly AMD17CPU cpu;
private readonly ulong threadAffinityMask;
private readonly Sensor powerSensor;
private readonly Sensor clockSensor;
private DateTime lastEnergyTime;
private uint lastEnergyConsumed;
private float? power = null;
public Core(int index, CPUID[] threads, AMD17CPU cpu, ISettings settings)
{
this.cpu = cpu;
this.threadAffinityMask = 1UL << threads[0].Thread;
string coreString = cpu.CoreString(index);
this.powerSensor =
new Sensor(coreString, index + 2, SensorType.Power, cpu, settings);
this.clockSensor =
new Sensor(coreString, index + 1, SensorType.Clock, cpu, settings);
if (cpu.energyUnitMultiplier != 0) {
if (Ring0.RdmsrTx(MSR_CORE_ENERGY_STAT, out uint energyConsumed,
out _, threadAffinityMask))
{
lastEnergyTime = DateTime.UtcNow;
lastEnergyConsumed = energyConsumed;
cpu.ActivateSensor(powerSensor);
}
}
}
private double? GetMultiplier() {
if (Ring0.Rdmsr(MSR_FAMILY_17H_P_STATE, out uint eax, out _)) {
uint cpuDfsId = (eax >> 8) & 0x3f;
uint cpuFid = eax & 0xff;
return 2.0 * cpuFid / cpuDfsId;
} else {
return null;
}
}
public float? Power { get { return power; } }
public void Update() {
DateTime energyTime = DateTime.MinValue;
double? multiplier = null;
ulong mask = ThreadAffinity.Set(threadAffinityMask);
if (Ring0.Rdmsr(MSR_CORE_ENERGY_STAT, out uint energyConsumed, out _)) {
energyTime = DateTime.UtcNow;
}
multiplier = GetMultiplier();
ThreadAffinity.Set(mask);
float deltaTime = (float)(energyTime - lastEnergyTime).TotalSeconds;
if (deltaTime > 0.01) {
power = cpu.energyUnitMultiplier *
unchecked(energyConsumed - lastEnergyConsumed) / deltaTime;
powerSensor.Value = power;
lastEnergyTime = energyTime;
lastEnergyConsumed = energyConsumed;
}
if (multiplier.HasValue) {
float? clock = (float?)(multiplier * cpu.busClock.Value);
clockSensor.Value = clock;
if (clock.HasValue)
cpu.ActivateSensor(clockSensor);
}
}
}
}
}

View File

@ -4,7 +4,7 @@
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
Copyright (C) 2009-2014 Michael Möller <mmoeller@openhardwaremonitor.org>
Copyright (C) 2009-2020 Michael Möller <mmoeller@openhardwaremonitor.org>
*/
@ -104,6 +104,9 @@ namespace OpenHardwareMonitor.Hardware.CPU {
case 0x16:
hardware.Add(new AMD10CPU(index, coreThreads, settings));
break;
case 0x17:
hardware.Add(new AMD17CPU(index, coreThreads, settings));
break;
default:
hardware.Add(new GenericCPU(index, coreThreads, settings));
break;

View File

@ -4,7 +4,7 @@
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
Copyright (C) 2009-2014 Michael Möller <mmoeller@openhardwaremonitor.org>
Copyright (C) 2009-2020 Michael Möller <mmoeller@openhardwaremonitor.org>
*/
@ -178,14 +178,20 @@ namespace OpenHardwareMonitor.Hardware.CPU {
NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage);
coreMaskWith = NextLog2(maxCoreIdPerPackage);
break;
case Vendor.AMD:
uint corePerPackage;
if (maxCpuidExt >= 8)
corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
else
corePerPackage = 1;
threadMaskWith = 0;
coreMaskWith = NextLog2(corePerPackage);
case Vendor.AMD:
if (this.family == 0x17) {
coreMaskWith = (cpuidExtData[8, 2] >> 12) & 0xF;
threadMaskWith =
NextLog2(((cpuidExtData[0x1E, 1] >> 8) & 0xFF) + 1);
} else {
uint corePerPackage;
if (maxCpuidExt >= 8)
corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
else
corePerPackage = 1;
coreMaskWith = NextLog2(corePerPackage);
threadMaskWith = 0;
}
break;
default:
threadMaskWith = 0;

View File

@ -62,6 +62,7 @@
<Compile Include="Hardware\ATI\ATIGPU.cs" />
<Compile Include="Hardware\ATI\ATIGroup.cs" />
<Compile Include="Hardware\Control.cs" />
<Compile Include="Hardware\CPU\AMD17CPU.cs" />
<Compile Include="Hardware\FirmwareTable.cs" />
<Compile Include="Hardware\HDD\DebugSmart.cs" />
<Compile Include="Hardware\HDD\DriveAttributeValue.cs" />