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 true if a fault was found. 181 */ 182 bool isFaulted() const 183 { 184 return (hasCommFault() || vinUVFault || inputFault || voutOVFault || 185 mfrFault); 186 } 187 188 /** 189 * @brief Return whether a fault has been logged for this power supply 190 */ 191 bool isFaultLogged() const 192 { 193 return faultLogged; 194 } 195 196 /** 197 * @brief Called when a fault for this power supply has been logged. 198 */ 199 void setFaultLogged() 200 { 201 faultLogged = true; 202 } 203 204 /** 205 * @brief Returns true if INPUT fault occurred. 206 */ 207 bool hasInputFault() const 208 { 209 return inputFault; 210 } 211 212 /** 213 * @brief Returns true if MFRSPECIFIC occurred. 214 */ 215 bool hasMFRFault() const 216 { 217 return mfrFault; 218 } 219 220 /** 221 * @brief Returns true if VIN_UV_FAULT occurred. 222 */ 223 bool hasVINUVFault() const 224 { 225 return vinUVFault; 226 } 227 228 /** 229 * @brief Returns true if VOUT_OV_FAULT occurred. 230 */ 231 bool hasVoutOVFault() const 232 { 233 return voutOVFault; 234 } 235 236 /** 237 * @brief Returns the device path 238 * 239 * This can be used for error call outs. 240 * Example: /sys/bus/i2c/devices/3-0068 241 */ 242 const std::string getDevicePath() const 243 { 244 return pmbusIntf->path(); 245 } 246 247 /** 248 * @brief Returns this power supplies inventory path. 249 * 250 * This can be used for error call outs. 251 * Example: 252 * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1 253 */ 254 const std::string& getInventoryPath() const 255 { 256 return inventoryPath; 257 } 258 259 /** 260 * @brief Returns the firmware revision version read from the power supply 261 */ 262 const std::string& getFWVersion() const 263 { 264 return fwVersion; 265 } 266 267 /** 268 * @brief Returns the model name of the power supply 269 */ 270 const std::string& getModelName() const 271 { 272 return modelName; 273 } 274 275 /** @brief Returns true if the number of failed reads exceeds limit 276 * TODO: or CML bit on. 277 */ 278 bool hasCommFault() const 279 { 280 return ((readFail >= LOG_LIMIT) || (cmlFault)); 281 } 282 283 /** 284 * @brief Reads the pmbus input voltage and returns that actual voltage 285 * reading and the calculated input voltage based on thresholds. 286 * @param[out] actualInputVoltage - The actual voltage reading, in Volts. 287 * @param[out] inputVoltage - A rounded up/down value of the actual input 288 * voltage based on thresholds, in Volts. 289 */ 290 void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const; 291 292 private: 293 /** @brief systemd bus member */ 294 sdbusplus::bus::bus& bus; 295 296 /** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/ 297 uint64_t statusWord = 0; 298 299 /** @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.*/ 300 uint64_t statusInput = 0; 301 302 /** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/ 303 uint64_t statusMFR = 0; 304 305 /** @brief Will be updated to the latest/last value read from STATUS_CML.*/ 306 uint64_t statusCML = 0; 307 308 /** @brief Will be updated to the latest/last value read from STATUS_VOUT.*/ 309 uint64_t statusVout = 0; 310 311 /** @brief True if an error for a fault has already been logged. */ 312 bool faultLogged = false; 313 314 /** @brief True if bit 2 of STATUS_WORD low byte is on. */ 315 bool cmlFault = false; 316 317 /** @brief True if bit 5 of STATUS_WORD high byte is on. */ 318 bool inputFault = false; 319 320 /** @brief True if bit 4 of STATUS_WORD high byte is on. */ 321 bool mfrFault = false; 322 323 /** @brief True if bit 3 of STATUS_WORD low byte is on. */ 324 bool vinUVFault = false; 325 326 /** @brief True if bit 5 of STATUS_WORD low byte is on. */ 327 bool voutOVFault = false; 328 329 /** @brief Count of the number of read failures. */ 330 size_t readFail = 0; 331 332 /** 333 * @brief D-Bus path to use for this power supply's inventory status. 334 **/ 335 std::string inventoryPath; 336 337 /** 338 * @brief The libgpiod object for monitoring PSU presence 339 */ 340 std::unique_ptr<GPIOInterfaceBase> presenceGPIO = nullptr; 341 342 /** @brief True if the power supply is present. */ 343 bool present = false; 344 345 /** @brief Power supply model name. */ 346 std::string modelName; 347 348 /** @brief D-Bus match variable used to subscribe to Present property 349 * changes. 350 **/ 351 std::unique_ptr<sdbusplus::bus::match_t> presentMatch; 352 353 /** @brief D-Bus match variable used to subscribe for Present property 354 * interface added. 355 */ 356 std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch; 357 358 /** 359 * @brief Pointer to the PMBus interface 360 * 361 * Used to read or write to/from PMBus power supply devices. 362 */ 363 std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr; 364 365 /** @brief Stored copy of the firmware version/revision string */ 366 std::string fwVersion; 367 368 /** 369 * @brief The file system path used for binding the device driver. 370 */ 371 const std::filesystem::path bindPath; 372 373 /* @brief The string to pass in for binding the device driver. */ 374 std::string bindDevice; 375 376 /** 377 * @brief Binds or unbinds the power supply device driver 378 * 379 * Called when a presence change is detected to either bind the device 380 * driver for the power supply when it is installed, or unbind the device 381 * driver when the power supply is removed. 382 * 383 * Writes <device> to <path>/bind (or unbind) 384 * 385 * @param present - when true, will bind the device driver 386 * when false, will unbind the device driver 387 */ 388 void bindOrUnbindDriver(bool present); 389 390 /** 391 * @brief Updates the presence status by querying D-Bus 392 * 393 * The D-Bus inventory properties for this power supply will be read to 394 * determine if the power supply is present or not and update this 395 * object's present member variable to reflect current status. 396 **/ 397 void updatePresence(); 398 399 /** 400 * @brief Updates the power supply presence by reading the GPIO line. 401 */ 402 void updatePresenceGPIO(); 403 404 /** 405 * @brief Callback for inventory property changes 406 * 407 * Process change of Present property for power supply. 408 * 409 * This is used if we are watching the D-Bus properties instead of reading 410 * the GPIO presence line ourselves. 411 * 412 * @param[in] msg - Data associated with Present change signal 413 **/ 414 void inventoryChanged(sdbusplus::message::message& msg); 415 416 /** 417 * @brief Callback for inventory property added. 418 * 419 * Process add of the interface with the Present property for power supply. 420 * 421 * This is used if we are watching the D-Bus properties instead of reading 422 * the GPIO presence line ourselves. 423 * 424 * @param[in] msg - Data associated with Present add signal 425 **/ 426 void inventoryAdded(sdbusplus::message::message& msg); 427 }; 428 429 } // namespace phosphor::power::psu 430