xref: /openbmc/witherspoon-pfault-analysis/power-supply/power_supply.cpp (revision befec58beb5f6ad5e3240151383cd56c5a502996)
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