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