Tomáš Pecka | 4d7e909 | 2023-03-26 11:07:43 +0200 | [diff] [blame] | 1 | #include <future> |
Tomáš Pecka | d03044f | 2020-11-12 14:33:10 +0100 | [diff] [blame] | 2 | #include "Factory.h" |
Tomáš Pecka | 45b67f9 | 2024-01-11 14:13:05 +0100 | [diff] [blame^] | 3 | #include "FspYh.h" |
Tomáš Pecka | d03044f | 2020-11-12 14:33:10 +0100 | [diff] [blame] | 4 | #include "ietf-hardware/IETFHardware.h" |
| 5 | #include "ietf-hardware/sysfs/EMMC.h" |
| 6 | #include "ietf-hardware/sysfs/HWMon.h" |
| 7 | |
| 8 | namespace velia::ietf_hardware { |
Václav Kubernát | 281af6b | 2021-05-14 03:07:29 +0200 | [diff] [blame] | 9 | using velia::ietf_hardware::data_reader::EMMC; |
Tomáš Pecka | 4d7e909 | 2023-03-26 11:07:43 +0200 | [diff] [blame] | 10 | using velia::ietf_hardware::data_reader::Fans; |
Tomáš Pecka | 2a4c9f6 | 2023-03-26 10:54:57 +0200 | [diff] [blame] | 11 | using velia::ietf_hardware::data_reader::Group; |
Václav Kubernát | 281af6b | 2021-05-14 03:07:29 +0200 | [diff] [blame] | 12 | using velia::ietf_hardware::data_reader::SensorType; |
Tomáš Pecka | 4d7e909 | 2023-03-26 11:07:43 +0200 | [diff] [blame] | 13 | using velia::ietf_hardware::data_reader::StaticData; |
| 14 | using velia::ietf_hardware::data_reader::SysfsValue; |
Václav Kubernát | 281af6b | 2021-05-14 03:07:29 +0200 | [diff] [blame] | 15 | |
| 16 | void createPower(std::shared_ptr<velia::ietf_hardware::IETFHardware> ietfHardware) |
| 17 | { |
Tomáš Pecka | a96d342 | 2023-03-25 19:00:55 +0100 | [diff] [blame] | 18 | /* |
| 19 | * The order of reading hwmon files of the PDU is important. |
| 20 | * Reading properties from hwmon can trigger page change in the device which can take more than 20ms. |
| 21 | * We have therefore grouped the properties based on their page location to minimize the page changes. |
| 22 | * See linux/drivers/hwmon/pmbus/fsp-3y.c |
| 23 | */ |
Tomáš Pecka | 2a4c9f6 | 2023-03-26 10:54:57 +0200 | [diff] [blame] | 24 | auto pduHwmon = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/bus/i2c/devices/2-0025/hwmon"); |
Tomáš Pecka | a96d342 | 2023-03-25 19:00:55 +0100 | [diff] [blame] | 25 | |
Tomáš Pecka | 2a4c9f6 | 2023-03-26 10:54:57 +0200 | [diff] [blame] | 26 | Group pduGroup; |
| 27 | pduGroup.registerDataReader(StaticData("ne:pdu", "ne", {{"class", "iana-hardware:power-supply"}})); |
Tomáš Pecka | a96d342 | 2023-03-25 19:00:55 +0100 | [diff] [blame] | 28 | |
Tomáš Pecka | 66c88ef | 2023-06-12 09:18:56 +0200 | [diff] [blame] | 29 | pduGroup.registerDataReader(SysfsValue<SensorType::VoltageDC>("ne:pdu:voltage-12V", |
| 30 | "ne:pdu", |
| 31 | pduHwmon, |
| 32 | 1, |
| 33 | Thresholds<int64_t>{ |
Jan Kundrát | 70dd828 | 2023-08-24 22:57:07 +0200 | [diff] [blame] | 34 | .criticalLow = OneThreshold<int64_t>{11300, 50}, |
| 35 | .warningLow = OneThreshold<int64_t>{11500, 50}, |
| 36 | .warningHigh = OneThreshold<int64_t>{12500, 50}, |
| 37 | .criticalHigh = OneThreshold<int64_t>{12700, 50}, |
Tomáš Pecka | 66c88ef | 2023-06-12 09:18:56 +0200 | [diff] [blame] | 38 | })); |
Tomáš Pecka | 2a4c9f6 | 2023-03-26 10:54:57 +0200 | [diff] [blame] | 39 | pduGroup.registerDataReader(SysfsValue<SensorType::Current>("ne:pdu:current-12V", "ne:pdu", pduHwmon, 1)); |
| 40 | pduGroup.registerDataReader(SysfsValue<SensorType::Power>("ne:pdu:power-12V", "ne:pdu", pduHwmon, 1)); |
Tomáš Pecka | 040bd6a | 2023-06-06 12:22:15 +0200 | [diff] [blame] | 41 | pduGroup.registerDataReader(SysfsValue<SensorType::Temperature>("ne:pdu:temperature-1", |
| 42 | "ne:pdu", |
| 43 | pduHwmon, |
| 44 | 1, |
| 45 | Thresholds<int64_t>{ |
| 46 | .criticalLow = std::nullopt, |
| 47 | .warningLow = std::nullopt, |
| 48 | .warningHigh = OneThreshold<int64_t>{40000, 1000}, |
| 49 | .criticalHigh = OneThreshold<int64_t>{45000, 1000}, |
| 50 | })); |
| 51 | pduGroup.registerDataReader(SysfsValue<SensorType::Temperature>("ne:pdu:temperature-2", |
| 52 | "ne:pdu", |
| 53 | pduHwmon, |
| 54 | 2, |
| 55 | Thresholds<int64_t>{ |
| 56 | .criticalLow = std::nullopt, |
| 57 | .warningLow = std::nullopt, |
| 58 | .warningHigh = OneThreshold<int64_t>{40000, 1000}, |
| 59 | .criticalHigh = OneThreshold<int64_t>{45000, 1000}, |
| 60 | })); |
| 61 | pduGroup.registerDataReader(SysfsValue<SensorType::Temperature>("ne:pdu:temperature-3", |
| 62 | "ne:pdu", |
| 63 | pduHwmon, |
| 64 | 3, |
| 65 | Thresholds<int64_t>{ |
| 66 | .criticalLow = std::nullopt, |
| 67 | .warningLow = std::nullopt, |
| 68 | .warningHigh = OneThreshold<int64_t>{40000, 1000}, |
| 69 | .criticalHigh = OneThreshold<int64_t>{45000, 1000}, |
| 70 | })); |
Tomáš Pecka | a96d342 | 2023-03-25 19:00:55 +0100 | [diff] [blame] | 71 | |
Tomáš Pecka | 66c88ef | 2023-06-12 09:18:56 +0200 | [diff] [blame] | 72 | pduGroup.registerDataReader(SysfsValue<SensorType::VoltageDC>("ne:pdu:voltage-5V", |
| 73 | "ne:pdu", |
| 74 | pduHwmon, |
| 75 | 2, |
| 76 | Thresholds<int64_t>{ |
Jan Kundrát | 70dd828 | 2023-08-24 22:57:07 +0200 | [diff] [blame] | 77 | .criticalLow = OneThreshold<int64_t>{4600, 50}, |
| 78 | .warningLow = OneThreshold<int64_t>{4700, 50}, |
| 79 | .warningHigh = OneThreshold<int64_t>{5300, 50}, |
| 80 | .criticalHigh = OneThreshold<int64_t>{5400, 50}, |
Tomáš Pecka | 66c88ef | 2023-06-12 09:18:56 +0200 | [diff] [blame] | 81 | })); |
Tomáš Pecka | 2a4c9f6 | 2023-03-26 10:54:57 +0200 | [diff] [blame] | 82 | pduGroup.registerDataReader(SysfsValue<SensorType::Current>("ne:pdu:current-5V", "ne:pdu", pduHwmon, 2)); |
| 83 | pduGroup.registerDataReader(SysfsValue<SensorType::Power>("ne:pdu:power-5V", "ne:pdu", pduHwmon, 2)); |
| 84 | |
Tomáš Pecka | 66c88ef | 2023-06-12 09:18:56 +0200 | [diff] [blame] | 85 | pduGroup.registerDataReader(SysfsValue<SensorType::VoltageDC>("ne:pdu:voltage-3V3", |
| 86 | "ne:pdu", |
| 87 | pduHwmon, |
| 88 | 3, |
| 89 | Thresholds<int64_t>{ |
Jan Kundrát | 70dd828 | 2023-08-24 22:57:07 +0200 | [diff] [blame] | 90 | .criticalLow = OneThreshold<int64_t>{3100, 25}, |
| 91 | .warningLow = OneThreshold<int64_t>{3200, 25}, |
Tomáš Pecka | 66c88ef | 2023-06-12 09:18:56 +0200 | [diff] [blame] | 92 | .warningHigh = OneThreshold<int64_t>{3400, 25}, |
Jan Kundrát | 70dd828 | 2023-08-24 22:57:07 +0200 | [diff] [blame] | 93 | .criticalHigh = OneThreshold<int64_t>{3500, 25}, |
Tomáš Pecka | 66c88ef | 2023-06-12 09:18:56 +0200 | [diff] [blame] | 94 | })); |
Tomáš Pecka | 2a4c9f6 | 2023-03-26 10:54:57 +0200 | [diff] [blame] | 95 | pduGroup.registerDataReader(SysfsValue<SensorType::Current>("ne:pdu:current-3V3", "ne:pdu", pduHwmon, 3)); |
| 96 | pduGroup.registerDataReader(SysfsValue<SensorType::Power>("ne:pdu:power-3V3", "ne:pdu", pduHwmon, 3)); |
| 97 | |
Tomáš Pecka | 4d7e909 | 2023-03-26 11:07:43 +0200 | [diff] [blame] | 98 | auto psu1 = std::make_shared<velia::ietf_hardware::FspYhPsu>("/sys/bus/i2c/devices/2-0058/hwmon", |
| 99 | "psu1", |
| 100 | std::make_shared<TransientI2C>(2, 0x58, "ym2151e")); |
| 101 | auto psu2 = std::make_shared<velia::ietf_hardware::FspYhPsu>("/sys/bus/i2c/devices/2-0059/hwmon", |
| 102 | "psu2", |
| 103 | std::make_shared<TransientI2C>(2, 0x59, "ym2151e")); |
Václav Kubernát | 281af6b | 2021-05-14 03:07:29 +0200 | [diff] [blame] | 104 | |
Tomáš Pecka | 4886db2 | 2023-05-10 10:46:15 +0200 | [diff] [blame] | 105 | struct ParallelPDUReader { |
| 106 | Group pduGroup; |
| 107 | std::shared_ptr<velia::ietf_hardware::FspYhPsu> psu1; |
| 108 | std::shared_ptr<velia::ietf_hardware::FspYhPsu> psu2; |
Václav Kubernát | 281af6b | 2021-05-14 03:07:29 +0200 | [diff] [blame] | 109 | |
Tomáš Pecka | 4886db2 | 2023-05-10 10:46:15 +0200 | [diff] [blame] | 110 | ParallelPDUReader(Group&& pduGroup, std::shared_ptr<velia::ietf_hardware::FspYhPsu> psu1, std::shared_ptr<velia::ietf_hardware::FspYhPsu> psu2) |
| 111 | : pduGroup(std::move(pduGroup)) |
| 112 | , psu1(std::move(psu1)) |
| 113 | , psu2(std::move(psu2)) |
| 114 | { |
| 115 | } |
| 116 | |
Tomáš Pecka | c0991ce | 2023-12-20 15:46:03 +0100 | [diff] [blame] | 117 | SensorPollData operator()() |
Tomáš Pecka | 4886db2 | 2023-05-10 10:46:15 +0200 | [diff] [blame] | 118 | { |
| 119 | auto psu1Reader = std::async(std::launch::async, [&] { return psu1->readValues(); }); |
| 120 | auto psu2Reader = std::async(std::launch::async, [&] { return psu2->readValues(); }); |
| 121 | auto pduReader = std::async(std::launch::async, [&] { return pduGroup(); }); |
| 122 | |
Tomáš Pecka | c0991ce | 2023-12-20 15:46:03 +0100 | [diff] [blame] | 123 | SensorPollData pollData; |
| 124 | pollData.merge(psu1Reader.get()); |
| 125 | pollData.merge(psu2Reader.get()); |
| 126 | pollData.merge(pduReader.get()); |
Tomáš Pecka | 4886db2 | 2023-05-10 10:46:15 +0200 | [diff] [blame] | 127 | |
Tomáš Pecka | c0991ce | 2023-12-20 15:46:03 +0100 | [diff] [blame] | 128 | return pollData; |
Tomáš Pecka | 4886db2 | 2023-05-10 10:46:15 +0200 | [diff] [blame] | 129 | } |
| 130 | }; |
| 131 | |
| 132 | ietfHardware->registerDataReader(ParallelPDUReader(std::move(pduGroup), psu1, psu2)); |
Václav Kubernát | 281af6b | 2021-05-14 03:07:29 +0200 | [diff] [blame] | 133 | } |
Tomáš Pecka | d03044f | 2020-11-12 14:33:10 +0100 | [diff] [blame] | 134 | |
| 135 | std::shared_ptr<IETFHardware> create(const std::string& applianceName) |
| 136 | { |
| 137 | auto ietfHardware = std::make_shared<velia::ietf_hardware::IETFHardware>(); |
| 138 | |
| 139 | if (applianceName == "czechlight-clearfog") { |
| 140 | auto hwmonFans = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/bus/i2c/devices/1-002e/hwmon/"); |
| 141 | auto sysfsTempFront = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/devices/platform/soc/soc:internal-regs/f1011100.i2c/i2c-1/1-002e/hwmon/"); |
| 142 | auto sysfsTempCpu = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/devices/virtual/thermal/thermal_zone0/"); |
| 143 | auto sysfsTempMII0 = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/devices/platform/soc/soc:internal-regs/f1072004.mdio/mdio_bus/f1072004.mdio-mii/f1072004.mdio-mii:00/hwmon/"); |
| 144 | auto sysfsTempMII1 = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/devices/platform/soc/soc:internal-regs/f1072004.mdio/mdio_bus/f1072004.mdio-mii/f1072004.mdio-mii:01/hwmon/"); |
| 145 | auto emmc = std::make_shared<velia::ietf_hardware::sysfs::EMMC>("/sys/block/mmcblk0/device/"); |
| 146 | |
Václav Kubernát | 6c17d0a | 2021-03-29 04:55:31 +0200 | [diff] [blame] | 147 | ietfHardware->registerDataReader(StaticData("ne", std::nullopt, {{"description", "Czechlight project"s}})); |
| 148 | ietfHardware->registerDataReader(StaticData("ne:ctrl", "ne", {{"class", "iana-hardware:module"}})); |
| 149 | ietfHardware->registerDataReader(Fans("ne:fans", "ne", hwmonFans, 4)); |
| 150 | ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:ctrl:temperature-front", "ne:ctrl", sysfsTempFront, 1)); |
| 151 | ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:ctrl:temperature-cpu", "ne:ctrl", sysfsTempCpu, 1)); |
| 152 | ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:ctrl:temperature-internal-0", "ne:ctrl", sysfsTempMII0, 1)); |
| 153 | ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:ctrl:temperature-internal-1", "ne:ctrl", sysfsTempMII1, 1)); |
| 154 | ietfHardware->registerDataReader(EMMC("ne:ctrl:emmc", "ne:ctrl", emmc)); |
Václav Kubernát | 281af6b | 2021-05-14 03:07:29 +0200 | [diff] [blame] | 155 | |
| 156 | createPower(ietfHardware); |
Jan Kundrát | 0163815 | 2021-02-05 19:13:25 +0100 | [diff] [blame] | 157 | } else if (applianceName == "czechlight-clearfog-g2") { |
| 158 | auto fans = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/bus/i2c/devices/1-0020/hwmon/"); |
| 159 | auto tempMainBoard = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/bus/i2c/devices/1-0048/hwmon/"); |
| 160 | auto tempFans = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/bus/i2c/devices/1-0049/hwmon/"); |
| 161 | auto tempCpu = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/devices/virtual/thermal/thermal_zone0/"); |
| 162 | auto tempMII0 = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/devices/platform/soc/soc:internal-regs/f1072004.mdio/mdio_bus/f1072004.mdio-mii/f1072004.mdio-mii:00/hwmon/"); |
| 163 | auto tempMII1 = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/devices/platform/soc/soc:internal-regs/f1072004.mdio/mdio_bus/f1072004.mdio-mii/f1072004.mdio-mii:01/hwmon/"); |
| 164 | auto emmc = std::make_shared<velia::ietf_hardware::sysfs::EMMC>("/sys/block/mmcblk0/device/"); |
| 165 | |
| 166 | /* FIXME: |
| 167 | * Publish more properties for ne element. We have an EEPROM at the PCB for storing serial numbers (etc.), but it's so far unused. We could also use U-Boot env variables |
| 168 | * This will be needed for sdn-roadm-line only. So we should also parse the model from /proc/cmdline here |
| 169 | */ |
Václav Kubernát | 6c17d0a | 2021-03-29 04:55:31 +0200 | [diff] [blame] | 170 | ietfHardware->registerDataReader(StaticData("ne", std::nullopt, {{"description", "Czechlight project"s}})); |
Jan Kundrát | 0163815 | 2021-02-05 19:13:25 +0100 | [diff] [blame] | 171 | |
Václav Kubernát | 6c17d0a | 2021-03-29 04:55:31 +0200 | [diff] [blame] | 172 | ietfHardware->registerDataReader(StaticData("ne:ctrl", "ne", {{"class", "iana-hardware:module"}})); |
Tomáš Pecka | 8bab0f0 | 2023-05-31 14:49:47 +0200 | [diff] [blame] | 173 | ietfHardware->registerDataReader(Fans("ne:fans", |
| 174 | "ne", |
| 175 | fans, |
| 176 | 4, |
| 177 | Thresholds<int64_t>{ |
| 178 | .criticalLow = OneThreshold<int64_t>{3680, 300}, /* 40 % of 9200 RPM */ |
| 179 | .warningLow = OneThreshold<int64_t>{7360, 300}, /* 80 % of 9200 RPM */ |
| 180 | .warningHigh = std::nullopt, |
| 181 | .criticalHigh = std::nullopt, |
| 182 | })); |
Václav Kubernát | 6c17d0a | 2021-03-29 04:55:31 +0200 | [diff] [blame] | 183 | ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:ctrl:temperature-front", "ne:ctrl", tempMainBoard, 1)); |
| 184 | ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:ctrl:temperature-cpu", "ne:ctrl", tempCpu, 1)); |
| 185 | ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:ctrl:temperature-rear", "ne:ctrl", tempFans, 1)); |
| 186 | ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:ctrl:temperature-internal-0", "ne:ctrl", tempMII0, 1)); |
| 187 | ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:ctrl:temperature-internal-1", "ne:ctrl", tempMII1, 1)); |
| 188 | ietfHardware->registerDataReader(EMMC("ne:ctrl:emmc", "ne:ctrl", emmc)); |
Václav Kubernát | 97e5ea1 | 2021-03-24 00:36:57 +0100 | [diff] [blame] | 189 | |
Václav Kubernát | 281af6b | 2021-05-14 03:07:29 +0200 | [diff] [blame] | 190 | createPower(ietfHardware); |
Tomáš Pecka | d03044f | 2020-11-12 14:33:10 +0100 | [diff] [blame] | 191 | } else { |
| 192 | throw std::runtime_error("Unknown appliance '" + applianceName + "'"); |
| 193 | } |
| 194 | |
| 195 | return ietfHardware; |
| 196 | } |
| 197 | |
| 198 | } |