124e422feSBrandon Wyman /**
224e422feSBrandon Wyman * Copyright © 2017 IBM Corporation
324e422feSBrandon Wyman *
424e422feSBrandon Wyman * Licensed under the Apache License, Version 2.0 (the "License");
524e422feSBrandon Wyman * you may not use this file except in compliance with the License.
624e422feSBrandon Wyman * You may obtain a copy of the License at
724e422feSBrandon Wyman *
824e422feSBrandon Wyman * http://www.apache.org/licenses/LICENSE-2.0
924e422feSBrandon Wyman *
1024e422feSBrandon Wyman * Unless required by applicable law or agreed to in writing, software
1124e422feSBrandon Wyman * distributed under the License is distributed on an "AS IS" BASIS,
1224e422feSBrandon Wyman * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324e422feSBrandon Wyman * See the License for the specific language governing permissions and
1424e422feSBrandon Wyman * limitations under the License.
1524e422feSBrandon Wyman */
16f0f02b9aSMatt Spinler #include "power_supply.hpp"
17f0f02b9aSMatt Spinler
18442035f0SBrandon Wyman #include "elog-errors.hpp"
19d734e65fSMatt Spinler #include "gpio.hpp"
2010295547SBrandon Wyman #include "names_values.hpp"
21442035f0SBrandon Wyman #include "pmbus.hpp"
22442035f0SBrandon Wyman #include "utility.hpp"
23442035f0SBrandon Wyman
24f0f02b9aSMatt Spinler #include <org/open_power/Witherspoon/Fault/error.hpp>
25f0f02b9aSMatt Spinler #include <phosphor-logging/elog.hpp>
26f0f02b9aSMatt Spinler #include <phosphor-logging/log.hpp>
27f0f02b9aSMatt Spinler #include <xyz/openbmc_project/Common/Device/error.hpp>
28f0f02b9aSMatt Spinler #include <xyz/openbmc_project/Software/Version/server.hpp>
29f0f02b9aSMatt Spinler
302c4fbc4cSPatrick Williams #include <functional>
312c4fbc4cSPatrick Williams
321db9a9e2SBrandon Wyman namespace witherspoon
3324e422feSBrandon Wyman {
3424e422feSBrandon Wyman namespace power
3524e422feSBrandon Wyman {
3624e422feSBrandon Wyman namespace psu
3724e422feSBrandon Wyman {
3824e422feSBrandon Wyman
39589e8726SMatt Spinler using namespace phosphor::logging;
40589e8726SMatt Spinler using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error;
41589e8726SMatt Spinler using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
42018a7bceSMatt Spinler namespace version = sdbusplus::xyz::openbmc_project::Software::server;
43589e8726SMatt Spinler
445b2964faSMatt Spinler constexpr auto ASSOCIATION_IFACE = "xyz.openbmc_project.Association";
45589e8726SMatt Spinler constexpr auto LOGGING_IFACE = "xyz.openbmc_project.Logging.Entry";
46589e8726SMatt Spinler constexpr auto INVENTORY_IFACE = "xyz.openbmc_project.Inventory.Item";
47589e8726SMatt Spinler constexpr auto POWER_IFACE = "org.openbmc.control.Power";
48018a7bceSMatt Spinler constexpr auto INVENTORY_MGR_IFACE = "xyz.openbmc_project.Inventory.Manager";
49018a7bceSMatt Spinler constexpr auto ASSET_IFACE = "xyz.openbmc_project.Inventory.Decorator.Asset";
50018a7bceSMatt Spinler constexpr auto VERSION_IFACE = "xyz.openbmc_project.Software.Version";
51589e8726SMatt Spinler
52589e8726SMatt Spinler constexpr auto ENDPOINTS_PROP = "endpoints";
53589e8726SMatt Spinler constexpr auto MESSAGE_PROP = "Message";
54589e8726SMatt Spinler constexpr auto RESOLVED_PROP = "Resolved";
5510295547SBrandon Wyman constexpr auto PRESENT_PROP = "Present";
56018a7bceSMatt Spinler constexpr auto SN_PROP = "SerialNumber";
57018a7bceSMatt Spinler constexpr auto PN_PROP = "PartNumber";
58018a7bceSMatt Spinler constexpr auto MODEL_PROP = "Model";
59018a7bceSMatt Spinler constexpr auto VERSION_PROP = "Version";
60018a7bceSMatt Spinler constexpr auto VERSION_PURPOSE_PROP = "Purpose";
61589e8726SMatt Spinler
62589e8726SMatt Spinler constexpr auto INVENTORY_OBJ_PATH = "/xyz/openbmc_project/inventory";
63431fbe43SBrandon Wyman constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0";
6410295547SBrandon Wyman
65018a7bceSMatt Spinler constexpr auto SERIAL_NUMBER = "serial_number";
66018a7bceSMatt Spinler constexpr auto PART_NUMBER = "part_number";
67018a7bceSMatt Spinler constexpr auto FW_VERSION = "fw_version";
68018a7bceSMatt Spinler constexpr auto CCIN = "ccin";
69eb169fd9SMatt Spinler constexpr auto INPUT_HISTORY = "input_history";
70018a7bceSMatt Spinler
PowerSupply(const std::string & name,size_t inst,const std::string & objpath,const std::string & invpath,sdbusplus::bus_t & bus,const sdeventplus::Event & e,std::chrono::seconds & t,std::chrono::seconds & p)7110295547SBrandon Wyman PowerSupply::PowerSupply(const std::string& name, size_t inst,
72f0f02b9aSMatt Spinler const std::string& objpath, const std::string& invpath,
731426a10bSPatrick Williams sdbusplus::bus_t& bus, const sdeventplus::Event& e,
74f0f02b9aSMatt Spinler std::chrono::seconds& t, std::chrono::seconds& p) :
75*befec58bSPatrick Williams Device(name, inst), monitorPath(objpath), pmbusIntf(objpath),
76f0f02b9aSMatt Spinler inventoryPath(INVENTORY_OBJ_PATH + invpath), bus(bus), presentInterval(p),
77f0f02b9aSMatt Spinler presentTimer(e, std::bind([this]() {
782877add8SBrandon Wyman // The hwmon path may have changed.
792877add8SBrandon Wyman pmbusIntf.findHwmonDir();
80590fc28aSBrandon Wyman this->present = true;
81234ce0d2SMatt Spinler
82d734e65fSMatt Spinler // Sync the INPUT_HISTORY data for all PSs
83d734e65fSMatt Spinler syncHistory();
84d734e65fSMatt Spinler
85234ce0d2SMatt Spinler // Update the inventory for the new device
86234ce0d2SMatt Spinler updateInventory();
871a0c9176SWilliam A. Kennington III })),
88590fc28aSBrandon Wyman powerOnInterval(t),
__anon16b4f1cd0202() 89f0f02b9aSMatt Spinler powerOnTimer(e, std::bind([this]() { this->powerOn = true; }))
9010295547SBrandon Wyman {
9110295547SBrandon Wyman using namespace sdbusplus::bus;
92817f8a7aSAatir Manzur using namespace witherspoon::pmbus;
93817f8a7aSAatir Manzur std::uint16_t statusWord = 0;
94817f8a7aSAatir Manzur try
95817f8a7aSAatir Manzur {
96817f8a7aSAatir Manzur // Read the 2 byte STATUS_WORD value to check for faults.
97817f8a7aSAatir Manzur statusWord = pmbusIntf.read(STATUS_WORD, Type::Debug);
98817f8a7aSAatir Manzur if (!((statusWord & status_word::INPUT_FAULT_WARN) ||
99817f8a7aSAatir Manzur (statusWord & status_word::VIN_UV_FAULT)))
100817f8a7aSAatir Manzur {
101817f8a7aSAatir Manzur resolveError(inventoryPath,
102817f8a7aSAatir Manzur std::string(PowerSupplyInputFault::errName));
103817f8a7aSAatir Manzur }
104817f8a7aSAatir Manzur }
105817f8a7aSAatir Manzur catch (ReadFailure& e)
106817f8a7aSAatir Manzur {
107817f8a7aSAatir Manzur log<level::INFO>("Unable to read the 2 byte STATUS_WORD value to check "
108817f8a7aSAatir Manzur "for power-supply input faults.");
109817f8a7aSAatir Manzur }
110f0f02b9aSMatt Spinler presentMatch = std::make_unique<match_t>(
111f0f02b9aSMatt Spinler bus, match::rules::propertiesChanged(inventoryPath, INVENTORY_IFACE),
__anon16b4f1cd0302(auto& msg) 112f0f02b9aSMatt Spinler [this](auto& msg) { this->inventoryChanged(msg); });
113431fbe43SBrandon Wyman // Get initial presence state.
114253dc9b9SBrandon Wyman updatePresence();
115431fbe43SBrandon Wyman
116234ce0d2SMatt Spinler // Write the SN, PN, etc to the inventory
117234ce0d2SMatt Spinler updateInventory();
118234ce0d2SMatt Spinler
119431fbe43SBrandon Wyman // Subscribe to power state changes
120f0f02b9aSMatt Spinler powerOnMatch = std::make_unique<match_t>(
121f0f02b9aSMatt Spinler bus, match::rules::propertiesChanged(POWER_OBJ_PATH, POWER_IFACE),
__anon16b4f1cd0402(auto& msg) 122f0f02b9aSMatt Spinler [this](auto& msg) { this->powerStateChanged(msg); });
123431fbe43SBrandon Wyman // Get initial power state.
124431fbe43SBrandon Wyman updatePowerState();
12510295547SBrandon Wyman }
126442035f0SBrandon Wyman
captureCmd(util::NamesValues & nv,const std::string & cmd,witherspoon::pmbus::Type type)127a1e96347SBrandon Wyman void PowerSupply::captureCmd(util::NamesValues& nv, const std::string& cmd,
128a1e96347SBrandon Wyman witherspoon::pmbus::Type type)
129a1e96347SBrandon Wyman {
130a1e96347SBrandon Wyman if (pmbusIntf.exists(cmd, type))
131a1e96347SBrandon Wyman {
132a1e96347SBrandon Wyman try
133a1e96347SBrandon Wyman {
134a1e96347SBrandon Wyman auto val = pmbusIntf.read(cmd, type);
135a1e96347SBrandon Wyman nv.add(cmd, val);
136a1e96347SBrandon Wyman }
137a1e96347SBrandon Wyman catch (std::exception& e)
138a1e96347SBrandon Wyman {
1395b48596fSJoseph Reynolds log<level::INFO>("Unable to capture metadata",
1405b48596fSJoseph Reynolds entry("CMD=%s", cmd.c_str()));
141a1e96347SBrandon Wyman }
142a1e96347SBrandon Wyman }
143a1e96347SBrandon Wyman }
144431fbe43SBrandon Wyman
analyze()1451db9a9e2SBrandon Wyman void PowerSupply::analyze()
1461db9a9e2SBrandon Wyman {
147442035f0SBrandon Wyman using namespace witherspoon::pmbus;
148442035f0SBrandon Wyman
149442035f0SBrandon Wyman try
150442035f0SBrandon Wyman {
15110295547SBrandon Wyman if (present)
15210295547SBrandon Wyman {
153764c797eSBrandon Wyman std::uint16_t statusWord = 0;
154764c797eSBrandon Wyman
155764c797eSBrandon Wyman // Read the 2 byte STATUS_WORD value to check for faults.
156764c797eSBrandon Wyman statusWord = pmbusIntf.read(STATUS_WORD, Type::Debug);
157e4af980fSBrandon Wyman readFail = 0;
158764c797eSBrandon Wyman
159603cc00fSBrandon Wyman checkInputFault(statusWord);
160764c797eSBrandon Wyman
161654eb6e9SBrandon Wyman if (powerOn && (inputFault == 0) && !faultFound)
162764c797eSBrandon Wyman {
16312661f1eSBrandon Wyman checkFanFault(statusWord);
164875b363cSBrandon Wyman checkTemperatureFault(statusWord);
165cfa032b6SBrandon Wyman checkOutputOvervoltageFault(statusWord);
166cfa032b6SBrandon Wyman checkCurrentOutOverCurrentFault(statusWord);
167cfa032b6SBrandon Wyman checkPGOrUnitOffFault(statusWord);
168442035f0SBrandon Wyman }
169eb169fd9SMatt Spinler
170eb169fd9SMatt Spinler updateHistory();
171442035f0SBrandon Wyman }
17210295547SBrandon Wyman }
173442035f0SBrandon Wyman catch (ReadFailure& e)
174442035f0SBrandon Wyman {
175e4af980fSBrandon Wyman if (readFail < FAULT_COUNT)
176e4af980fSBrandon Wyman {
177e4af980fSBrandon Wyman readFail++;
178e4af980fSBrandon Wyman }
179e4af980fSBrandon Wyman
180e4af980fSBrandon Wyman if (!readFailLogged && readFail >= FAULT_COUNT)
181442035f0SBrandon Wyman {
182442035f0SBrandon Wyman commit<ReadFailure>();
183442035f0SBrandon Wyman readFailLogged = true;
184442035f0SBrandon Wyman }
185442035f0SBrandon Wyman }
186442035f0SBrandon Wyman
1871db9a9e2SBrandon Wyman return;
1881db9a9e2SBrandon Wyman }
1891db9a9e2SBrandon Wyman
inventoryChanged(sdbusplus::message_t & msg)1901426a10bSPatrick Williams void PowerSupply::inventoryChanged(sdbusplus::message_t& msg)
19110295547SBrandon Wyman {
19210295547SBrandon Wyman std::string msgSensor;
193d7778fb0SPatrick Williams std::map<std::string, std::variant<uint32_t, bool>> msgData;
19410295547SBrandon Wyman msg.read(msgSensor, msgData);
19510295547SBrandon Wyman
19610295547SBrandon Wyman // Check if it was the Present property that changed.
19710295547SBrandon Wyman auto valPropMap = msgData.find(PRESENT_PROP);
19810295547SBrandon Wyman if (valPropMap != msgData.end())
19910295547SBrandon Wyman {
2005124fb35SPatrick Williams if (std::get<bool>(valPropMap->second))
20110295547SBrandon Wyman {
2026ccce0b8SBrandon Wyman clearFaults();
2031a0c9176SWilliam A. Kennington III presentTimer.restartOnce(presentInterval);
204590fc28aSBrandon Wyman }
205590fc28aSBrandon Wyman else
206590fc28aSBrandon Wyman {
2072ef48cf6SBrandon Wyman present = false;
2081a0c9176SWilliam A. Kennington III presentTimer.setEnabled(false);
209234ce0d2SMatt Spinler
210234ce0d2SMatt Spinler // Clear out the now outdated inventory properties
211234ce0d2SMatt Spinler updateInventory();
21210295547SBrandon Wyman }
21310295547SBrandon Wyman }
21410295547SBrandon Wyman
21510295547SBrandon Wyman return;
21610295547SBrandon Wyman }
21710295547SBrandon Wyman
updatePresence()21810295547SBrandon Wyman void PowerSupply::updatePresence()
21910295547SBrandon Wyman {
22010295547SBrandon Wyman // Use getProperty utility function to get presence status.
22110295547SBrandon Wyman std::string service = "xyz.openbmc_project.Inventory.Manager";
222f0f02b9aSMatt Spinler util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath, service,
223f0f02b9aSMatt Spinler bus, this->present);
2248731a30bSBrandon Wyman }
22510295547SBrandon Wyman
powerStateChanged(sdbusplus::message_t & msg)2261426a10bSPatrick Williams void PowerSupply::powerStateChanged(sdbusplus::message_t& msg)
227431fbe43SBrandon Wyman {
228431fbe43SBrandon Wyman int32_t state = 0;
229431fbe43SBrandon Wyman std::string msgSensor;
230d7778fb0SPatrick Williams std::map<std::string, std::variant<int32_t>> msgData;
231431fbe43SBrandon Wyman msg.read(msgSensor, msgData);
232431fbe43SBrandon Wyman
233431fbe43SBrandon Wyman // Check if it was the Present property that changed.
234431fbe43SBrandon Wyman auto valPropMap = msgData.find("state");
235431fbe43SBrandon Wyman if (valPropMap != msgData.end())
236431fbe43SBrandon Wyman {
2375124fb35SPatrick Williams state = std::get<int32_t>(valPropMap->second);
238431fbe43SBrandon Wyman
239431fbe43SBrandon Wyman // Power is on when state=1. Set the fault logged variables to false
240431fbe43SBrandon Wyman // and start the power on timer when the state changes to 1.
241431fbe43SBrandon Wyman if (state)
242431fbe43SBrandon Wyman {
2436ccce0b8SBrandon Wyman clearFaults();
2441a0c9176SWilliam A. Kennington III powerOnTimer.restartOnce(powerOnInterval);
245431fbe43SBrandon Wyman }
246431fbe43SBrandon Wyman else
247431fbe43SBrandon Wyman {
2481a0c9176SWilliam A. Kennington III powerOnTimer.setEnabled(false);
249431fbe43SBrandon Wyman powerOn = false;
250431fbe43SBrandon Wyman }
251431fbe43SBrandon Wyman }
252431fbe43SBrandon Wyman }
253431fbe43SBrandon Wyman
updatePowerState()254431fbe43SBrandon Wyman void PowerSupply::updatePowerState()
255431fbe43SBrandon Wyman {
256431fbe43SBrandon Wyman // When state = 1, system is powered on
257431fbe43SBrandon Wyman int32_t state = 0;
258431fbe43SBrandon Wyman
259431fbe43SBrandon Wyman try
260431fbe43SBrandon Wyman {
261f0f02b9aSMatt Spinler auto service = util::getService(POWER_OBJ_PATH, POWER_IFACE, bus);
262431fbe43SBrandon Wyman
263431fbe43SBrandon Wyman // Use getProperty utility function to get power state.
264f0f02b9aSMatt Spinler util::getProperty<int32_t>(POWER_IFACE, "state", POWER_OBJ_PATH,
265f0f02b9aSMatt Spinler service, bus, state);
266431fbe43SBrandon Wyman
267431fbe43SBrandon Wyman if (state)
268431fbe43SBrandon Wyman {
269431fbe43SBrandon Wyman powerOn = true;
270431fbe43SBrandon Wyman }
271431fbe43SBrandon Wyman else
272431fbe43SBrandon Wyman {
273431fbe43SBrandon Wyman powerOn = false;
274431fbe43SBrandon Wyman }
275431fbe43SBrandon Wyman }
276431fbe43SBrandon Wyman catch (std::exception& e)
277431fbe43SBrandon Wyman {
278431fbe43SBrandon Wyman log<level::INFO>("Failed to get power state. Assuming it is off.");
279431fbe43SBrandon Wyman powerOn = false;
280431fbe43SBrandon Wyman }
281431fbe43SBrandon Wyman }
282431fbe43SBrandon Wyman
checkInputFault(const uint16_t statusWord)283603cc00fSBrandon Wyman void PowerSupply::checkInputFault(const uint16_t statusWord)
284603cc00fSBrandon Wyman {
285603cc00fSBrandon Wyman using namespace witherspoon::pmbus;
286603cc00fSBrandon Wyman
287a3c675c1SBrandon Wyman if ((inputFault < FAULT_COUNT) &&
288a3c675c1SBrandon Wyman ((statusWord & status_word::INPUT_FAULT_WARN) ||
289d20686afSBrandon Wyman (statusWord & status_word::VIN_UV_FAULT)))
290603cc00fSBrandon Wyman {
291ad70824cSBrandon Wyman if (inputFault == 0)
292ad70824cSBrandon Wyman {
293ad70824cSBrandon Wyman log<level::INFO>("INPUT or VIN_UV fault",
294ad70824cSBrandon Wyman entry("STATUS_WORD=0x%04X", statusWord));
295ad70824cSBrandon Wyman }
296ad70824cSBrandon Wyman
297a3c675c1SBrandon Wyman inputFault++;
298603cc00fSBrandon Wyman }
299603cc00fSBrandon Wyman else
300603cc00fSBrandon Wyman {
301f0f02b9aSMatt Spinler if ((inputFault > 0) && !(statusWord & status_word::INPUT_FAULT_WARN) &&
302d20686afSBrandon Wyman !(statusWord & status_word::VIN_UV_FAULT))
303603cc00fSBrandon Wyman {
304a3c675c1SBrandon Wyman inputFault = 0;
3053343e828SBrandon Wyman faultFound = false;
3067502f6ccSBrandon Wyman // When an input fault occurs, the power supply cannot be on.
3077502f6ccSBrandon Wyman // However, the check for the case where the power supply should be
3087502f6ccSBrandon Wyman // on will stop when there is a fault found.
3097502f6ccSBrandon Wyman // Clear the powerOnFault when the inputFault is cleared to reset
3107502f6ccSBrandon Wyman // the powerOnFault de-glitching.
3117502f6ccSBrandon Wyman powerOnFault = 0;
31269591bd4SBrandon Wyman
313603cc00fSBrandon Wyman log<level::INFO>("INPUT_FAULT_WARN cleared",
314a3c675c1SBrandon Wyman entry("POWERSUPPLY=%s", inventoryPath.c_str()));
31569591bd4SBrandon Wyman
31608b05712SBrandon Wyman resolveError(inventoryPath,
31708b05712SBrandon Wyman std::string(PowerSupplyInputFault::errName));
31808b05712SBrandon Wyman
31969591bd4SBrandon Wyman if (powerOn)
32069591bd4SBrandon Wyman {
32169591bd4SBrandon Wyman // The power supply will not be immediately powered on after
32269591bd4SBrandon Wyman // the input power is restored.
32369591bd4SBrandon Wyman powerOn = false;
32469591bd4SBrandon Wyman // Start up the timer that will set the state to indicate we
32569591bd4SBrandon Wyman // are ready for the powered on fault checks.
3261a0c9176SWilliam A. Kennington III powerOnTimer.restartOnce(powerOnInterval);
32769591bd4SBrandon Wyman }
328603cc00fSBrandon Wyman }
329603cc00fSBrandon Wyman }
330a3c675c1SBrandon Wyman
331a3c675c1SBrandon Wyman if (!faultFound && (inputFault >= FAULT_COUNT))
332a3c675c1SBrandon Wyman {
333ad70824cSBrandon Wyman // If the power is on, report the fault in an error log entry.
334ad70824cSBrandon Wyman if (powerOn)
335ad70824cSBrandon Wyman {
336a3c675c1SBrandon Wyman util::NamesValues nv;
337a3c675c1SBrandon Wyman nv.add("STATUS_WORD", statusWord);
338a3c675c1SBrandon Wyman captureCmd(nv, STATUS_INPUT, Type::Debug);
339a3c675c1SBrandon Wyman
340f0f02b9aSMatt Spinler using metadata =
341f0f02b9aSMatt Spinler org::open_power::Witherspoon::Fault::PowerSupplyInputFault;
342a3c675c1SBrandon Wyman
343a3c675c1SBrandon Wyman report<PowerSupplyInputFault>(
344a3c675c1SBrandon Wyman metadata::RAW_STATUS(nv.get().c_str()),
345a3c675c1SBrandon Wyman metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
346ad70824cSBrandon Wyman
347a3c675c1SBrandon Wyman faultFound = true;
348a3c675c1SBrandon Wyman }
349ad70824cSBrandon Wyman }
350603cc00fSBrandon Wyman }
351603cc00fSBrandon Wyman
checkPGOrUnitOffFault(const uint16_t statusWord)352603cc00fSBrandon Wyman void PowerSupply::checkPGOrUnitOffFault(const uint16_t statusWord)
353603cc00fSBrandon Wyman {
354603cc00fSBrandon Wyman using namespace witherspoon::pmbus;
355603cc00fSBrandon Wyman
356593d24f8SBrandon Wyman if (powerOnFault < FAULT_COUNT)
357593d24f8SBrandon Wyman {
358603cc00fSBrandon Wyman // Check PG# and UNIT_IS_OFF
359593d24f8SBrandon Wyman if ((statusWord & status_word::POWER_GOOD_NEGATED) ||
360593d24f8SBrandon Wyman (statusWord & status_word::UNIT_IS_OFF))
361593d24f8SBrandon Wyman {
362593d24f8SBrandon Wyman log<level::INFO>("PGOOD or UNIT_IS_OFF bit bad",
363593d24f8SBrandon Wyman entry("STATUS_WORD=0x%04X", statusWord));
364593d24f8SBrandon Wyman powerOnFault++;
365593d24f8SBrandon Wyman }
366593d24f8SBrandon Wyman else
367593d24f8SBrandon Wyman {
368593d24f8SBrandon Wyman if (powerOnFault > 0)
369593d24f8SBrandon Wyman {
370593d24f8SBrandon Wyman log<level::INFO>("PGOOD and UNIT_IS_OFF bits good");
371593d24f8SBrandon Wyman powerOnFault = 0;
372593d24f8SBrandon Wyman }
373593d24f8SBrandon Wyman }
374593d24f8SBrandon Wyman
375e2fc7aa9SBrandon Wyman if (!faultFound && (powerOnFault >= FAULT_COUNT))
376603cc00fSBrandon Wyman {
3773343e828SBrandon Wyman faultFound = true;
3783343e828SBrandon Wyman
379603cc00fSBrandon Wyman util::NamesValues nv;
380603cc00fSBrandon Wyman nv.add("STATUS_WORD", statusWord);
381a1e96347SBrandon Wyman captureCmd(nv, STATUS_INPUT, Type::Debug);
382a1e96347SBrandon Wyman auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0);
383a1e96347SBrandon Wyman captureCmd(nv, status0Vout, Type::Debug);
384a1e96347SBrandon Wyman captureCmd(nv, STATUS_IOUT, Type::Debug);
385a1e96347SBrandon Wyman captureCmd(nv, STATUS_MFR, Type::Debug);
386603cc00fSBrandon Wyman
387f0f02b9aSMatt Spinler using metadata =
388f0f02b9aSMatt Spinler org::open_power::Witherspoon::Fault::PowerSupplyShouldBeOn;
389603cc00fSBrandon Wyman
390603cc00fSBrandon Wyman // A power supply is OFF (or pgood low) but should be on.
391593d24f8SBrandon Wyman report<PowerSupplyShouldBeOn>(
392593d24f8SBrandon Wyman metadata::RAW_STATUS(nv.get().c_str()),
393f0f02b9aSMatt Spinler metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
394593d24f8SBrandon Wyman }
395603cc00fSBrandon Wyman }
396603cc00fSBrandon Wyman }
397603cc00fSBrandon Wyman
checkCurrentOutOverCurrentFault(const uint16_t statusWord)398603cc00fSBrandon Wyman void PowerSupply::checkCurrentOutOverCurrentFault(const uint16_t statusWord)
399603cc00fSBrandon Wyman {
400603cc00fSBrandon Wyman using namespace witherspoon::pmbus;
401603cc00fSBrandon Wyman
402dd61be48SBrandon Wyman if (outputOCFault < FAULT_COUNT)
403dd61be48SBrandon Wyman {
404603cc00fSBrandon Wyman // Check for an output overcurrent fault.
405dd61be48SBrandon Wyman if ((statusWord & status_word::IOUT_OC_FAULT))
406dd61be48SBrandon Wyman {
407dd61be48SBrandon Wyman outputOCFault++;
408dd61be48SBrandon Wyman }
409dd61be48SBrandon Wyman else
410dd61be48SBrandon Wyman {
411dd61be48SBrandon Wyman if (outputOCFault > 0)
412dd61be48SBrandon Wyman {
413dd61be48SBrandon Wyman outputOCFault = 0;
414dd61be48SBrandon Wyman }
415dd61be48SBrandon Wyman }
416dd61be48SBrandon Wyman
417e2fc7aa9SBrandon Wyman if (!faultFound && (outputOCFault >= FAULT_COUNT))
418603cc00fSBrandon Wyman {
419603cc00fSBrandon Wyman util::NamesValues nv;
420603cc00fSBrandon Wyman nv.add("STATUS_WORD", statusWord);
421a1e96347SBrandon Wyman captureCmd(nv, STATUS_INPUT, Type::Debug);
422a1e96347SBrandon Wyman auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0);
423a1e96347SBrandon Wyman captureCmd(nv, status0Vout, Type::Debug);
424a1e96347SBrandon Wyman captureCmd(nv, STATUS_IOUT, Type::Debug);
425a1e96347SBrandon Wyman captureCmd(nv, STATUS_MFR, Type::Debug);
426603cc00fSBrandon Wyman
427e0eb45ccSBrandon Wyman using metadata = org::open_power::Witherspoon::Fault::
428603cc00fSBrandon Wyman PowerSupplyOutputOvercurrent;
429603cc00fSBrandon Wyman
430dd61be48SBrandon Wyman report<PowerSupplyOutputOvercurrent>(
431dd61be48SBrandon Wyman metadata::RAW_STATUS(nv.get().c_str()),
432dd61be48SBrandon Wyman metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
433603cc00fSBrandon Wyman
4343343e828SBrandon Wyman faultFound = true;
435dd61be48SBrandon Wyman }
436603cc00fSBrandon Wyman }
437603cc00fSBrandon Wyman }
438603cc00fSBrandon Wyman
checkOutputOvervoltageFault(const uint16_t statusWord)439ab05c079SBrandon Wyman void PowerSupply::checkOutputOvervoltageFault(const uint16_t statusWord)
440ab05c079SBrandon Wyman {
441ab05c079SBrandon Wyman using namespace witherspoon::pmbus;
442ab05c079SBrandon Wyman
4432ab319b0SBrandon Wyman if (outputOVFault < FAULT_COUNT)
4442ab319b0SBrandon Wyman {
445ab05c079SBrandon Wyman // Check for an output overvoltage fault.
4462ab319b0SBrandon Wyman if (statusWord & status_word::VOUT_OV_FAULT)
4472ab319b0SBrandon Wyman {
4482ab319b0SBrandon Wyman outputOVFault++;
4492ab319b0SBrandon Wyman }
4502ab319b0SBrandon Wyman else
4512ab319b0SBrandon Wyman {
4522ab319b0SBrandon Wyman if (outputOVFault > 0)
4532ab319b0SBrandon Wyman {
4542ab319b0SBrandon Wyman outputOVFault = 0;
4552ab319b0SBrandon Wyman }
4562ab319b0SBrandon Wyman }
4572ab319b0SBrandon Wyman
458e2fc7aa9SBrandon Wyman if (!faultFound && (outputOVFault >= FAULT_COUNT))
459ab05c079SBrandon Wyman {
460ab05c079SBrandon Wyman util::NamesValues nv;
461ab05c079SBrandon Wyman nv.add("STATUS_WORD", statusWord);
462a1e96347SBrandon Wyman captureCmd(nv, STATUS_INPUT, Type::Debug);
463a1e96347SBrandon Wyman auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0);
464a1e96347SBrandon Wyman captureCmd(nv, status0Vout, Type::Debug);
465a1e96347SBrandon Wyman captureCmd(nv, STATUS_IOUT, Type::Debug);
466a1e96347SBrandon Wyman captureCmd(nv, STATUS_MFR, Type::Debug);
467ab05c079SBrandon Wyman
468e0eb45ccSBrandon Wyman using metadata = org::open_power::Witherspoon::Fault::
469ab05c079SBrandon Wyman PowerSupplyOutputOvervoltage;
470ab05c079SBrandon Wyman
4712ab319b0SBrandon Wyman report<PowerSupplyOutputOvervoltage>(
4722ab319b0SBrandon Wyman metadata::RAW_STATUS(nv.get().c_str()),
4732ab319b0SBrandon Wyman metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
474ab05c079SBrandon Wyman
4753343e828SBrandon Wyman faultFound = true;
4762ab319b0SBrandon Wyman }
477ab05c079SBrandon Wyman }
478ab05c079SBrandon Wyman }
479ab05c079SBrandon Wyman
checkFanFault(const uint16_t statusWord)48012661f1eSBrandon Wyman void PowerSupply::checkFanFault(const uint16_t statusWord)
48112661f1eSBrandon Wyman {
48212661f1eSBrandon Wyman using namespace witherspoon::pmbus;
48312661f1eSBrandon Wyman
484ba25553bSBrandon Wyman if (fanFault < FAULT_COUNT)
485ba25553bSBrandon Wyman {
486875b363cSBrandon Wyman // Check for a fan fault or warning condition
487ba25553bSBrandon Wyman if (statusWord & status_word::FAN_FAULT)
488ba25553bSBrandon Wyman {
489ba25553bSBrandon Wyman fanFault++;
490ba25553bSBrandon Wyman }
491ba25553bSBrandon Wyman else
492ba25553bSBrandon Wyman {
493ba25553bSBrandon Wyman if (fanFault > 0)
494ba25553bSBrandon Wyman {
495ba25553bSBrandon Wyman fanFault = 0;
496ba25553bSBrandon Wyman }
497ba25553bSBrandon Wyman }
498ba25553bSBrandon Wyman
499e2fc7aa9SBrandon Wyman if (!faultFound && (fanFault >= FAULT_COUNT))
50012661f1eSBrandon Wyman {
50112661f1eSBrandon Wyman util::NamesValues nv;
50212661f1eSBrandon Wyman nv.add("STATUS_WORD", statusWord);
503a1e96347SBrandon Wyman captureCmd(nv, STATUS_MFR, Type::Debug);
504a1e96347SBrandon Wyman captureCmd(nv, STATUS_TEMPERATURE, Type::Debug);
505a1e96347SBrandon Wyman captureCmd(nv, STATUS_FANS_1_2, Type::Debug);
50612661f1eSBrandon Wyman
507f0f02b9aSMatt Spinler using metadata =
508f0f02b9aSMatt Spinler org::open_power::Witherspoon::Fault::PowerSupplyFanFault;
50912661f1eSBrandon Wyman
51012661f1eSBrandon Wyman report<PowerSupplyFanFault>(
51112661f1eSBrandon Wyman metadata::RAW_STATUS(nv.get().c_str()),
51212661f1eSBrandon Wyman metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
51312661f1eSBrandon Wyman
5143343e828SBrandon Wyman faultFound = true;
515ba25553bSBrandon Wyman }
51612661f1eSBrandon Wyman }
51712661f1eSBrandon Wyman }
51812661f1eSBrandon Wyman
checkTemperatureFault(const uint16_t statusWord)519875b363cSBrandon Wyman void PowerSupply::checkTemperatureFault(const uint16_t statusWord)
520875b363cSBrandon Wyman {
521875b363cSBrandon Wyman using namespace witherspoon::pmbus;
522875b363cSBrandon Wyman
523875b363cSBrandon Wyman // Due to how the PMBus core device driver sends a clear faults command
524875b363cSBrandon Wyman // the bit in STATUS_WORD will likely be cleared when we attempt to examine
525875b363cSBrandon Wyman // it for a Thermal Fault or Warning. So, check the STATUS_WORD and the
526875b363cSBrandon Wyman // STATUS_TEMPERATURE bits. If either indicates a fault, proceed with
527875b363cSBrandon Wyman // logging the over-temperature condition.
528875b363cSBrandon Wyman std::uint8_t statusTemperature = 0;
529875b363cSBrandon Wyman statusTemperature = pmbusIntf.read(STATUS_TEMPERATURE, Type::Debug);
53050044ea7SBrandon Wyman if (temperatureFault < FAULT_COUNT)
53150044ea7SBrandon Wyman {
53250044ea7SBrandon Wyman if ((statusWord & status_word::TEMPERATURE_FAULT_WARN) ||
53350044ea7SBrandon Wyman (statusTemperature & status_temperature::OT_FAULT))
53450044ea7SBrandon Wyman {
53550044ea7SBrandon Wyman temperatureFault++;
53650044ea7SBrandon Wyman }
53750044ea7SBrandon Wyman else
53850044ea7SBrandon Wyman {
53950044ea7SBrandon Wyman if (temperatureFault > 0)
54050044ea7SBrandon Wyman {
54150044ea7SBrandon Wyman temperatureFault = 0;
54250044ea7SBrandon Wyman }
54350044ea7SBrandon Wyman }
54450044ea7SBrandon Wyman
545e2fc7aa9SBrandon Wyman if (!faultFound && (temperatureFault >= FAULT_COUNT))
546875b363cSBrandon Wyman {
547875b363cSBrandon Wyman // The power supply has had an over-temperature condition.
548875b363cSBrandon Wyman // This may not result in a shutdown if experienced for a short
549875b363cSBrandon Wyman // duration.
550875b363cSBrandon Wyman // This should not occur under normal conditions.
55150044ea7SBrandon Wyman // The power supply may be faulty, or the paired supply may be
55250044ea7SBrandon Wyman // putting out less current.
553875b363cSBrandon Wyman // Capture command responses with potentially relevant information,
554875b363cSBrandon Wyman // and call out the power supply reporting the condition.
555875b363cSBrandon Wyman util::NamesValues nv;
556875b363cSBrandon Wyman nv.add("STATUS_WORD", statusWord);
557a1e96347SBrandon Wyman captureCmd(nv, STATUS_MFR, Type::Debug);
558a1e96347SBrandon Wyman captureCmd(nv, STATUS_IOUT, Type::Debug);
559875b363cSBrandon Wyman nv.add("STATUS_TEMPERATURE", statusTemperature);
560a1e96347SBrandon Wyman captureCmd(nv, STATUS_FANS_1_2, Type::Debug);
561875b363cSBrandon Wyman
562e0eb45ccSBrandon Wyman using metadata = org::open_power::Witherspoon::Fault::
563875b363cSBrandon Wyman PowerSupplyTemperatureFault;
564875b363cSBrandon Wyman
565875b363cSBrandon Wyman report<PowerSupplyTemperatureFault>(
566875b363cSBrandon Wyman metadata::RAW_STATUS(nv.get().c_str()),
567875b363cSBrandon Wyman metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
568875b363cSBrandon Wyman
5693343e828SBrandon Wyman faultFound = true;
57050044ea7SBrandon Wyman }
571875b363cSBrandon Wyman }
572875b363cSBrandon Wyman }
573875b363cSBrandon Wyman
clearFaults()5741db9a9e2SBrandon Wyman void PowerSupply::clearFaults()
5751db9a9e2SBrandon Wyman {
576e4af980fSBrandon Wyman readFail = 0;
5776ccce0b8SBrandon Wyman readFailLogged = false;
578a3c675c1SBrandon Wyman inputFault = 0;
5796ccce0b8SBrandon Wyman powerOnFault = 0;
580dd61be48SBrandon Wyman outputOCFault = 0;
5812ab319b0SBrandon Wyman outputOVFault = 0;
582ba25553bSBrandon Wyman fanFault = 0;
58350044ea7SBrandon Wyman temperatureFault = 0;
5843343e828SBrandon Wyman faultFound = false;
5856ccce0b8SBrandon Wyman
5861db9a9e2SBrandon Wyman return;
5871db9a9e2SBrandon Wyman }
5881db9a9e2SBrandon Wyman
resolveError(const std::string & callout,const std::string & message)58943ce2089SBrandon Wyman void PowerSupply::resolveError(const std::string& callout,
59043ce2089SBrandon Wyman const std::string& message)
59143ce2089SBrandon Wyman {
59201741f17SBrandon Wyman using EndpointList = std::vector<std::string>;
59301741f17SBrandon Wyman
59401741f17SBrandon Wyman try
59501741f17SBrandon Wyman {
59601741f17SBrandon Wyman auto path = callout + "/fault";
59701741f17SBrandon Wyman // Get the service name from the mapper for the fault callout
598f0f02b9aSMatt Spinler auto service = util::getService(path, ASSOCIATION_IFACE, bus);
59901741f17SBrandon Wyman
60001741f17SBrandon Wyman // Use getProperty utility function to get log entries (endpoints)
60101741f17SBrandon Wyman EndpointList logEntries;
602f0f02b9aSMatt Spinler util::getProperty(ASSOCIATION_IFACE, ENDPOINTS_PROP, path, service, bus,
603f0f02b9aSMatt Spinler logEntries);
60401741f17SBrandon Wyman
60501741f17SBrandon Wyman // It is possible that all such entries for this callout have since
60601741f17SBrandon Wyman // been deleted.
60701741f17SBrandon Wyman if (logEntries.empty())
60801741f17SBrandon Wyman {
60943ce2089SBrandon Wyman return;
61043ce2089SBrandon Wyman }
61143ce2089SBrandon Wyman
612*befec58bSPatrick Williams auto logEntryService =
613*befec58bSPatrick Williams util::getService(logEntries[0], LOGGING_IFACE, bus);
61401741f17SBrandon Wyman if (logEntryService.empty())
61501741f17SBrandon Wyman {
61601741f17SBrandon Wyman return;
61701741f17SBrandon Wyman }
61801741f17SBrandon Wyman
61901741f17SBrandon Wyman // go through each log entry that matches this callout path
62001741f17SBrandon Wyman std::string logMessage;
62101741f17SBrandon Wyman for (const auto& logEntry : logEntries)
62201741f17SBrandon Wyman {
62301741f17SBrandon Wyman // Check to see if this logEntry has a message that matches.
624589e8726SMatt Spinler util::getProperty(LOGGING_IFACE, MESSAGE_PROP, logEntry,
62501741f17SBrandon Wyman logEntryService, bus, logMessage);
62601741f17SBrandon Wyman
62701741f17SBrandon Wyman if (message == logMessage)
62801741f17SBrandon Wyman {
62901741f17SBrandon Wyman // Log entry matches call out and message, set Resolved to true
63001741f17SBrandon Wyman bool resolved = true;
631589e8726SMatt Spinler util::setProperty(LOGGING_IFACE, RESOLVED_PROP, logEntry,
63201741f17SBrandon Wyman logEntryService, bus, resolved);
63301741f17SBrandon Wyman }
63401741f17SBrandon Wyman }
63501741f17SBrandon Wyman }
63601741f17SBrandon Wyman catch (std::exception& e)
63701741f17SBrandon Wyman {
63801741f17SBrandon Wyman log<level::INFO>("Failed to resolve error",
63901741f17SBrandon Wyman entry("CALLOUT=%s", callout.c_str()),
6400d09f298SMatt Spinler entry("ERROR=%s", message.c_str()));
64101741f17SBrandon Wyman }
64201741f17SBrandon Wyman }
64301741f17SBrandon Wyman
updateInventory()644234ce0d2SMatt Spinler void PowerSupply::updateInventory()
645234ce0d2SMatt Spinler {
646018a7bceSMatt Spinler using namespace witherspoon::pmbus;
647018a7bceSMatt Spinler using namespace sdbusplus::message;
648018a7bceSMatt Spinler
649018a7bceSMatt Spinler // If any of these accesses fail, the fields will just be
650018a7bceSMatt Spinler // blank in the inventory. Leave logging ReadFailure errors
651018a7bceSMatt Spinler // to analyze() as it runs continuously and will most
652018a7bceSMatt Spinler // likely hit and threshold them first anyway. The
653018a7bceSMatt Spinler // readString() function will do the tracing of the failing
654018a7bceSMatt Spinler // path so this code doesn't need to.
655018a7bceSMatt Spinler std::string pn;
656018a7bceSMatt Spinler std::string sn;
657018a7bceSMatt Spinler std::string ccin;
658018a7bceSMatt Spinler std::string version;
659018a7bceSMatt Spinler
660018a7bceSMatt Spinler if (present)
661018a7bceSMatt Spinler {
662018a7bceSMatt Spinler try
663018a7bceSMatt Spinler {
664018a7bceSMatt Spinler sn = pmbusIntf.readString(SERIAL_NUMBER, Type::HwmonDeviceDebug);
665018a7bceSMatt Spinler }
666f0f02b9aSMatt Spinler catch (ReadFailure& e)
6672c4fbc4cSPatrick Williams {}
668018a7bceSMatt Spinler
669018a7bceSMatt Spinler try
670018a7bceSMatt Spinler {
671018a7bceSMatt Spinler pn = pmbusIntf.readString(PART_NUMBER, Type::HwmonDeviceDebug);
672018a7bceSMatt Spinler }
673f0f02b9aSMatt Spinler catch (ReadFailure& e)
6742c4fbc4cSPatrick Williams {}
675018a7bceSMatt Spinler
676018a7bceSMatt Spinler try
677018a7bceSMatt Spinler {
678018a7bceSMatt Spinler ccin = pmbusIntf.readString(CCIN, Type::HwmonDeviceDebug);
679018a7bceSMatt Spinler }
680f0f02b9aSMatt Spinler catch (ReadFailure& e)
6812c4fbc4cSPatrick Williams {}
682018a7bceSMatt Spinler
683018a7bceSMatt Spinler try
684018a7bceSMatt Spinler {
685018a7bceSMatt Spinler version = pmbusIntf.readString(FW_VERSION, Type::HwmonDeviceDebug);
686018a7bceSMatt Spinler }
687f0f02b9aSMatt Spinler catch (ReadFailure& e)
6882c4fbc4cSPatrick Williams {}
689018a7bceSMatt Spinler }
690018a7bceSMatt Spinler
691018a7bceSMatt Spinler // Build the object map and send it to the inventory
6922c4fbc4cSPatrick Williams using Properties = std::map<std::string, std::variant<std::string>>;
693018a7bceSMatt Spinler using Interfaces = std::map<std::string, Properties>;
694018a7bceSMatt Spinler using Object = std::map<object_path, Interfaces>;
695018a7bceSMatt Spinler Properties assetProps;
696018a7bceSMatt Spinler Properties versionProps;
697018a7bceSMatt Spinler Interfaces interfaces;
698018a7bceSMatt Spinler Object object;
699018a7bceSMatt Spinler
700018a7bceSMatt Spinler assetProps.emplace(SN_PROP, sn);
701018a7bceSMatt Spinler assetProps.emplace(PN_PROP, pn);
702018a7bceSMatt Spinler assetProps.emplace(MODEL_PROP, ccin);
703018a7bceSMatt Spinler interfaces.emplace(ASSET_IFACE, std::move(assetProps));
704018a7bceSMatt Spinler
705018a7bceSMatt Spinler versionProps.emplace(VERSION_PROP, version);
706018a7bceSMatt Spinler interfaces.emplace(VERSION_IFACE, std::move(versionProps));
707018a7bceSMatt Spinler
708018a7bceSMatt Spinler // For Notify(), just send the relative path of the inventory
709018a7bceSMatt Spinler // object so remove the INVENTORY_OBJ_PATH prefix
710018a7bceSMatt Spinler auto path = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
711018a7bceSMatt Spinler
712018a7bceSMatt Spinler object.emplace(path, std::move(interfaces));
713018a7bceSMatt Spinler
714018a7bceSMatt Spinler try
715018a7bceSMatt Spinler {
716*befec58bSPatrick Williams auto service =
717*befec58bSPatrick Williams util::getService(INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
718018a7bceSMatt Spinler
719018a7bceSMatt Spinler if (service.empty())
720018a7bceSMatt Spinler {
721018a7bceSMatt Spinler log<level::ERR>("Unable to get inventory manager service");
722018a7bceSMatt Spinler return;
723018a7bceSMatt Spinler }
724018a7bceSMatt Spinler
725f0f02b9aSMatt Spinler auto method = bus.new_method_call(service.c_str(), INVENTORY_OBJ_PATH,
726f0f02b9aSMatt Spinler INVENTORY_MGR_IFACE, "Notify");
727018a7bceSMatt Spinler
728018a7bceSMatt Spinler method.append(std::move(object));
729018a7bceSMatt Spinler
730018a7bceSMatt Spinler auto reply = bus.call(method);
731018a7bceSMatt Spinler
732018a7bceSMatt Spinler // TODO: openbmc/openbmc#2756
733018a7bceSMatt Spinler // Calling Notify() with an enumerated property crashes inventory
734018a7bceSMatt Spinler // manager, so let it default to Unknown and now set it to the
735018a7bceSMatt Spinler // right value.
736f0f02b9aSMatt Spinler auto purpose =
737f0f02b9aSMatt Spinler version::convertForMessage(version::Version::VersionPurpose::Other);
738018a7bceSMatt Spinler
739f0f02b9aSMatt Spinler util::setProperty(VERSION_IFACE, VERSION_PURPOSE_PROP, inventoryPath,
740f0f02b9aSMatt Spinler service, bus, purpose);
741018a7bceSMatt Spinler }
742018a7bceSMatt Spinler catch (std::exception& e)
743018a7bceSMatt Spinler {
744f0f02b9aSMatt Spinler log<level::ERR>(e.what(), entry("PATH=%s", inventoryPath.c_str()));
745018a7bceSMatt Spinler }
746234ce0d2SMatt Spinler }
747234ce0d2SMatt Spinler
syncHistory()748d734e65fSMatt Spinler void PowerSupply::syncHistory()
749d734e65fSMatt Spinler {
750d734e65fSMatt Spinler using namespace witherspoon::gpio;
751d734e65fSMatt Spinler
752d734e65fSMatt Spinler if (syncGPIODevPath.empty())
753d734e65fSMatt Spinler {
754d734e65fSMatt Spinler // Sync not implemented
755d734e65fSMatt Spinler return;
756d734e65fSMatt Spinler }
757d734e65fSMatt Spinler
758f0f02b9aSMatt Spinler GPIO gpio{syncGPIODevPath, static_cast<gpioNum_t>(syncGPIONumber),
759d734e65fSMatt Spinler Direction::output};
760d734e65fSMatt Spinler
761d734e65fSMatt Spinler try
762d734e65fSMatt Spinler {
763d734e65fSMatt Spinler gpio.set(Value::low);
764d734e65fSMatt Spinler
765d734e65fSMatt Spinler std::this_thread::sleep_for(std::chrono::milliseconds{5});
766d734e65fSMatt Spinler
767d734e65fSMatt Spinler gpio.set(Value::high);
768d734e65fSMatt Spinler
769d734e65fSMatt Spinler recordManager->clear();
770d734e65fSMatt Spinler }
771d734e65fSMatt Spinler catch (std::exception& e)
772d734e65fSMatt Spinler {
773d734e65fSMatt Spinler // Do nothing. There would already be a journal entry.
774d734e65fSMatt Spinler }
775d734e65fSMatt Spinler }
776d734e65fSMatt Spinler
enableHistory(const std::string & objectPath,size_t numRecords,const std::string & syncGPIOPath,size_t syncGPIONum)777*befec58bSPatrick Williams void PowerSupply::enableHistory(
778*befec58bSPatrick Williams const std::string& objectPath, size_t numRecords,
779*befec58bSPatrick Williams const std::string& syncGPIOPath, size_t syncGPIONum)
78082384146SMatt Spinler {
78182384146SMatt Spinler historyObjectPath = objectPath;
78282384146SMatt Spinler syncGPIODevPath = syncGPIOPath;
78382384146SMatt Spinler syncGPIONumber = syncGPIONum;
78482384146SMatt Spinler
78582384146SMatt Spinler recordManager = std::make_unique<history::RecordManager>(numRecords);
78682384146SMatt Spinler
78782384146SMatt Spinler auto avgPath = historyObjectPath + '/' + history::Average::name;
78882384146SMatt Spinler auto maxPath = historyObjectPath + '/' + history::Maximum::name;
78982384146SMatt Spinler
79082384146SMatt Spinler average = std::make_unique<history::Average>(bus, avgPath);
79182384146SMatt Spinler
79282384146SMatt Spinler maximum = std::make_unique<history::Maximum>(bus, maxPath);
79382384146SMatt Spinler }
79482384146SMatt Spinler
updateHistory()795eb169fd9SMatt Spinler void PowerSupply::updateHistory()
796eb169fd9SMatt Spinler {
797eb169fd9SMatt Spinler if (!recordManager)
798eb169fd9SMatt Spinler {
799eb169fd9SMatt Spinler // Not enabled
800eb169fd9SMatt Spinler return;
801eb169fd9SMatt Spinler }
802eb169fd9SMatt Spinler
803eb169fd9SMatt Spinler // Read just the most recent average/max record
804*befec58bSPatrick Williams auto data =
805*befec58bSPatrick Williams pmbusIntf.readBinary(INPUT_HISTORY, pmbus::Type::HwmonDeviceDebug,
806eb169fd9SMatt Spinler history::RecordManager::RAW_RECORD_SIZE);
807eb169fd9SMatt Spinler
808eb169fd9SMatt Spinler // Update D-Bus only if something changed (a new record ID, or cleared out)
809eb169fd9SMatt Spinler auto changed = recordManager->add(data);
810eb169fd9SMatt Spinler if (changed)
811eb169fd9SMatt Spinler {
81298473dbcSPatrick Williams average->values(recordManager->getAverageRecords());
81398473dbcSPatrick Williams maximum->values(recordManager->getMaximumRecords());
814eb169fd9SMatt Spinler }
815eb169fd9SMatt Spinler }
816eb169fd9SMatt Spinler
817f0f02b9aSMatt Spinler } // namespace psu
818f0f02b9aSMatt Spinler } // namespace power
819f0f02b9aSMatt Spinler } // namespace witherspoon
820