blob: 8e4625f21df664e0c48bcaf87ff24e2c5bc8911d [file] [log] [blame]
Tomáš Pecka4d7e9092023-03-26 11:07:43 +02001#include <future>
Tomáš Peckad03044f2020-11-12 14:33:10 +01002#include "Factory.h"
Tomáš Pecka45b67f92024-01-11 14:13:05 +01003#include "FspYh.h"
Tomáš Peckad03044f2020-11-12 14:33:10 +01004#include "ietf-hardware/IETFHardware.h"
5#include "ietf-hardware/sysfs/EMMC.h"
6#include "ietf-hardware/sysfs/HWMon.h"
7
8namespace velia::ietf_hardware {
Václav Kubernát281af6b2021-05-14 03:07:29 +02009using velia::ietf_hardware::data_reader::EMMC;
Tomáš Pecka4d7e9092023-03-26 11:07:43 +020010using velia::ietf_hardware::data_reader::Fans;
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +020011using velia::ietf_hardware::data_reader::Group;
Václav Kubernát281af6b2021-05-14 03:07:29 +020012using velia::ietf_hardware::data_reader::SensorType;
Tomáš Pecka4d7e9092023-03-26 11:07:43 +020013using velia::ietf_hardware::data_reader::StaticData;
14using velia::ietf_hardware::data_reader::SysfsValue;
Václav Kubernát281af6b2021-05-14 03:07:29 +020015
16void createPower(std::shared_ptr<velia::ietf_hardware::IETFHardware> ietfHardware)
17{
Tomáš Peckaa96d3422023-03-25 19:00:55 +010018 /*
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áš Pecka2a4c9f62023-03-26 10:54:57 +020024 auto pduHwmon = std::make_shared<velia::ietf_hardware::sysfs::HWMon>("/sys/bus/i2c/devices/2-0025/hwmon");
Tomáš Peckaa96d3422023-03-25 19:00:55 +010025
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +020026 Group pduGroup;
27 pduGroup.registerDataReader(StaticData("ne:pdu", "ne", {{"class", "iana-hardware:power-supply"}}));
Tomáš Peckaa96d3422023-03-25 19:00:55 +010028
Tomáš Pecka66c88ef2023-06-12 09:18:56 +020029 pduGroup.registerDataReader(SysfsValue<SensorType::VoltageDC>("ne:pdu:voltage-12V",
30 "ne:pdu",
31 pduHwmon,
32 1,
33 Thresholds<int64_t>{
Jan Kundrát70dd8282023-08-24 22:57:07 +020034 .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áš Pecka66c88ef2023-06-12 09:18:56 +020038 }));
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +020039 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áš Pecka040bd6a2023-06-06 12:22:15 +020041 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áš Peckaa96d3422023-03-25 19:00:55 +010071
Tomáš Pecka66c88ef2023-06-12 09:18:56 +020072 pduGroup.registerDataReader(SysfsValue<SensorType::VoltageDC>("ne:pdu:voltage-5V",
73 "ne:pdu",
74 pduHwmon,
75 2,
76 Thresholds<int64_t>{
Jan Kundrát70dd8282023-08-24 22:57:07 +020077 .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áš Pecka66c88ef2023-06-12 09:18:56 +020081 }));
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +020082 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áš Pecka66c88ef2023-06-12 09:18:56 +020085 pduGroup.registerDataReader(SysfsValue<SensorType::VoltageDC>("ne:pdu:voltage-3V3",
86 "ne:pdu",
87 pduHwmon,
88 3,
89 Thresholds<int64_t>{
Jan Kundrát70dd8282023-08-24 22:57:07 +020090 .criticalLow = OneThreshold<int64_t>{3100, 25},
91 .warningLow = OneThreshold<int64_t>{3200, 25},
Tomáš Pecka66c88ef2023-06-12 09:18:56 +020092 .warningHigh = OneThreshold<int64_t>{3400, 25},
Jan Kundrát70dd8282023-08-24 22:57:07 +020093 .criticalHigh = OneThreshold<int64_t>{3500, 25},
Tomáš Pecka66c88ef2023-06-12 09:18:56 +020094 }));
Tomáš Pecka2a4c9f62023-03-26 10:54:57 +020095 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áš Pecka4d7e9092023-03-26 11:07:43 +020098 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át281af6b2021-05-14 03:07:29 +0200104
Tomáš Pecka4886db22023-05-10 10:46:15 +0200105 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át281af6b2021-05-14 03:07:29 +0200109
Tomáš Pecka4886db22023-05-10 10:46:15 +0200110 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áš Peckac0991ce2023-12-20 15:46:03 +0100117 SensorPollData operator()()
Tomáš Pecka4886db22023-05-10 10:46:15 +0200118 {
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áš Peckac0991ce2023-12-20 15:46:03 +0100123 SensorPollData pollData;
124 pollData.merge(psu1Reader.get());
125 pollData.merge(psu2Reader.get());
126 pollData.merge(pduReader.get());
Tomáš Pecka4886db22023-05-10 10:46:15 +0200127
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100128 return pollData;
Tomáš Pecka4886db22023-05-10 10:46:15 +0200129 }
130 };
131
132 ietfHardware->registerDataReader(ParallelPDUReader(std::move(pduGroup), psu1, psu2));
Václav Kubernát281af6b2021-05-14 03:07:29 +0200133}
Tomáš Peckad03044f2020-11-12 14:33:10 +0100134
135std::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át6c17d0a2021-03-29 04:55:31 +0200147 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át281af6b2021-05-14 03:07:29 +0200155
156 createPower(ietfHardware);
Jan Kundrát01638152021-02-05 19:13:25 +0100157 } 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át6c17d0a2021-03-29 04:55:31 +0200170 ietfHardware->registerDataReader(StaticData("ne", std::nullopt, {{"description", "Czechlight project"s}}));
Jan Kundrát01638152021-02-05 19:13:25 +0100171
Václav Kubernát6c17d0a2021-03-29 04:55:31 +0200172 ietfHardware->registerDataReader(StaticData("ne:ctrl", "ne", {{"class", "iana-hardware:module"}}));
Tomáš Pecka8bab0f02023-05-31 14:49:47 +0200173 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át6c17d0a2021-03-29 04:55:31 +0200183 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át97e5ea12021-03-24 00:36:57 +0100189
Václav Kubernát281af6b2021-05-14 03:07:29 +0200190 createPower(ietfHardware);
Tomáš Peckad03044f2020-11-12 14:33:10 +0100191 } else {
192 throw std::runtime_error("Unknown appliance '" + applianceName + "'");
193 }
194
195 return ietfHardware;
196}
197
198}