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 private: 239 /** @brief systemd bus member */ 240 sdbusplus::bus::bus& bus; 241 242 /** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/ 243 uint64_t statusWord = 0; 244 245 /** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/ 246 uint64_t statusMFR = 0; 247 248 /** @brief True if a fault has already been found and not cleared */ 249 bool faultFound = false; 250 251 /** @brief True if an error for a fault has already been logged. */ 252 bool faultLogged = false; 253 254 /** @brief True if bit 5 of STATUS_WORD high byte is on. */ 255 bool inputFault = false; 256 257 /** @brief True if bit 4 of STATUS_WORD high byte is on. */ 258 bool mfrFault = false; 259 260 /** @brief True if bit 3 of STATUS_WORD low byte is on. */ 261 bool vinUVFault = false; 262 263 /** @brief Count of the number of read failures. */ 264 size_t readFail = 0; 265 266 /** 267 * @brief D-Bus path to use for this power supply's inventory status. 268 **/ 269 std::string inventoryPath; 270 271 /** 272 * @brief The libgpiod object for monitoring PSU presence 273 */ 274 std::unique_ptr<GPIOInterface> presenceGPIO = nullptr; 275 276 /** @brief True if the power supply is present. */ 277 bool present = false; 278 279 /** @brief Power supply model name. */ 280 std::string modelName; 281 282 /** @brief D-Bus match variable used to subscribe to Present property 283 * changes. 284 **/ 285 std::unique_ptr<sdbusplus::bus::match_t> presentMatch; 286 287 /** @brief D-Bus match variable used to subscribe for Present property 288 * interface added. 289 */ 290 std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch; 291 292 /** 293 * @brief Pointer to the PMBus interface 294 * 295 * Used to read or write to/from PMBus power supply devices. 296 */ 297 std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr; 298 299 /** @brief Stored copy of the firmware version/revision string */ 300 std::string fwVersion; 301 302 /** 303 * @brief The file system path used for binding the device driver. 304 */ 305 const std::filesystem::path bindPath; 306 307 /* @brief The string to pass in for binding the device driver. */ 308 std::string bindDevice; 309 310 /** 311 * @brief Binds or unbinds the power supply device driver 312 * 313 * Called when a presence change is detected to either bind the device 314 * driver for the power supply when it is installed, or unbind the device 315 * driver when the power supply is removed. 316 * 317 * Writes <device> to <path>/bind (or unbind) 318 * 319 * @param present - when true, will bind the device driver 320 * when false, will unbind the device driver 321 */ 322 void bindOrUnbindDriver(bool present); 323 324 /** 325 * @brief Updates the presence status by querying D-Bus 326 * 327 * The D-Bus inventory properties for this power supply will be read to 328 * determine if the power supply is present or not and update this 329 * object's present member variable to reflect current status. 330 **/ 331 void updatePresence(); 332 333 /** 334 * @brief Updates the power supply presence by reading the GPIO line. 335 */ 336 void updatePresenceGPIO(); 337 338 /** 339 * @brief Callback for inventory property changes 340 * 341 * Process change of Present property for power supply. 342 * 343 * This is used if we are watching the D-Bus properties instead of reading 344 * the GPIO presence line ourselves. 345 * 346 * @param[in] msg - Data associated with Present change signal 347 **/ 348 void inventoryChanged(sdbusplus::message::message& msg); 349 350 /** 351 * @brief Callback for inventory property added. 352 * 353 * Process add of the interface with the Present property for power supply. 354 * 355 * This is used if we are watching the D-Bus properties instead of reading 356 * the GPIO presence line ourselves. 357 * 358 * @param[in] msg - Data associated with Present add signal 359 **/ 360 void inventoryAdded(sdbusplus::message::message& msg); 361 }; 362 363 } // namespace phosphor::power::psu 364