1 #pragma once 2 3 #include "pmbus.hpp" 4 #include "types.hpp" 5 #include "util.hpp" 6 #include "utility.hpp" 7 8 #include <gpiod.hpp> 9 #include <sdbusplus/bus/match.hpp> 10 11 #include <filesystem> 12 #include <stdexcept> 13 14 namespace phosphor::power::psu 15 { 16 17 #if IBM_VPD 18 // PMBus device driver "file name" to read for CCIN value. 19 constexpr auto CCIN = "ccin"; 20 constexpr auto PART_NUMBER = "part_number"; 21 constexpr auto FRU_NUMBER = "fru"; 22 constexpr auto SERIAL_HEADER = "header"; 23 constexpr auto SERIAL_NUMBER = "serial_number"; 24 constexpr auto FW_VERSION = "fw_version"; 25 26 // The D-Bus property name to update with the CCIN value. 27 constexpr auto MODEL_PROP = "Model"; 28 constexpr auto PN_PROP = "PartNumber"; 29 constexpr auto SN_PROP = "SerialNumber"; 30 constexpr auto VERSION_PROP = "Version"; 31 32 // ipzVPD Keyword sizes 33 static constexpr auto FL_KW_SIZE = 20; 34 #endif 35 36 constexpr auto LOG_LIMIT = 3; 37 38 /** 39 * @class PowerSupply 40 * Represents a PMBus power supply device. 41 */ 42 class PowerSupply 43 { 44 public: 45 PowerSupply() = delete; 46 PowerSupply(const PowerSupply&) = delete; 47 PowerSupply(PowerSupply&&) = delete; 48 PowerSupply& operator=(const PowerSupply&) = delete; 49 PowerSupply& operator=(PowerSupply&&) = delete; 50 ~PowerSupply() = default; 51 52 /** 53 * @param[in] invpath - String for inventory path to use 54 * @param[in] i2cbus - The bus number this power supply is on 55 * @param[in] i2caddr - The 16-bit I2C address of the power supply 56 * @param[in] gpioLineName - The gpio-line-name to read for presence. See 57 * https://github.com/openbmc/docs/blob/master/designs/device-tree-gpio-naming.md 58 */ 59 PowerSupply(sdbusplus::bus::bus& bus, const std::string& invpath, 60 std::uint8_t i2cbus, const std::uint16_t i2caddr, 61 const std::string& gpioLineName); 62 63 phosphor::pmbus::PMBusBase& getPMBus() 64 { 65 return *pmbusIntf; 66 } 67 68 GPIOInterfaceBase* getPresenceGPIO() 69 { 70 return presenceGPIO.get(); 71 } 72 73 std::string getPresenceGPIOName() const 74 { 75 if (presenceGPIO != nullptr) 76 { 77 return presenceGPIO->getName(); 78 } 79 else 80 { 81 return std::string(); 82 } 83 } 84 85 /** 86 * Power supply specific function to analyze for faults/errors. 87 * 88 * Various PMBus status bits will be checked for fault conditions. 89 * If a certain fault bits are on, the appropriate error will be 90 * committed. 91 */ 92 void analyze(); 93 94 /** 95 * Write PMBus ON_OFF_CONFIG 96 * 97 * This function will be called to cause the PMBus device driver to send the 98 * ON_OFF_CONFIG command. Takes one byte of data. 99 * 100 * @param[in] data - The ON_OFF_CONFIG data byte mask. 101 */ 102 void onOffConfig(uint8_t data); 103 104 /** 105 * Write PMBus CLEAR_FAULTS 106 * 107 * This function will be called in various situations in order to clear 108 * any fault status bits that may have been set, in order to start over 109 * with a clean state. Presence changes and power state changes will 110 * want to clear any faults logged. 111 */ 112 void clearFaults(); 113 114 /** 115 * @brief Adds properties to the inventory. 116 * 117 * Reads the values from the device and writes them to the 118 * associated power supply D-Bus inventory object. 119 * 120 * This needs to be done on startup, and each time the presence 121 * state changes. 122 * 123 * Properties added: 124 * - Serial Number 125 * - Part Number 126 * - CCIN (Customer Card Identification Number) - added as the Model 127 * - Firmware version 128 */ 129 void updateInventory(); 130 131 /** 132 * @brief Accessor function to indicate present status 133 */ 134 bool isPresent() const 135 { 136 return present; 137 } 138 139 /** 140 * @brief Returns the last read value from STATUS_WORD. 141 */ 142 uint64_t getStatusWord() const 143 { 144 return statusWord; 145 } 146 147 /** 148 * @brief Returns the last read value from STATUS_INPUT. 149 */ 150 uint64_t getStatusInput() const 151 { 152 return statusInput; 153 } 154 155 /** 156 * @brief Returns the last read value from STATUS_MFR. 157 */ 158 uint64_t getMFRFault() const 159 { 160 return statusMFR; 161 } 162 163 /** 164 * @brief Returns the last read value from STATUS_CML. 165 */ 166 uint64_t getStatusCML() const 167 { 168 return statusCML; 169 } 170 171 /** 172 * @brief Returns the last read value from STATUS_VOUT. 173 */ 174 uint64_t getStatusVout() const 175 { 176 return statusVout; 177 } 178 179 /** 180 * @brief Returns the last value read from STATUS_IOUT. 181 */ 182 uint64_t getStatusIout() const 183 { 184 return statusIout; 185 } 186 187 /** 188 * @brief Returns the last value read from STATUS_FANS_1_2. 189 */ 190 uint64_t getStatusFans12() const 191 { 192 return statusFans12; 193 } 194 195 /** 196 * @brief Returns the last value read from STATUS_TEMPERATURE. 197 */ 198 uint64_t getStatusTemperature() const 199 { 200 return statusTemperature; 201 } 202 203 /** 204 * @brief Returns true if a fault was found. 205 */ 206 bool isFaulted() const 207 { 208 return (hasCommFault() || vinUVFault || inputFault || voutOVFault || 209 ioutOCFault || voutUVFault || fanFault || tempFault || 210 pgoodFault || mfrFault); 211 } 212 213 /** 214 * @brief Return whether a fault has been logged for this power supply 215 */ 216 bool isFaultLogged() const 217 { 218 return faultLogged; 219 } 220 221 /** 222 * @brief Called when a fault for this power supply has been logged. 223 */ 224 void setFaultLogged() 225 { 226 faultLogged = true; 227 } 228 229 /** 230 * @brief Returns true if INPUT fault occurred. 231 */ 232 bool hasInputFault() const 233 { 234 return inputFault; 235 } 236 237 /** 238 * @brief Returns true if MFRSPECIFIC occurred. 239 */ 240 bool hasMFRFault() const 241 { 242 return mfrFault; 243 } 244 245 /** 246 * @brief Returns true if VIN_UV_FAULT occurred. 247 */ 248 bool hasVINUVFault() const 249 { 250 return vinUVFault; 251 } 252 253 /** 254 * @brief Returns true if VOUT_OV_FAULT occurred. 255 */ 256 bool hasVoutOVFault() const 257 { 258 return voutOVFault; 259 } 260 261 /** 262 * @brief Returns true if IOUT_OC fault occurred (bit 4 STATUS_BYTE). 263 */ 264 bool hasIoutOCFault() const 265 { 266 return ioutOCFault; 267 } 268 269 /** 270 * @brief Returns true if VOUT_UV_FAULT occurred. 271 */ 272 bool hasVoutUVFault() const 273 { 274 return voutUVFault; 275 } 276 277 /** 278 *@brief Returns true if fan fault occurred. 279 */ 280 bool hasFanFault() const 281 { 282 return fanFault; 283 } 284 285 /** 286 * @brief Returns true if TEMPERATURE fault occurred. 287 */ 288 bool hasTempFault() const 289 { 290 return tempFault; 291 } 292 293 /** 294 * @brief Returns true if there is a PGood fault (PGOOD# inactive, or OFF 295 * bit on). 296 */ 297 bool hasPgoodFault() const 298 { 299 return pgoodFault; 300 } 301 302 /** 303 * @brief Returns the device path 304 * 305 * This can be used for error call outs. 306 * Example: /sys/bus/i2c/devices/3-0068 307 */ 308 const std::string getDevicePath() const 309 { 310 return pmbusIntf->path(); 311 } 312 313 /** 314 * @brief Returns this power supplies inventory path. 315 * 316 * This can be used for error call outs. 317 * Example: 318 * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1 319 */ 320 const std::string& getInventoryPath() const 321 { 322 return inventoryPath; 323 } 324 325 /** 326 * @brief Returns the firmware revision version read from the power supply 327 */ 328 const std::string& getFWVersion() const 329 { 330 return fwVersion; 331 } 332 333 /** 334 * @brief Returns the model name of the power supply 335 */ 336 const std::string& getModelName() const 337 { 338 return modelName; 339 } 340 341 /** @brief Returns true if the number of failed reads exceeds limit 342 * TODO: or CML bit on. 343 */ 344 bool hasCommFault() const 345 { 346 return ((readFail >= LOG_LIMIT) || (cmlFault)); 347 } 348 349 /** 350 * @brief Reads the pmbus input voltage and returns that actual voltage 351 * reading and the calculated input voltage based on thresholds. 352 * @param[out] actualInputVoltage - The actual voltage reading, in Volts. 353 * @param[out] inputVoltage - A rounded up/down value of the actual input 354 * voltage based on thresholds, in Volts. 355 */ 356 void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const; 357 358 private: 359 /** @brief systemd bus member */ 360 sdbusplus::bus::bus& bus; 361 362 /** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/ 363 uint64_t statusWord = 0; 364 365 /** @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.*/ 366 uint64_t statusInput = 0; 367 368 /** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/ 369 uint64_t statusMFR = 0; 370 371 /** @brief Will be updated to the latest/last value read from STATUS_CML.*/ 372 uint64_t statusCML = 0; 373 374 /** @brief Will be updated to the latest/last value read from STATUS_VOUT.*/ 375 uint64_t statusVout = 0; 376 377 /** @brief Will be updated to the latest/last value read from STATUS_IOUT.*/ 378 uint64_t statusIout = 0; 379 380 /** @brief Will be updated to the latest/last value read from 381 * STATUS_FANS_1_2. */ 382 uint64_t statusFans12 = 0; 383 384 /** @brief Will be updated to the latest/last value read from 385 * STATUS_TEMPERATURE.*/ 386 uint64_t statusTemperature = 0; 387 388 /** @brief True if an error for a fault has already been logged. */ 389 bool faultLogged = false; 390 391 /** @brief True if bit 1 of STATUS_WORD low byte is on. */ 392 bool cmlFault = false; 393 394 /** @brief True if bit 5 of STATUS_WORD high byte is on. */ 395 bool inputFault = false; 396 397 /** @brief True if bit 4 of STATUS_WORD high byte is on. */ 398 bool mfrFault = false; 399 400 /** @brief True if bit 3 of STATUS_WORD low byte is on. */ 401 bool vinUVFault = false; 402 403 /** @brief True if bit 5 of STATUS_WORD low byte is on. */ 404 bool voutOVFault = false; 405 406 /** @brief True if bit 4 of STATUS_WORD low byte is on. */ 407 bool ioutOCFault = false; 408 409 /** @brief True if bit 7 of STATUS_WORD high byte is on and bit 5 (VOUT_OV) 410 * of low byte is off. */ 411 bool voutUVFault = false; 412 413 /** @brief True if FANS fault/warn bit on in STATUS_WORD. */ 414 bool fanFault = false; 415 416 /** @brief True if bit 2 of STATUS_WORD low byte is on. */ 417 bool tempFault = false; 418 419 /** 420 * @brief True if bit 11 or 6 of STATUS_WORD is on. PGOOD# is inactive, or 421 * the unit is off. 422 */ 423 bool pgoodFault = false; 424 425 /** @brief Count of the number of read failures. */ 426 size_t readFail = 0; 427 428 /** 429 * @brief D-Bus path to use for this power supply's inventory status. 430 **/ 431 std::string inventoryPath; 432 433 /** 434 * @brief The libgpiod object for monitoring PSU presence 435 */ 436 std::unique_ptr<GPIOInterfaceBase> presenceGPIO = nullptr; 437 438 /** @brief True if the power supply is present. */ 439 bool present = false; 440 441 /** @brief Power supply model name. */ 442 std::string modelName; 443 444 /** @brief D-Bus match variable used to subscribe to Present property 445 * changes. 446 **/ 447 std::unique_ptr<sdbusplus::bus::match_t> presentMatch; 448 449 /** @brief D-Bus match variable used to subscribe for Present property 450 * interface added. 451 */ 452 std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch; 453 454 /** 455 * @brief Pointer to the PMBus interface 456 * 457 * Used to read or write to/from PMBus power supply devices. 458 */ 459 std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr; 460 461 /** @brief Stored copy of the firmware version/revision string */ 462 std::string fwVersion; 463 464 /** 465 * @brief The file system path used for binding the device driver. 466 */ 467 const std::filesystem::path bindPath; 468 469 /* @brief The string to pass in for binding the device driver. */ 470 std::string bindDevice; 471 472 /** 473 * @brief Binds or unbinds the power supply device driver 474 * 475 * Called when a presence change is detected to either bind the device 476 * driver for the power supply when it is installed, or unbind the device 477 * driver when the power supply is removed. 478 * 479 * Writes <device> to <path>/bind (or unbind) 480 * 481 * @param present - when true, will bind the device driver 482 * when false, will unbind the device driver 483 */ 484 void bindOrUnbindDriver(bool present); 485 486 /** 487 * @brief Updates the presence status by querying D-Bus 488 * 489 * The D-Bus inventory properties for this power supply will be read to 490 * determine if the power supply is present or not and update this 491 * object's present member variable to reflect current status. 492 **/ 493 void updatePresence(); 494 495 /** 496 * @brief Updates the power supply presence by reading the GPIO line. 497 */ 498 void updatePresenceGPIO(); 499 500 /** 501 * @brief Callback for inventory property changes 502 * 503 * Process change of Present property for power supply. 504 * 505 * This is used if we are watching the D-Bus properties instead of reading 506 * the GPIO presence line ourselves. 507 * 508 * @param[in] msg - Data associated with Present change signal 509 **/ 510 void inventoryChanged(sdbusplus::message::message& msg); 511 512 /** 513 * @brief Callback for inventory property added. 514 * 515 * Process add of the interface with the Present property for power supply. 516 * 517 * This is used if we are watching the D-Bus properties instead of reading 518 * the GPIO presence line ourselves. 519 * 520 * @param[in] msg - Data associated with Present add signal 521 **/ 522 void inventoryAdded(sdbusplus::message::message& msg); 523 }; 524 525 } // namespace phosphor::power::psu 526