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 /** 74 * Power supply specific function to analyze for faults/errors. 75 * 76 * Various PMBus status bits will be checked for fault conditions. 77 * If a certain fault bits are on, the appropriate error will be 78 * committed. 79 */ 80 void analyze(); 81 82 /** 83 * Write PMBus ON_OFF_CONFIG 84 * 85 * This function will be called to cause the PMBus device driver to send the 86 * ON_OFF_CONFIG command. Takes one byte of data. 87 * 88 * @param[in] data - The ON_OFF_CONFIG data byte mask. 89 */ 90 void onOffConfig(uint8_t data); 91 92 /** 93 * Write PMBus CLEAR_FAULTS 94 * 95 * This function will be called in various situations in order to clear 96 * any fault status bits that may have been set, in order to start over 97 * with a clean state. Presence changes and power state changes will 98 * want to clear any faults logged. 99 */ 100 void clearFaults(); 101 102 /** 103 * @brief Adds properties to the inventory. 104 * 105 * Reads the values from the device and writes them to the 106 * associated power supply D-Bus inventory object. 107 * 108 * This needs to be done on startup, and each time the presence 109 * state changes. 110 * 111 * Properties added: 112 * - Serial Number 113 * - Part Number 114 * - CCIN (Customer Card Identification Number) - added as the Model 115 * - Firmware version 116 */ 117 void updateInventory(); 118 119 /** 120 * @brief Accessor function to indicate present status 121 */ 122 bool isPresent() const 123 { 124 return present; 125 } 126 127 /** 128 * @brief Returns the last read value from STATUS_WORD. 129 */ 130 uint64_t getStatusWord() const 131 { 132 return statusWord; 133 } 134 135 /** 136 * @brief Returns the last read value from STATUS_MFR. 137 */ 138 uint64_t getMFRFault() const 139 { 140 return statusMFR; 141 } 142 143 /** 144 * @brief Returns true if a fault was found. 145 */ 146 bool isFaulted() const 147 { 148 return (faultFound || hasCommFault()); 149 } 150 151 /** 152 * @brief Return whether a fault has been logged for this power supply 153 */ 154 bool isFaultLogged() const 155 { 156 return faultLogged; 157 } 158 159 /** 160 * @brief Called when a fault for this power supply has been logged. 161 */ 162 void setFaultLogged() 163 { 164 faultLogged = true; 165 } 166 167 /** 168 * @brief Returns true if INPUT fault occurred. 169 */ 170 bool hasInputFault() const 171 { 172 return inputFault; 173 } 174 175 /** 176 * @brief Returns true if MFRSPECIFIC occurred. 177 */ 178 bool hasMFRFault() const 179 { 180 return mfrFault; 181 } 182 183 /** 184 * @brief Returns true if VIN_UV_FAULT occurred. 185 */ 186 bool hasVINUVFault() const 187 { 188 return vinUVFault; 189 } 190 191 /** 192 * @brief Returns the device path 193 * 194 * This can be used for error call outs. 195 * Example: /sys/bus/i2c/devices/3-0068 196 */ 197 const std::string getDevicePath() const 198 { 199 return pmbusIntf->path(); 200 } 201 202 /** 203 * @brief Returns this power supplies inventory path. 204 * 205 * This can be used for error call outs. 206 * Example: 207 * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1 208 */ 209 const std::string& getInventoryPath() const 210 { 211 return inventoryPath; 212 } 213 214 /** 215 * @brief Returns the firmware revision version read from the power supply 216 */ 217 const std::string& getFWVersion() const 218 { 219 return fwVersion; 220 } 221 222 /** 223 * @brief Returns the model name of the power supply 224 */ 225 const std::string& getModelName() const 226 { 227 return modelName; 228 } 229 230 /** @brief Returns true if the number of failed reads exceeds limit 231 * TODO: or CML bit on. 232 */ 233 bool hasCommFault() const 234 { 235 return readFail >= LOG_LIMIT; 236 } 237 238 /** 239 * @brief Reads the pmbus input voltage and returns that actual voltage 240 * reading and the calculated input voltage based on thresholds. 241 * @param[out] actualInputVoltage - The actual voltage reading, in Volts. 242 * @param[out] inputVoltage - A rounded up/down value of the actual input 243 * voltage based on thresholds, in Volts. 244 */ 245 void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const; 246 247 private: 248 /** @brief systemd bus member */ 249 sdbusplus::bus::bus& bus; 250 251 /** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/ 252 uint64_t statusWord = 0; 253 254 /** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/ 255 uint64_t statusMFR = 0; 256 257 /** @brief True if a fault has already been found and not cleared */ 258 bool faultFound = false; 259 260 /** @brief True if an error for a fault has already been logged. */ 261 bool faultLogged = false; 262 263 /** @brief True if bit 5 of STATUS_WORD high byte is on. */ 264 bool inputFault = false; 265 266 /** @brief True if bit 4 of STATUS_WORD high byte is on. */ 267 bool mfrFault = false; 268 269 /** @brief True if bit 3 of STATUS_WORD low byte is on. */ 270 bool vinUVFault = false; 271 272 /** @brief Count of the number of read failures. */ 273 size_t readFail = 0; 274 275 /** 276 * @brief D-Bus path to use for this power supply's inventory status. 277 **/ 278 std::string inventoryPath; 279 280 /** 281 * @brief The libgpiod object for monitoring PSU presence 282 */ 283 std::unique_ptr<GPIOInterface> presenceGPIO = nullptr; 284 285 /** @brief True if the power supply is present. */ 286 bool present = false; 287 288 /** @brief Power supply model name. */ 289 std::string modelName; 290 291 /** @brief D-Bus match variable used to subscribe to Present property 292 * changes. 293 **/ 294 std::unique_ptr<sdbusplus::bus::match_t> presentMatch; 295 296 /** @brief D-Bus match variable used to subscribe for Present property 297 * interface added. 298 */ 299 std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch; 300 301 /** 302 * @brief Pointer to the PMBus interface 303 * 304 * Used to read or write to/from PMBus power supply devices. 305 */ 306 std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr; 307 308 /** @brief Stored copy of the firmware version/revision string */ 309 std::string fwVersion; 310 311 /** 312 * @brief The file system path used for binding the device driver. 313 */ 314 const std::filesystem::path bindPath; 315 316 /* @brief The string to pass in for binding the device driver. */ 317 std::string bindDevice; 318 319 /** 320 * @brief Binds or unbinds the power supply device driver 321 * 322 * Called when a presence change is detected to either bind the device 323 * driver for the power supply when it is installed, or unbind the device 324 * driver when the power supply is removed. 325 * 326 * Writes <device> to <path>/bind (or unbind) 327 * 328 * @param present - when true, will bind the device driver 329 * when false, will unbind the device driver 330 */ 331 void bindOrUnbindDriver(bool present); 332 333 /** 334 * @brief Updates the presence status by querying D-Bus 335 * 336 * The D-Bus inventory properties for this power supply will be read to 337 * determine if the power supply is present or not and update this 338 * object's present member variable to reflect current status. 339 **/ 340 void updatePresence(); 341 342 /** 343 * @brief Updates the power supply presence by reading the GPIO line. 344 */ 345 void updatePresenceGPIO(); 346 347 /** 348 * @brief Callback for inventory property changes 349 * 350 * Process change of Present property for power supply. 351 * 352 * This is used if we are watching the D-Bus properties instead of reading 353 * the GPIO presence line ourselves. 354 * 355 * @param[in] msg - Data associated with Present change signal 356 **/ 357 void inventoryChanged(sdbusplus::message::message& msg); 358 359 /** 360 * @brief Callback for inventory property added. 361 * 362 * Process add of the interface with the 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 add signal 368 **/ 369 void inventoryAdded(sdbusplus::message::message& msg); 370 }; 371 372 } // namespace phosphor::power::psu 373