1 #pragma once 2 #include "average.hpp" 3 #include "device.hpp" 4 #include "maximum.hpp" 5 #include "names_values.hpp" 6 #include "pmbus.hpp" 7 #include "record_manager.hpp" 8 9 #include <nlohmann/json.hpp> 10 #include <sdbusplus/bus/match.hpp> 11 #include <sdeventplus/clock.hpp> 12 #include <sdeventplus/event.hpp> 13 #include <sdeventplus/utility/timer.hpp> 14 15 namespace phosphor 16 { 17 namespace power 18 { 19 namespace psu 20 { 21 namespace sdbusRule = sdbusplus::bus::match::rules; 22 23 constexpr auto FAULT_COUNT = 3; 24 25 /** 26 * @class PowerSupply 27 * Represents a PMBus power supply device. 28 */ 29 class PowerSupply : public Device 30 { 31 public: 32 PowerSupply() = delete; 33 PowerSupply(const PowerSupply&) = delete; 34 PowerSupply(PowerSupply&&) = default; 35 PowerSupply& operator=(const PowerSupply&) = default; 36 PowerSupply& operator=(PowerSupply&&) = default; 37 ~PowerSupply() = default; 38 39 /** 40 * Constructor 41 * 42 * @param[in] name - the device name 43 * @param[in] inst - the device instance 44 * @param[in] objpath - the path to monitor 45 * @param[in] invpath - the inventory path to use 46 * @param[in] bus - D-Bus bus object 47 * @param[in] e - event object 48 * @param[in] t - time to allow power supply to assert PG# 49 * @param[in] p - time to allow power supply presence state to 50 * settle/deglitch and allow for application of power 51 * prior to fault checking 52 */ 53 PowerSupply(const std::string& name, size_t inst, 54 const std::string& objpath, const std::string& invpath, 55 sdbusplus::bus::bus& bus, const sdeventplus::Event& e, 56 std::chrono::seconds& t, std::chrono::seconds& p); 57 58 /** 59 * Power supply specific function to analyze for faults/errors. 60 * 61 * Various PMBus status bits will be checked for fault conditions. 62 * If a certain fault bits are on, the appropriate error will be 63 * committed. 64 */ 65 void analyze() override; 66 67 /** 68 * Write PMBus CLEAR_FAULTS 69 * 70 * This function will be called in various situations in order to clear 71 * any fault status bits that may have been set, in order to start over 72 * with a clean state. Presence changes and power state changes will 73 * want to clear any faults logged. 74 */ 75 void clearFaults() override; 76 77 /** 78 * Mark error for specified callout and message as resolved. 79 * 80 * @param[in] callout - The callout to be resolved (inventory path) 81 * @parma[in] message - The message for the fault to be resolved 82 */ 83 void resolveError(const std::string& callout, const std::string& message); 84 85 /** 86 * Enables making the input power history available on D-Bus 87 * 88 * @param[in] objectPath - the D-Bus object path to use 89 * @param[in] maxRecords - the number of history records to keep 90 * @param[in] syncGPIOPath - The gpiochip device path to use for 91 * sending the sync command 92 * @paramp[in] syncGPIONum - the GPIO number for the sync command 93 */ 94 void enableHistory(const std::string& objectPath, size_t numRecords, 95 const std::string& syncGPIOPath, size_t syncGPIONum); 96 97 private: 98 /** 99 * The path to use for reading various PMBus bits/words. 100 */ 101 std::string monitorPath; 102 103 /** 104 * @brief Pointer to the PMBus interface 105 * 106 * Used to read out of or write to the /sysfs tree(s) containing files 107 * that a device driver monitors the PMBus interface to the power 108 * supplies. 109 */ 110 phosphor::pmbus::PMBus pmbusIntf; 111 112 /** 113 * @brief D-Bus path to use for this power supply's inventory status. 114 */ 115 std::string inventoryPath; 116 117 /** @brief Connection for sdbusplus bus */ 118 sdbusplus::bus::bus& bus; 119 120 /** @brief True if the power supply is present. */ 121 bool present = false; 122 123 /** @brief Used to subscribe to D-Bus property changes for Present */ 124 std::unique_ptr<sdbusplus::bus::match_t> presentMatch; 125 126 /** 127 * @brief Interval for setting present to true. 128 * 129 * The amount of time to wait from not present to present change before 130 * updating the internal present indicator. Allows person servicing 131 * the power supply some time to plug in the cable. 132 */ 133 std::chrono::seconds presentInterval; 134 135 /** 136 * @brief Timer used to delay setting the internal present state. 137 * 138 * The timer used to do the callback after the present property has 139 * changed. 140 */ 141 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> presentTimer; 142 143 /** @brief True if a fault has already been found and not cleared */ 144 bool faultFound = false; 145 146 /** @brief True if the power is on. */ 147 bool powerOn = false; 148 149 /** 150 * @brief Equal to FAULT_COUNT if power on fault has been 151 * detected. 152 */ 153 size_t powerOnFault = 0; 154 155 /** 156 * @brief Interval to setting powerOn to true. 157 * 158 * The amount of time to wait from power state on to setting the 159 * internal powerOn state to true. The amount of time the power supply 160 * is allowed to delay setting DGood/PG#. 161 */ 162 std::chrono::seconds powerOnInterval; 163 164 /** 165 * @brief Timer used to delay setting the internal powerOn state. 166 * 167 * The timer used to do the callback after the power state has been on 168 * long enough. 169 */ 170 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> powerOnTimer; 171 172 /** @brief Used to subscribe to D-Bus power on state changes */ 173 std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch; 174 175 /** @brief Indicates that a read failure has occurred. 176 * 177 * @details This will be incremented each time a read failure is 178 * encountered. If it is incremented to FAULT_COUNT, an error 179 * will be logged. 180 */ 181 size_t readFail = 0; 182 183 /** @brief Has a PMBus read failure already been logged? */ 184 bool readFailLogged = false; 185 186 /** 187 * @brief Indicates an input fault or warning if equal to FAULT_COUNT. 188 * 189 * @details This is the "INPUT FAULT OR WARNING" bit in the high byte, 190 * or the VIN_UV_FAULT bit in the low byte in the STATUS_WORD 191 * command response. If either of those bits are on, this will 192 * be incremented. 193 */ 194 size_t inputFault = 0; 195 196 /** 197 * @brief Indicates output over current fault if equal to FAULT_COUNT 198 * 199 * @details This is incremented when the "IOUT_OC_FAULT" bit in the low 200 * byte from the STATUS_WORD command response is on. 201 */ 202 size_t outputOCFault = 0; 203 204 /** 205 * @brief Indicates output overvoltage fault if equal to FAULT_COUNT. 206 * 207 * @details This is incremented when the "VOUT_OV_FAULT" bit in the 208 * STATUS_WORD command response is on. 209 */ 210 size_t outputOVFault = 0; 211 212 /** 213 * @brief Indicates a fan fault or warning condition was detected if 214 * equal to FAULT_COUNT. 215 * 216 * @details This is incremented when the 'FAN_FAULT' bit in the 217 * STATUS_WORD command response is on. 218 */ 219 size_t fanFault = 0; 220 221 /** 222 * @brief Indicates a temperature fault or warn condition was detected 223 * if equal to FAULT_COUNT. 224 * 225 * @details This is incremented when the 'TEMPERATURE_FAULT_WARN' bit 226 * in the STATUS_WORD command response is on, or if the 227 * 'OT_FAULT' bit in the STATUS_TEMPERATURE command response 228 * is on. 229 */ 230 size_t temperatureFault = 0; 231 232 /** 233 * @brief Class that manages the input power history records. 234 */ 235 std::unique_ptr<history::RecordManager> recordManager; 236 237 /** 238 * @brief The D-Bus object for the average input power history 239 */ 240 std::unique_ptr<history::Average> average; 241 242 /** 243 * @brief The D-Bus object for the maximum input power history 244 */ 245 std::unique_ptr<history::Maximum> maximum; 246 247 /** 248 * @brief The base D-Bus object path to use for the average 249 * and maximum objects. 250 */ 251 std::string historyObjectPath; 252 253 /** 254 * @brief The GPIO device path to use for sending the 'sync' 255 * command to the PS. 256 */ 257 std::string syncGPIODevPath; 258 259 /** 260 * @brief The GPIO number to use for sending the 'sync' 261 * command to the PS. 262 */ 263 size_t syncGPIONumber = 0; 264 265 /** 266 * @brief The type of the power supply inventory pmbus access. 267 */ 268 phosphor::pmbus::Type inventoryPMBusAccessType = 269 phosphor::pmbus::Type::Base; 270 271 /** 272 * @brief The JSON from the parsed power supply FRU JSON File. 273 */ 274 nlohmann::json fruJson; 275 276 /** 277 * @brief get the power supply access type from the JSON file. 278 * 279 */ 280 void getAccessType(); 281 282 /** 283 * @brief Callback for inventory property changes 284 * 285 * Process change of Present property for power supply. 286 * 287 * @param[in] msg - Data associated with Present change signal 288 * 289 */ 290 void inventoryChanged(sdbusplus::message::message& msg); 291 292 /** 293 * Updates the presence status by querying D-Bus 294 * 295 * The D-Bus inventory properties for this power supply will be read to 296 * determine if the power supply is present or not and update this 297 * objects present member variable to reflect current status. 298 */ 299 void updatePresence(); 300 301 /** 302 * @brief Updates the poweredOn status by querying D-Bus 303 * 304 * The D-Bus property for the system power state will be read to 305 * determine if the system is powered on or not. 306 */ 307 void updatePowerState(); 308 309 /** 310 * @brief Callback for power state property changes 311 * 312 * Process changes to the powered on stat property for the system. 313 * 314 * @param[in] msg - Data associated with the power state signal 315 */ 316 void powerStateChanged(sdbusplus::message::message& msg); 317 318 /** 319 * @brief Wrapper for PMBus::read() and adding metadata 320 * 321 * @param[out] nv - NamesValues instance to store cmd string and value 322 * @param[in] cmd - String for the command to read data from. 323 * @param[in] type - The type of file to read the command from. 324 */ 325 void captureCmd(util::NamesValues& nv, const std::string& cmd, 326 phosphor::pmbus::Type type); 327 328 /** 329 * @brief Checks for input voltage faults and logs error if needed. 330 * 331 * Check for voltage input under voltage fault (VIN_UV_FAULT) and/or 332 * input fault or warning (INPUT_FAULT), and logs appropriate error(s). 333 * 334 * @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs 335 */ 336 void checkInputFault(const uint16_t statusWord); 337 338 /** 339 * @brief Checks for power good negated or unit is off in wrong state 340 * 341 * @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs 342 */ 343 void checkPGOrUnitOffFault(const uint16_t statusWord); 344 345 /** 346 * @brief Checks for output current over current fault. 347 * 348 * IOUT_OC_FAULT is checked, if on, appropriate error is logged. 349 * 350 * @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs 351 */ 352 void checkCurrentOutOverCurrentFault(const uint16_t statusWord); 353 354 /** 355 * @brief Checks for output overvoltage fault. 356 * 357 * VOUT_OV_FAULT is checked, if on, appropriate error is logged. 358 * 359 * @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs 360 */ 361 void checkOutputOvervoltageFault(const uint16_t statusWord); 362 363 /** 364 * @brief Checks for a fan fault or warning condition. 365 * 366 * The high byte of STATUS_WORD is checked to see if the "FAN FAULT OR 367 * WARNING" bit is turned on. If it is on, log an error. 368 * 369 * @param[in] statusWord - 2 byte STATUS_WORD value read from sysfs 370 */ 371 void checkFanFault(const uint16_t statusWord); 372 373 /** 374 * @brief Checks for a temperature fault or warning condition. 375 * 376 * The low byte of STATUS_WORD is checked to see if the "TEMPERATURE 377 * FAULT OR WARNING" bit is turned on. If it is on, log an error, 378 * call out the power supply indicating the fault/warning condition. 379 * 380 * @parma[in] statusWord - 2 byte STATUS_WORD value read from sysfs 381 */ 382 void checkTemperatureFault(const uint16_t statusWord); 383 384 /** 385 * @brief Adds properties to the inventory. 386 * 387 * Reads the values from the device and writes them to the 388 * associated power supply D-Bus inventory object. 389 * 390 * This needs to be done on startup, and each time the presence 391 * state changes. 392 * 393 * Properties added: 394 * - Serial Number 395 * - Part Number 396 * - Manufacturer 397 * - Model 398 */ 399 void updateInventory(); 400 401 /** 402 * @brief Toggles the GPIO to sync power supply input history readings 403 * 404 * This GPIO is connected to all supplies. This will clear the 405 * previous readings out of the supplies and restart them both at the 406 * same time zero and at record ID 0. The supplies will return 0 407 * bytes of data for the input history command right after this until 408 * a new entry shows up. 409 * 410 * This will cause the code to delete all previous history data and 411 * start fresh. 412 */ 413 void syncHistory(); 414 415 /** 416 * @brief Reads the most recent input history record from the power 417 * supply and updates the average and maximum properties in 418 * D-Bus if there is a new reading available. 419 * 420 * This will still run every time analyze() is called so code can 421 * post new data as soon as possible and the timestamp will more 422 * accurately reflect the correct time. 423 * 424 * D-Bus is only updated if there is a change and the oldest record 425 * will be pruned if the property already contains the max number of 426 * records. 427 */ 428 void updateHistory(); 429 }; 430 431 } // namespace psu 432 } // namespace power 433 } // namespace phosphor 434