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