From 019ed7192d182773474be98dddc2ca8e157984d6 Mon Sep 17 00:00:00 2001 From: Eugene Shalygin Date: Fri, 29 Apr 2022 17:09:18 +0200 Subject: [PATCH] Sync EC implementation to the Linux driver (#720) * EC: add CPU core voltage sensor * Introfuce BoardInfo struct for storing EC initialization data We need to keep some more information about the current board than just the sensors set and this allows us do not duplicate sensor definitions for such board variants as " (WI-FI)" when sensors are identical to the base variant. * EC: add board families * fixup! EC: add board families * EC: add Amd 400 series --- .../Hardware/Motherboard/Identification.cs | 2 + .../Motherboard/Lpc/EC/EmbeddedController.cs | 263 +++++++++++------- .../Hardware/Motherboard/Model.cs | 1 + 3 files changed, 166 insertions(+), 100 deletions(-) diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs index 56833f7..d8b480e 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs @@ -301,6 +301,8 @@ namespace LibreHardwareMonitor.Hardware.Motherboard return Model.AX370_Gaming_K7; case var _ when name.Equals("PRIME X370-PRO", StringComparison.OrdinalIgnoreCase): return Model.PRIME_X370_PRO; + case var _ when name.Equals("PRIME X470-PRO", StringComparison.OrdinalIgnoreCase): + return Model.PRIME_X470_PRO; case var _ when name.Equals("PRIME X570-PRO", StringComparison.OrdinalIgnoreCase): return Model.PRIME_X570_PRO; case var _ when name.Equals("Pro WS X570-ACE", StringComparison.OrdinalIgnoreCase): diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedController.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedController.cs index b3a069e..939f7cd 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedController.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedController.cs @@ -25,6 +25,8 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC TempTSensor, /// VRM temperature [℃] TempVrm, + /// CPU Core voltage [mV] + VoltageCPU, /// CPU_Opt fan [RPM] FanCPUOpt, /// VRM heat sink fan [RPM] @@ -44,110 +46,160 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC Max }; - private static readonly Dictionary _knownSensors = new() + private enum BoardFamily { - { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, - { ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) }, - { ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) }, - { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, - { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, - { ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) }, - { ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) }, - { ECSensor.FanChipset, new EmbeddedControllerSource("Chipset Fan", SensorType.Fan, 0x00b4, 2) }, - { ECSensor.FanWaterPump, new EmbeddedControllerSource("Water Pump", SensorType.Fan, 0x00bc, 2) }, - // TODO: "why 42?" is a silly question, I know, but still, why? On the serious side, it might be 41.6(6) - { ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00bc, 2, factor: 1.0f / 42f * 60f) }, - { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, - { ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) }, - { ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) }, + Amd400, + Amd500, + Intel100, + Intel600, + } + + private struct BoardInfo + { + public BoardInfo(Model[] models, BoardFamily family, params ECSensor[] sensors) + { + Models = models; + Family = family; + Sensors = sensors; + } + + public BoardInfo(Model model, BoardFamily family, params ECSensor[] sensors) + { + Models = new Model[] { model }; + Family = family; + Sensors = sensors; + } + + public Model[] Models { get; } + public BoardFamily Family { get; } + public ECSensor[] Sensors { get; } }; - private static readonly Dictionary _boardSensors = new() + private static readonly Dictionary> _knownSensors = new() { { - Model.PRIME_X570_PRO, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempVrm, ECSensor.TempTSensor, ECSensor.FanChipset } - }, - { - Model.PRO_WS_X570_ACE, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB , - ECSensor.TempVrm, ECSensor.FanChipset, ECSensor.CurrCPU} - }, - { - Model.ROG_CROSSHAIR_VIII_HERO, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempTSensor, ECSensor.TempVrm, ECSensor.TempWaterIn, ECSensor.TempWaterOut, - ECSensor.FanCPUOpt, ECSensor.FanChipset, ECSensor.FanWaterFlow, ECSensor.CurrCPU} - }, - { - Model.ROG_CROSSHAIR_VIII_HERO_WIFI, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempTSensor, ECSensor.TempVrm, ECSensor.TempWaterIn, ECSensor.TempWaterOut, - ECSensor.FanCPUOpt, ECSensor.FanChipset, ECSensor.FanWaterFlow, ECSensor.CurrCPU} - }, - { - Model.ROG_CROSSHAIR_VIII_DARK_HERO, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempTSensor, ECSensor.TempVrm, ECSensor.TempWaterIn, ECSensor.TempWaterOut, - ECSensor.FanCPUOpt, ECSensor.FanWaterFlow, ECSensor.CurrCPU + BoardFamily.Amd400, + new() // no chipset fans in this generation + { + { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, + { ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) }, + { ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) }, + { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, + { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, + { ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) }, + { ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00bc, 2) }, + { ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) }, + { ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00b4, 2, factor: 1.0f / 42f * 60f) }, + { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, + { ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x010d, blank: -40) }, + { ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x010b, blank: -40) }, } }, { - Model.CROSSHAIR_III_FORMULA, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempTSensor, ECSensor.TempVrm, - ECSensor.FanCPUOpt, ECSensor.FanChipset, ECSensor.CurrCPU } + BoardFamily.Amd500, + new() + { + { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, + { ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) }, + { ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) }, + { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, + { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, + { ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) }, + { ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) }, + { ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) }, + { ECSensor.FanChipset, new EmbeddedControllerSource("Chipset Fan", SensorType.Fan, 0x00b4, 2) }, + // TODO: "why 42?" is a silly question, I know, but still, why? On the serious side, it might be 41.6(6) + { ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00bc, 2, factor: 1.0f / 42f * 60f) }, + { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, + { ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) }, + { ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) }, + } }, { - Model.ROG_CROSSHAIR_VIII_IMPACT, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempTSensor, ECSensor.TempVrm, - ECSensor.FanChipset, ECSensor.CurrCPU } + BoardFamily.Intel100, + new() { + { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, + { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, + { ECSensor.FanWaterPump, new EmbeddedControllerSource("Water Pump", SensorType.Fan, 0x00bc, 2) }, + { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, + { ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) }, + } }, { - Model.ROG_STRIX_B550_E_GAMING, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempTSensor, ECSensor.TempVrm, ECSensor.FanCPUOpt } + BoardFamily.Intel600, + new() + { + { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, + { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, + } }, - { - Model.ROG_STRIX_B550_I_GAMING, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempTSensor, ECSensor.TempVrm, - ECSensor.FanVrmHS, ECSensor.CurrCPU } - }, - { - Model.ROG_STRIX_X570_E_GAMING, - new ECSensor[] { ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempTSensor, ECSensor.TempVrm, - ECSensor.FanChipset, ECSensor.CurrCPU } - }, - { - Model.ROG_STRIX_X570_F_GAMING, - new ECSensor[]{ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, - ECSensor.TempTSensor, ECSensor.FanChipset} - }, - { - Model.ROG_STRIX_X570_I_GAMING, - new ECSensor[] { - ECSensor.TempTSensor, ECSensor.FanVrmHS, ECSensor.FanChipset, ECSensor.CurrCPU } - }, - { - Model.ROG_STRIX_Z690_A_GAMING_WIFI_D4, - new ECSensor[] { - ECSensor.TempTSensor, ECSensor.TempVrm } - }, - { - Model.Z170_A, - new ECSensor[] { - ECSensor.TempTSensor, ECSensor.TempChipset, ECSensor.FanWaterPump, ECSensor.CurrCPU } - } }; - static EmbeddedController() - { - System.Diagnostics.Debug.Assert(_knownSensors.Count == ((int)ECSensor.Max)); - } + private static readonly BoardInfo[] _boards = new BoardInfo[]{ + new(Model.PRIME_X470_PRO, BoardFamily.Amd400, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempVrm, ECSensor.TempVrm, ECSensor.FanCPUOpt, + ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + new (Model.PRIME_X570_PRO, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempVrm, ECSensor.TempTSensor, ECSensor.FanChipset + ), + new(Model.PRO_WS_X570_ACE, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempVrm, ECSensor.FanChipset, ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + new(new Model[] {Model.ROG_CROSSHAIR_VIII_HERO, Model.ROG_CROSSHAIR_VIII_HERO_WIFI }, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempTSensor, ECSensor.TempVrm, ECSensor.TempWaterIn, ECSensor.TempWaterOut, + ECSensor.FanCPUOpt, ECSensor.FanChipset, ECSensor.FanWaterFlow, + ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + new(Model.ROG_CROSSHAIR_VIII_DARK_HERO, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempTSensor, ECSensor.TempVrm, ECSensor.TempWaterIn, ECSensor.TempWaterOut, + ECSensor.FanCPUOpt, ECSensor.FanWaterFlow, ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + new(Model.CROSSHAIR_III_FORMULA, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempTSensor, ECSensor.TempVrm, + ECSensor.FanCPUOpt, ECSensor.FanChipset, ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + new(Model.ROG_CROSSHAIR_VIII_IMPACT, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempTSensor, ECSensor.TempVrm, + ECSensor.FanChipset, ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + new(Model.ROG_STRIX_B550_E_GAMING, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempTSensor, ECSensor.TempVrm, ECSensor.FanCPUOpt + ), + new(Model.ROG_STRIX_B550_I_GAMING, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempTSensor, ECSensor.TempVrm, + ECSensor.FanVrmHS, ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + new(Model.ROG_STRIX_X570_E_GAMING, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempTSensor, ECSensor.TempVrm, + ECSensor.FanChipset, ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + new(Model.ROG_STRIX_X570_F_GAMING, BoardFamily.Amd500, + ECSensor.TempChipset, ECSensor.TempCPU, ECSensor.TempMB, + ECSensor.TempTSensor, ECSensor.FanChipset + ), + new(Model.ROG_STRIX_X570_I_GAMING, BoardFamily.Amd500, + ECSensor.TempTSensor, ECSensor.FanVrmHS, ECSensor.FanChipset, + ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + new(Model.ROG_STRIX_Z690_A_GAMING_WIFI_D4, BoardFamily.Intel600, + ECSensor.TempTSensor, ECSensor.TempVrm + ), + new(Model.Z170_A, BoardFamily.Intel100, + ECSensor.TempTSensor, ECSensor.TempChipset, ECSensor.FanWaterPump, + ECSensor.CurrCPU, ECSensor.VoltageCPU + ), + }; private readonly IReadOnlyList _sources; private readonly List _sensors; @@ -192,18 +244,19 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC internal static EmbeddedController Create(Model model, ISettings settings) { - if (_boardSensors.TryGetValue(model, out ECSensor[] sensors)) + var boards = _boards.Where(b => b.Models.Contains(model)).ToList(); + if (boards.Count == 0) + return null; + if (boards.Count > 1) + throw new MultipleBoardRecordsFoundException(model.ToString()); + BoardInfo board = boards[0]; + var sources = board.Sensors.Select(ecs => _knownSensors[board.Family][ecs]); + + return Environment.OSVersion.Platform switch { - var sources = sensors.Select(ecs => _knownSensors[ecs]); - - return Environment.OSVersion.Platform switch - { - PlatformID.Win32NT => new WindowsEmbeddedController(sources, settings), - _ => null - }; - } - - return null; + PlatformID.Win32NT => new WindowsEmbeddedController(sources, settings), + _ => null + }; } public override void Update() @@ -291,5 +344,15 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC public class IOException: System.IO.IOException { public IOException(string message): base($"ACPI embedded controller I/O error: {message}") { } } + + public class BadConfigurationException: System.Exception + { + public BadConfigurationException(string message): base(message) { } + } + + public class MultipleBoardRecordsFoundException : BadConfigurationException + { + public MultipleBoardRecordsFoundException(string model) : base($"Multiple board records refer to the same model '{model}'") { } + } } } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Model.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Model.cs index dc4dce9..dc8b3bc 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Model.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Model.cs @@ -62,6 +62,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard P8Z77_V, P9X79, PRIME_X370_PRO, + PRIME_X470_PRO, PRIME_X570_PRO, PRO_WS_X570_ACE, RAMPAGE_EXTREME,