Add support for Global\\Access_PCI mutex
Based on the work of @moellerm
This commit is contained in:
@@ -92,26 +92,34 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (_miscellaneousControlAddress != Interop.Ring0.INVALID_PCI_ADDRESS)
|
||||
|
||||
if (Ring0.WaitPciBusMutex(10))
|
||||
{
|
||||
for (uint i = 0; i < _coreTemperatures.Length; i++)
|
||||
if (_miscellaneousControlAddress != Interop.Ring0.INVALID_PCI_ADDRESS)
|
||||
{
|
||||
if (Ring0.WritePciConfig(_miscellaneousControlAddress, THERMTRIP_STATUS_REGISTER, i > 0 ? _thermSenseCoreSelCPU1 : _thermSenseCoreSelCPU0))
|
||||
for (uint i = 0; i < _coreTemperatures.Length; i++)
|
||||
{
|
||||
if (Ring0.ReadPciConfig(_miscellaneousControlAddress, THERMTRIP_STATUS_REGISTER, out uint value))
|
||||
if (Ring0.WritePciConfig(_miscellaneousControlAddress,
|
||||
THERMTRIP_STATUS_REGISTER,
|
||||
i > 0 ? _thermSenseCoreSelCPU1 : _thermSenseCoreSelCPU0))
|
||||
{
|
||||
_coreTemperatures[i].Value = ((value >> 16) & 0xFF) + _coreTemperatures[i].Parameters[0].Value;
|
||||
ActivateSensor(_coreTemperatures[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateSensor(_coreTemperatures[i]);
|
||||
if (Ring0.ReadPciConfig(_miscellaneousControlAddress, THERMTRIP_STATUS_REGISTER, out uint value))
|
||||
{
|
||||
_coreTemperatures[i].Value = ((value >> 16) & 0xFF) + _coreTemperatures[i].Parameters[0].Value;
|
||||
ActivateSensor(_coreTemperatures[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateSensor(_coreTemperatures[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ring0.ReleasePciBusMutex();
|
||||
}
|
||||
|
||||
|
||||
if (HasTimeStampCounter)
|
||||
{
|
||||
double newBusClock = 0;
|
||||
|
||||
@@ -22,13 +22,14 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
private readonly Sensor _coreVoltage;
|
||||
private readonly byte _cStatesIoOffset;
|
||||
private readonly Sensor[] _cStatesResidency;
|
||||
private readonly bool _isSVI2;
|
||||
|
||||
private readonly bool _isSvi2;
|
||||
private readonly bool _hasSmuTemperatureRegister;
|
||||
private readonly uint _miscellaneousControlAddress;
|
||||
private readonly Sensor _northbridgeVoltage;
|
||||
private readonly FileStream _temperatureStream;
|
||||
private readonly double _timeStampCounterMultiplier;
|
||||
|
||||
|
||||
public Amd10Cpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings)
|
||||
{
|
||||
// AMD family 1Xh processors support only one temperature sensor
|
||||
@@ -38,7 +39,8 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
ActivateSensor(_coreVoltage);
|
||||
_northbridgeVoltage = new Sensor("Northbridge", 0, SensorType.Voltage, this, settings);
|
||||
ActivateSensor(_northbridgeVoltage);
|
||||
_isSVI2 = (_family == 0x15 && _model >= 0x10) || _family == 0x16;
|
||||
|
||||
_isSvi2 = (_family == 0x15 && _model >= 0x10) || _family == 0x16;
|
||||
|
||||
switch (_family)
|
||||
{
|
||||
@@ -82,9 +84,15 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
break;
|
||||
}
|
||||
case 0x70:
|
||||
case 0x60:
|
||||
{
|
||||
miscellaneousControlDeviceId = FAMILY_15H_MODEL_70_MISC_CONTROL_DEVICE_ID;
|
||||
_hasSmuTemperatureRegister = true;
|
||||
break;
|
||||
}
|
||||
case 0x60:
|
||||
{
|
||||
miscellaneousControlDeviceId = FAMILY_15H_MODEL_60_MISC_CONTROL_DEVICE_ID;
|
||||
_hasSmuTemperatureRegister = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -394,34 +402,34 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
{
|
||||
if (_miscellaneousControlAddress != Interop.Ring0.INVALID_PCI_ADDRESS)
|
||||
{
|
||||
uint value;
|
||||
if (_miscellaneousControlAddress == FAMILY_15H_MODEL_60_MISC_CONTROL_DEVICE_ID)
|
||||
{
|
||||
Ring0.WritePciConfig(Ring0.GetPciAddress(0, 0, 0), 0xB8, F15H_M60H_REPORTED_TEMP_CTRL_OFFSET);
|
||||
Ring0.ReadPciConfig(Ring0.GetPciAddress(0, 0, 0), 0xBC, out value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ring0.ReadPciConfig(_miscellaneousControlAddress, REPORTED_TEMPERATURE_CONTROL_REGISTER, out value);
|
||||
}
|
||||
bool isValueValid = _hasSmuTemperatureRegister
|
||||
? ReadSmuRegister(SMU_REPORTED_TEMP_CTRL_OFFSET, out uint value)
|
||||
: Ring0.ReadPciConfig(_miscellaneousControlAddress, REPORTED_TEMPERATURE_CONTROL_REGISTER, out value);
|
||||
|
||||
if ((_family == 0x15 || _family == 0x16) && (value & 0x30000) == 0x3000)
|
||||
if (isValueValid)
|
||||
{
|
||||
if (_family == 0x15 && (_model & 0xF0) == 0x00)
|
||||
if ((_family == 0x15 || _family == 0x16) && (value & 0x30000) == 0x3000)
|
||||
{
|
||||
_coreTemperature.Value = ((value >> 21) & 0x7FC) / 8.0f + _coreTemperature.Parameters[0].Value - 49;
|
||||
if (_family == 0x15 && (_model & 0xF0) == 0x00)
|
||||
{
|
||||
_coreTemperature.Value = ((value >> 21) & 0x7FC) / 8.0f + _coreTemperature.Parameters[0].Value - 49;
|
||||
}
|
||||
else
|
||||
{
|
||||
_coreTemperature.Value = ((value >> 21) & 0x7FF) / 8.0f + _coreTemperature.Parameters[0].Value - 49;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_coreTemperature.Value = ((value >> 21) & 0x7FF) / 8.0f + _coreTemperature.Parameters[0].Value - 49;
|
||||
_coreTemperature.Value = ((value >> 21) & 0x7FF) / 8.0f + _coreTemperature.Parameters[0].Value;
|
||||
}
|
||||
|
||||
ActivateSensor(_coreTemperature);
|
||||
}
|
||||
else
|
||||
{
|
||||
_coreTemperature.Value = ((value >> 21) & 0x7FF) / 8.0f + _coreTemperature.Parameters[0].Value;
|
||||
DeactivateSensor(_coreTemperature);
|
||||
}
|
||||
|
||||
ActivateSensor(_coreTemperature);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -468,7 +476,7 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
|
||||
float newCoreVoltage, newNbVoltage;
|
||||
uint coreVid60 = (curEax >> 9) & 0x7F;
|
||||
if (_isSVI2)
|
||||
if (_isSvi2)
|
||||
{
|
||||
newCoreVoltage = SVI2Volt(curEax >> 13 & 0x80 | coreVid60);
|
||||
newNbVoltage = SVI2Volt(curEax >> 24);
|
||||
@@ -506,6 +514,28 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
}
|
||||
}
|
||||
|
||||
private bool ReadSmuRegister(uint address, out uint value)
|
||||
{
|
||||
if (Ring0.WaitPciBusMutex(10))
|
||||
{
|
||||
if (!Ring0.WritePciConfig(0, 0xB8, address))
|
||||
{
|
||||
value = 0;
|
||||
|
||||
Ring0.ReleasePciBusMutex();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = Ring0.ReadPciConfig(0, 0xBC, out value);
|
||||
|
||||
Ring0.ReleasePciBusMutex();
|
||||
return result;
|
||||
}
|
||||
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
_temperatureStream?.Close();
|
||||
@@ -516,7 +546,7 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
private const uint CLOCK_POWER_TIMING_CONTROL_0_REGISTER = 0xD4;
|
||||
private const uint COFVID_STATUS = 0xC0010071;
|
||||
private const uint CSTATES_IO_PORT = 0xCD6;
|
||||
private const uint F15H_M60H_REPORTED_TEMP_CTRL_OFFSET = 0xD8200CA4;
|
||||
private const uint SMU_REPORTED_TEMP_CTRL_OFFSET = 0xD8200CA4;
|
||||
private const uint HWCR = 0xC0010015;
|
||||
private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3;
|
||||
private const uint P_STATE_0 = 0xC0010064;
|
||||
@@ -532,6 +562,7 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
private const ushort FAMILY_15H_MODEL_10_MISC_CONTROL_DEVICE_ID = 0x1403;
|
||||
private const ushort FAMILY_15H_MODEL_30_MISC_CONTROL_DEVICE_ID = 0x141D;
|
||||
private const ushort FAMILY_15H_MODEL_60_MISC_CONTROL_DEVICE_ID = 0x1573;
|
||||
private const ushort FAMILY_15H_MODEL_70_MISC_CONTROL_DEVICE_ID = 0x15B3;
|
||||
private const ushort FAMILY_16H_MODEL_00_MISC_CONTROL_DEVICE_ID = 0x1533;
|
||||
private const ushort FAMILY_16H_MODEL_30_MISC_CONTROL_DEVICE_ID = 0x1583;
|
||||
private const ushort FAMILY_17H_MODEL_00_MISC_CONTROL_DEVICE_ID = 0x1577;
|
||||
|
||||
@@ -91,18 +91,19 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
|
||||
private class Processor
|
||||
{
|
||||
private readonly Sensor _coreTemperatureTctl;
|
||||
private readonly Sensor _coreTemperatureTdie;
|
||||
private readonly Sensor _coreTemperatureTctlTdie;
|
||||
private readonly Sensor[] _ccdTemperatures;
|
||||
private readonly Sensor _coreTemperatureTctl;
|
||||
private readonly Sensor _coreTemperatureTctlTdie;
|
||||
private readonly Sensor _coreTemperatureTdie;
|
||||
private readonly Sensor _coreVoltage;
|
||||
private readonly Amd17Cpu _hardware;
|
||||
private readonly Sensor _packagePower;
|
||||
private readonly Sensor _socVoltage;
|
||||
private Sensor _ccdsMaxTemperature;
|
||||
private Sensor _ccdsAverageTemperature;
|
||||
private Sensor _ccdsMaxTemperature;
|
||||
private DateTime _lastPwrTime = new DateTime(0);
|
||||
private uint _lastPwrValue;
|
||||
private Sensor _busClock;
|
||||
|
||||
public Processor(Hardware hardware)
|
||||
{
|
||||
@@ -116,7 +117,8 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
_ccdTemperatures = new Sensor[8]; // Hardcoded until there's a way to get max CCDs.
|
||||
_coreVoltage = new Sensor("Core (SVI2 TFN)", _hardware._sensorVoltage++, SensorType.Voltage, _hardware, _hardware._settings);
|
||||
_socVoltage = new Sensor("SoC (SVI2 TFN)", _hardware._sensorVoltage++, SensorType.Voltage, _hardware, _hardware._settings);
|
||||
|
||||
_busClock = new Sensor("Bus Speed", 0, SensorType.Clock, _hardware, _hardware._settings);
|
||||
|
||||
_hardware.ActivateSensor(_packagePower);
|
||||
}
|
||||
|
||||
@@ -143,177 +145,186 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
// total_energy [31:0]
|
||||
DateTime sampleTime = DateTime.Now;
|
||||
Ring0.ReadMsr(MSR_PKG_ENERGY_STAT, out uint eax, out _);
|
||||
|
||||
uint totalEnergy = eax;
|
||||
|
||||
// THM_TCON_CUR_TMP
|
||||
// CUR_TEMP [31:21]
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_THM_TCON_CUR_TMP);
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint temperature);
|
||||
uint smuSvi0Tfn = 0;
|
||||
uint smuSvi0TelPlane0 = 0;
|
||||
uint smuSvi0TelPlane1 = 0;
|
||||
|
||||
// SVI0_TFN_PLANE0 [0]
|
||||
// SVI0_TFN_PLANE1 [1]
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0x8);
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint smuSvi0Tfn);
|
||||
|
||||
uint sviPlane0Offset;
|
||||
uint sviPlane1Offset;
|
||||
|
||||
bool isZen2 = false;
|
||||
|
||||
// TODO: find a better way because these will probably keep changing in the future.
|
||||
switch (cpu.Model)
|
||||
if (Ring0.WaitPciBusMutex(10))
|
||||
{
|
||||
case 0x31: // Threadripper 3000.
|
||||
// THM_TCON_CUR_TMP
|
||||
// CUR_TEMP [31:21]
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_THM_TCON_CUR_TMP);
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint temperature);
|
||||
|
||||
// SVI0_TFN_PLANE0 [0]
|
||||
// SVI0_TFN_PLANE1 [1]
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0x8);
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0Tfn);
|
||||
|
||||
bool isZen2 = false;
|
||||
|
||||
// TODO: find a better way because these will probably keep changing in the future.
|
||||
|
||||
uint sviPlane0Offset;
|
||||
uint sviPlane1Offset;
|
||||
switch (cpu.Model)
|
||||
{
|
||||
sviPlane0Offset = F17H_M01H_SVI + 0x14;
|
||||
sviPlane1Offset = F17H_M01H_SVI + 0x10;
|
||||
isZen2 = true;
|
||||
break;
|
||||
case 0x31: // Threadripper 3000.
|
||||
{
|
||||
sviPlane0Offset = F17H_M01H_SVI + 0x14;
|
||||
sviPlane1Offset = F17H_M01H_SVI + 0x10;
|
||||
isZen2 = true;
|
||||
break;
|
||||
}
|
||||
case 0x71: // Zen 2.
|
||||
{
|
||||
sviPlane0Offset = F17H_M01H_SVI + 0x10;
|
||||
sviPlane1Offset = F17H_M01H_SVI + 0xC;
|
||||
isZen2 = true;
|
||||
break;
|
||||
}
|
||||
default: // Zen and Zen+.
|
||||
{
|
||||
sviPlane0Offset = F17H_M01H_SVI + 0xC;
|
||||
sviPlane1Offset = F17H_M01H_SVI + 0x10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 0x71: // Zen 2.
|
||||
|
||||
// SVI0_PLANE0_VDDCOR [24:16]
|
||||
// SVI0_PLANE0_IDDCOR [7:0]
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane0Offset);
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0TelPlane0);
|
||||
|
||||
// SVI0_PLANE1_VDDCOR [24:16]
|
||||
// SVI0_PLANE1_IDDCOR [7:0]
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane1Offset);
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0TelPlane1);
|
||||
|
||||
ThreadAffinity.Set(previousAffinity);
|
||||
|
||||
// power consumption
|
||||
// power.Value = (float) ((double)pu * 0.125);
|
||||
// esu = 15.3 micro Joule per increment
|
||||
if (_lastPwrTime.Ticks == 0)
|
||||
{
|
||||
sviPlane0Offset = F17H_M01H_SVI + 0x10;
|
||||
sviPlane1Offset = F17H_M01H_SVI + 0xC;
|
||||
isZen2 = true;
|
||||
break;
|
||||
_lastPwrTime = sampleTime;
|
||||
_lastPwrValue = totalEnergy;
|
||||
}
|
||||
default: // Zen and Zen+.
|
||||
{
|
||||
sviPlane0Offset = F17H_M01H_SVI + 0xC;
|
||||
sviPlane1Offset = F17H_M01H_SVI + 0x10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SVI0_PLANE0_VDDCOR [24:16]
|
||||
// SVI0_PLANE0_IDDCOR [7:0]
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane0Offset);
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint smuSvi0TelPlane0);
|
||||
// ticks diff
|
||||
TimeSpan time = sampleTime - _lastPwrTime;
|
||||
long pwr;
|
||||
if (_lastPwrValue <= totalEnergy)
|
||||
pwr = totalEnergy - _lastPwrValue;
|
||||
else
|
||||
pwr = (0xffffffff - _lastPwrValue) + totalEnergy;
|
||||
|
||||
// SVI0_PLANE1_VDDCOR [24:16]
|
||||
// SVI0_PLANE1_IDDCOR [7:0]
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane1Offset);
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint smuSvi0TelPlane1);
|
||||
|
||||
ThreadAffinity.Set(previousAffinity);
|
||||
|
||||
// power consumption
|
||||
// power.Value = (float) ((double)pu * 0.125);
|
||||
// esu = 15.3 micro Joule per increment
|
||||
if (_lastPwrTime.Ticks == 0)
|
||||
{
|
||||
// update for next sample
|
||||
_lastPwrTime = sampleTime;
|
||||
_lastPwrValue = totalEnergy;
|
||||
}
|
||||
|
||||
// ticks diff
|
||||
TimeSpan time = sampleTime - _lastPwrTime;
|
||||
long pwr;
|
||||
if (_lastPwrValue <= totalEnergy)
|
||||
pwr = totalEnergy - _lastPwrValue;
|
||||
else
|
||||
pwr = (0xffffffff - _lastPwrValue) + totalEnergy;
|
||||
double energy = 15.3e-6 * pwr;
|
||||
energy /= time.TotalSeconds;
|
||||
|
||||
// update for next sample
|
||||
_lastPwrTime = sampleTime;
|
||||
_lastPwrValue = totalEnergy;
|
||||
if (!double.IsNaN(energy))
|
||||
_packagePower.Value = (float)energy;
|
||||
|
||||
double energy = 15.3e-6 * pwr;
|
||||
energy /= time.TotalSeconds;
|
||||
// current temp Bit [31:21]
|
||||
// If bit 19 of the Temperature Control register is set, there is an additional offset of 49 degrees C.
|
||||
bool tempOffsetFlag = (temperature & F17H_TEMP_OFFSET_FLAG) != 0;
|
||||
temperature = (temperature >> 21) * 125;
|
||||
|
||||
if (!double.IsNaN(energy))
|
||||
_packagePower.Value = (float)energy;
|
||||
float offset = 0.0f;
|
||||
|
||||
// current temp Bit [31:21]
|
||||
//If bit 19 of the Temperature Control register is set, there is an additional offset of 49 degrees C.
|
||||
bool tempOffsetFlag = (temperature & F17H_TEMP_OFFSET_FLAG) != 0;
|
||||
temperature = (temperature >> 21) * 125;
|
||||
// Offset table: https://github.com/torvalds/linux/blob/master/drivers/hwmon/k10temp.c#L78
|
||||
if (string.IsNullOrWhiteSpace(cpu.Name))
|
||||
offset = 0;
|
||||
else if (cpu.Name.Contains("1600X") || cpu.Name.Contains("1700X") || cpu.Name.Contains("1800X"))
|
||||
offset = -20.0f;
|
||||
else if (cpu.Name.Contains("Threadripper 19") || cpu.Name.Contains("Threadripper 29"))
|
||||
offset = -27.0f;
|
||||
else if (cpu.Name.Contains("2700X"))
|
||||
offset = -10.0f;
|
||||
|
||||
float offset = 0.0f;
|
||||
float t = temperature * 0.001f;
|
||||
if (tempOffsetFlag)
|
||||
t += -49.0f;
|
||||
|
||||
// Offset table: https://github.com/torvalds/linux/blob/master/drivers/hwmon/k10temp.c#L78
|
||||
if (string.IsNullOrWhiteSpace(cpu.Name))
|
||||
offset = 0;
|
||||
else if (cpu.Name.Contains("1600X") || cpu.Name.Contains("1700X") || cpu.Name.Contains("1800X"))
|
||||
offset = -20.0f;
|
||||
else if (cpu.Name.Contains("Threadripper 19") || cpu.Name.Contains("Threadripper 29"))
|
||||
offset = -27.0f;
|
||||
else if (cpu.Name.Contains("2700X"))
|
||||
offset = -10.0f;
|
||||
|
||||
float t = temperature * 0.001f;
|
||||
if (tempOffsetFlag)
|
||||
t += -49.0f;
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
_coreTemperatureTctl.Value = t;
|
||||
_coreTemperatureTdie.Value = t + offset;
|
||||
|
||||
_hardware.ActivateSensor(_coreTemperatureTctl);
|
||||
_hardware.ActivateSensor(_coreTemperatureTdie);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Zen 2 doesn't have an offset so Tdie and Tctl are the same.
|
||||
_coreTemperatureTctlTdie.Value = t;
|
||||
_hardware.ActivateSensor(_coreTemperatureTctlTdie);
|
||||
}
|
||||
|
||||
// Tested only on R5 3600 & Threadripper 3960X.
|
||||
if (isZen2)
|
||||
{
|
||||
for (uint i = 0; i < _ccdTemperatures.Length; i++)
|
||||
if (offset < 0)
|
||||
{
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M70H_CCD1_TEMP + (i * 0x4));
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint ccdRawTemp);
|
||||
_coreTemperatureTctl.Value = t;
|
||||
_coreTemperatureTdie.Value = t + offset;
|
||||
|
||||
ccdRawTemp &= 0xFFF;
|
||||
if (ccdRawTemp == 0)
|
||||
break;
|
||||
|
||||
|
||||
float ccdTemp = ((ccdRawTemp * 125) - 305000) * 0.001f;
|
||||
if (ccdTemp > 125) // Zen 2 reports 95 degrees C max, but it might exceed that.
|
||||
break;
|
||||
|
||||
if (_ccdTemperatures[i] == null)
|
||||
{
|
||||
_hardware.ActivateSensor(_ccdTemperatures[i] = new Sensor($"CCD{i + 1} (Tdie)",
|
||||
_hardware._sensorTemperatures++,
|
||||
SensorType.Temperature,
|
||||
_hardware,
|
||||
_hardware._settings));
|
||||
}
|
||||
|
||||
_ccdTemperatures[i].Value = ccdTemp;
|
||||
_hardware.ActivateSensor(_coreTemperatureTctl);
|
||||
_hardware.ActivateSensor(_coreTemperatureTdie);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Zen 2 doesn't have an offset so Tdie and Tctl are the same.
|
||||
_coreTemperatureTctlTdie.Value = t;
|
||||
_hardware.ActivateSensor(_coreTemperatureTctlTdie);
|
||||
}
|
||||
|
||||
Sensor[] activeCcds = _ccdTemperatures.Where(x => x != null).ToArray();
|
||||
if (activeCcds.Length > 1)
|
||||
// Tested only on R5 3600 & Threadripper 3960X.
|
||||
if (isZen2)
|
||||
{
|
||||
// No need to get the max / average ccds temp if there is only one CCD.
|
||||
|
||||
if (_ccdsMaxTemperature == null)
|
||||
for (uint i = 0; i < _ccdTemperatures.Length; i++)
|
||||
{
|
||||
_hardware.ActivateSensor(_ccdsMaxTemperature = new Sensor("CCDs Max (Tdie)",
|
||||
_hardware._sensorTemperatures++,
|
||||
SensorType.Temperature,
|
||||
_hardware,
|
||||
_hardware._settings));
|
||||
Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M70H_CCD1_TEMP + (i * 0x4));
|
||||
Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint ccdRawTemp);
|
||||
|
||||
ccdRawTemp &= 0xFFF;
|
||||
if (ccdRawTemp == 0)
|
||||
break;
|
||||
|
||||
|
||||
float ccdTemp = ((ccdRawTemp * 125) - 305000) * 0.001f;
|
||||
if (ccdTemp > 125) // Zen 2 reports 95 degrees C max, but it might exceed that.
|
||||
break;
|
||||
|
||||
|
||||
if (_ccdTemperatures[i] == null)
|
||||
{
|
||||
_hardware.ActivateSensor(_ccdTemperatures[i] = new Sensor($"CCD{i + 1} (Tdie)",
|
||||
_hardware._sensorTemperatures++,
|
||||
SensorType.Temperature,
|
||||
_hardware,
|
||||
_hardware._settings));
|
||||
}
|
||||
|
||||
_ccdTemperatures[i].Value = ccdTemp;
|
||||
}
|
||||
|
||||
if (_ccdsAverageTemperature == null)
|
||||
Sensor[] activeCcds = _ccdTemperatures.Where(x => x != null).ToArray();
|
||||
if (activeCcds.Length > 1)
|
||||
{
|
||||
_hardware.ActivateSensor(_ccdsAverageTemperature = new Sensor("CCDs Average (Tdie)",
|
||||
_hardware._sensorTemperatures++,
|
||||
SensorType.Temperature,
|
||||
_hardware,
|
||||
_hardware._settings));
|
||||
}
|
||||
// No need to get the max / average ccds temp if there is only one CCD.
|
||||
|
||||
_ccdsMaxTemperature.Value = activeCcds.Max(x => x.Value);
|
||||
_ccdsAverageTemperature.Value = activeCcds.Average(x => x.Value);
|
||||
if (_ccdsMaxTemperature == null)
|
||||
{
|
||||
_hardware.ActivateSensor(_ccdsMaxTemperature = new Sensor("CCDs Max (Tdie)",
|
||||
_hardware._sensorTemperatures++,
|
||||
SensorType.Temperature,
|
||||
_hardware,
|
||||
_hardware._settings));
|
||||
}
|
||||
|
||||
if (_ccdsAverageTemperature == null)
|
||||
{
|
||||
_hardware.ActivateSensor(_ccdsAverageTemperature = new Sensor("CCDs Average (Tdie)",
|
||||
_hardware._sensorTemperatures++,
|
||||
SensorType.Temperature,
|
||||
_hardware,
|
||||
_hardware._settings));
|
||||
}
|
||||
|
||||
_ccdsMaxTemperature.Value = activeCcds.Max(x => x.Value);
|
||||
_ccdsAverageTemperature.Value = activeCcds.Average(x => x.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,6 +352,21 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
|
||||
_hardware.ActivateSensor(_socVoltage);
|
||||
}
|
||||
|
||||
double timeStampCounterMultiplier = GetTimeStampCounterMultiplier();
|
||||
if (timeStampCounterMultiplier > 0)
|
||||
{
|
||||
_busClock.Value = (float)(_hardware.TimeStampCounterFrequency / timeStampCounterMultiplier);
|
||||
_hardware.ActivateSensor(_busClock);
|
||||
}
|
||||
}
|
||||
|
||||
private double GetTimeStampCounterMultiplier()
|
||||
{
|
||||
Ring0.ReadMsr(MSR_PSTATE_0, out uint eax, out _);
|
||||
uint cpuDfsId = (eax >> 8) & 0x3f;
|
||||
uint cpuFid = eax & 0xff;
|
||||
return 2.0 * cpuFid / cpuDfsId;
|
||||
}
|
||||
|
||||
public void AppendThread(CpuId thread, int numaId, int coreId)
|
||||
@@ -533,6 +559,7 @@ namespace LibreHardwareMonitor.Hardware.CPU
|
||||
private const uint MSR_PSTATE_0 = 0xC0010064;
|
||||
private const uint MSR_PWR_UNIT = 0xC0010299;
|
||||
private const uint PERF_CTL_0 = 0xC0010000;
|
||||
|
||||
private const uint PERF_CTR_0 = 0xC0010004;
|
||||
// ReSharper restore InconsistentNaming
|
||||
}
|
||||
|
||||
@@ -22,9 +22,10 @@ namespace LibreHardwareMonitor.Hardware
|
||||
private static KernelDriver _driver;
|
||||
private static string _fileName;
|
||||
private static Mutex _isaBusMutex;
|
||||
private static Mutex _pciBusMutex;
|
||||
|
||||
private static readonly StringBuilder _report = new StringBuilder();
|
||||
|
||||
|
||||
public static bool IsOpen
|
||||
{
|
||||
get { return _driver != null; }
|
||||
@@ -217,18 +218,19 @@ namespace LibreHardwareMonitor.Hardware
|
||||
if (!_driver.IsOpen)
|
||||
_driver = null;
|
||||
|
||||
string mutexName = "Global\\Access_ISABUS.HTP.Method";
|
||||
const string isaMutexName = "Global\\Access_ISABUS.HTP.Method";
|
||||
|
||||
try
|
||||
{
|
||||
#if NETSTANDARD2_0
|
||||
_isaBusMutex = new Mutex(false, mutexName);
|
||||
_isaBusMutex = new Mutex(false, isaMutexName);
|
||||
#else
|
||||
//mutex permissions set to everyone to allow other software to access the hardware
|
||||
//otherwise other monitoring software cant access
|
||||
var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
|
||||
var securitySettings = new MutexSecurity();
|
||||
securitySettings.AddAccessRule(allowEveryoneRule);
|
||||
_isaBusMutex = new Mutex(false, mutexName, out _, securitySettings);
|
||||
_isaBusMutex = new Mutex(false, isaMutexName, out _, securitySettings);
|
||||
#endif
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
@@ -236,9 +238,29 @@ namespace LibreHardwareMonitor.Hardware
|
||||
try
|
||||
{
|
||||
#if NETSTANDARD2_0
|
||||
_isaBusMutex = Mutex.OpenExisting(mutexName);
|
||||
_isaBusMutex = Mutex.OpenExisting(isaMutexName);
|
||||
#else
|
||||
_isaBusMutex = Mutex.OpenExisting(mutexName, MutexRights.Synchronize);
|
||||
_isaBusMutex = Mutex.OpenExisting(isaMutexName, MutexRights.Synchronize);
|
||||
#endif
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
|
||||
const string pciMutexName = "Global\\Access_PCI";
|
||||
|
||||
try
|
||||
{
|
||||
_pciBusMutex = new Mutex(false, pciMutexName);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if NETSTANDARD2_0
|
||||
_pciBusMutex = Mutex.OpenExisting(pciMutexName);
|
||||
#else
|
||||
_pciBusMutex = Mutex.OpenExisting(pciMutexName, MutexRights.Synchronize);
|
||||
#endif
|
||||
}
|
||||
catch
|
||||
@@ -266,6 +288,12 @@ namespace LibreHardwareMonitor.Hardware
|
||||
_isaBusMutex = null;
|
||||
}
|
||||
|
||||
if (_pciBusMutex != null)
|
||||
{
|
||||
_pciBusMutex.Close();
|
||||
_pciBusMutex = null;
|
||||
}
|
||||
|
||||
// try to delete temporary driver file again if failed during open
|
||||
if (_fileName != null && File.Exists(_fileName))
|
||||
{
|
||||
@@ -280,7 +308,7 @@ namespace LibreHardwareMonitor.Hardware
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static string GetReport()
|
||||
{
|
||||
if (_report.Length > 0)
|
||||
@@ -321,6 +349,31 @@ namespace LibreHardwareMonitor.Hardware
|
||||
_isaBusMutex?.ReleaseMutex();
|
||||
}
|
||||
|
||||
public static bool WaitPciBusMutex(int millisecondsTimeout)
|
||||
{
|
||||
if (_pciBusMutex == null)
|
||||
return true;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
return _pciBusMutex.WaitOne(millisecondsTimeout, false);
|
||||
}
|
||||
catch (AbandonedMutexException)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReleasePciBusMutex()
|
||||
{
|
||||
_pciBusMutex?.ReleaseMutex();
|
||||
}
|
||||
|
||||
public static bool ReadMsr(uint index, out uint eax, out uint edx)
|
||||
{
|
||||
if (_driver == null)
|
||||
|
||||
Reference in New Issue
Block a user