1 #pragma once 2 3 #include "config.h" 4 5 #include "utils.hpp" 6 7 #include <sdbusplus/bus.hpp> 8 #include <sdbusplus/bus/match.hpp> 9 #include <xyz/openbmc_project/Control/Power/CapLimits/server.hpp> 10 11 #include <filesystem> 12 #include <regex> 13 14 namespace open_power 15 { 16 namespace occ 17 { 18 class Status; 19 20 namespace powercap 21 { 22 23 namespace sdbusRule = sdbusplus::bus::match::rules; 24 namespace fs = std::filesystem; 25 26 constexpr auto PCAPLIMITS_PATH = 27 "/xyz/openbmc_project/control/host0/power_cap_limits"; 28 29 namespace Base = sdbusplus::xyz::openbmc_project::Control::Power::server; 30 using CapLimitsInterface = sdbusplus::server::object_t<Base::CapLimits>; 31 32 constexpr auto PCAPDATA_FILE_VERSION = 1; 33 struct PowerCapData 34 { 35 uint32_t version = PCAPDATA_FILE_VERSION; 36 bool initialized = false; 37 uint32_t softMin = 0x0000; 38 uint32_t hardMin = 0x0000; 39 uint32_t max = UINT_MAX; 40 }; 41 42 /** @class OccPersistCapData 43 * @brief Provides persistent container to store data for OCC 44 * 45 * Data is stored in filesystem 46 */ 47 class OccPersistCapData 48 { 49 public: 50 ~OccPersistCapData() = default; 51 OccPersistCapData(const OccPersistCapData&) = default; 52 OccPersistCapData& operator=(const OccPersistCapData&) = default; 53 OccPersistCapData(OccPersistCapData&&) = default; 54 OccPersistCapData& operator=(OccPersistCapData&&) = default; 55 56 /** @brief Loads any saved power cap data */ OccPersistCapData()57 OccPersistCapData() 58 { 59 load(); 60 } 61 62 /** @brief Save Power Mode data to persistent file 63 * 64 * @param[in] softMin - soft minimum power cap in Watts 65 * @param[in] hardMin - hard minimum power cap in Watts 66 * @param[in] max - maximum power cap in Watts 67 */ updateCapLimits(const uint32_t softMin,const uint32_t hardMin,const uint32_t max)68 void updateCapLimits(const uint32_t softMin, const uint32_t hardMin, 69 const uint32_t max) 70 { 71 capData.softMin = softMin; 72 capData.hardMin = hardMin; 73 capData.max = max; 74 capData.initialized = true; 75 save(); 76 } 77 78 /** @brief Return the power cap limits 79 * 80 * @param[out] softMin - soft minimum power cap in Watts 81 * @param[out] hardMin - hard minimum power cap in Watts 82 * @param[out] max - maximum power cap in Watts 83 */ getCapLimits(uint32_t & softMin,uint32_t & hardMin,uint32_t & max) const84 void getCapLimits(uint32_t& softMin, uint32_t& hardMin, uint32_t& max) const 85 { 86 // If not initialized yet, still return PowerCapData defaults 87 softMin = capData.softMin; 88 hardMin = capData.hardMin; 89 max = capData.max; 90 } 91 92 /** @brief Return true if the power cap limits are available */ limitsAvailable()93 bool limitsAvailable() 94 { 95 return (capData.initialized); 96 } 97 98 /** @brief Saves the Power Mode data in the filesystem. */ 99 void save(); 100 101 /** @brief Trace the Power Mode and IPS parameters. */ 102 void print(); 103 104 private: 105 /** @brief Power Mode data filename to store persistent data */ 106 static constexpr auto powerCapFilename = "powerCapLimitData"; 107 108 /** @brief Power Mode data object to be persisted */ 109 PowerCapData capData; 110 111 /** @brief Loads the persisted power cap data from the filesystem. */ 112 void load(); 113 }; 114 115 /** @class PowerCap 116 * @brief Monitors for changes to the power cap and notifies occ 117 * 118 * The customer power cap is provided to the OCC by host TMGT when the occ 119 * first goes active or is reset. This code is responsible for sending 120 * the power cap to the OCC if the cap is changed while the occ is active. 121 */ 122 123 class PowerCap : public CapLimitsInterface 124 { 125 public: 126 /** @brief PowerCap object to inform occ of changes to cap 127 * 128 * This object will monitor for changes to the power cap setting and 129 * power cap enable properties. If a change is detected, and the occ 130 * is active, then this object will notify the OCC of the change. 131 * 132 * @param[in] occStatus - The occ status object 133 */ PowerCap(Status & occStatus)134 explicit PowerCap(Status& occStatus) : 135 CapLimitsInterface(utils::getBus(), PCAPLIMITS_PATH, 136 CapLimitsInterface::action::defer_emit), 137 occStatus(occStatus), 138 pcapMatch( 139 utils::getBus(), 140 sdbusRule::member("PropertiesChanged") + 141 sdbusRule::path( 142 "/xyz/openbmc_project/control/host0/power_cap") + 143 sdbusRule::argN(0, "xyz.openbmc_project.Control.Power.Cap") + 144 sdbusRule::interface("org.freedesktop.DBus.Properties"), 145 std::bind(std::mem_fn(&PowerCap::pcapChanged), this, 146 std::placeholders::_1)) 147 { 148 // Read the current limits from persistent data 149 uint32_t capSoftMin, capHardMin, capMax; 150 persistedData.getCapLimits(capSoftMin, capHardMin, capMax); 151 // Update limits on dbus 152 updateDbusPcapLimits(capSoftMin, capHardMin, capMax); 153 // CapLimit interface is now ready 154 this->emit_object_added(); 155 }; 156 157 /** @brief Return the appropriate value to write to the OCC (output/DC 158 * power) 159 * 160 * @param[in] pcap - Current user power cap setting (input/AC power) 161 * @param[in] pcapEnabled - Current power cap enable setting 162 * 163 * @return The value to write to the occ user pcap 164 */ 165 uint32_t getOccInput(uint32_t pcap, bool pcapEnabled); 166 167 /** @brief Read the power cap bounds from sysfs and update DBus */ 168 void updatePcapBounds(); 169 170 private: 171 /** @brief Persisted power cap limits */ 172 OccPersistCapData persistedData; 173 174 /** @brief Callback for pcap setting changes 175 * 176 * Process change and inform OCC 177 * 178 * @param[in] msg - Data associated with pcap change signal 179 * 180 */ 181 void pcapChanged(sdbusplus::message_t& msg); 182 183 /** @brief Get the power cap property 184 * 185 * @return Power cap, 0 on failure to indicate no pcap 186 */ 187 uint32_t getPcap(); 188 189 /** @brief Get the power cap enable property 190 * 191 * @return Whether power cap enabled, will return false on error 192 */ 193 bool getPcapEnabled(); 194 195 /** @brief Write the output/DC power cap to the occ hwmon entry 196 * 197 * @param[in] pcapValue - Power cap value to write to OCC 198 */ 199 void writeOcc(uint32_t pcapValue); 200 201 /** @brief Read the user power cap from sysfs 202 * 203 * @return User power cap value in Watts or 0 if disabled 204 */ 205 uint32_t readUserCapHwmon(); 206 207 /** 208 * @brief Returns the filename to use for the user power cap 209 * 210 * The file is of the form "powerX_cap_user", where X is any 211 * number. 212 * 213 * @param[in] expr - Regular expression of file to find 214 * 215 * @return full path/filename, or empty path if not found. 216 */ 217 fs::path getPcapFilename(const std::regex& expr); 218 219 /* @brief OCC Status object */ 220 Status& occStatus; 221 222 /** @brief Used to subscribe to dbus pcap property changes **/ 223 sdbusplus::bus::match_t pcapMatch; 224 225 /** @brief Path to the sysfs files holding the cap properties **/ 226 fs::path pcapBasePathname; 227 228 /** @brief Update the power cap bounds on DBus 229 * 230 * @param[in] softMin - soft minimum power cap in Watts 231 * @param[in] hardMin - hard minimum power cap in Watts 232 * @param[in] pcapMax - maximum power cap in Watts 233 */ 234 void updateDbusPcapLimits(uint32_t softMin, uint32_t hardMin, 235 uint32_t pcapMax); 236 }; 237 238 } // namespace powercap 239 240 } // namespace occ 241 242 } // namespace open_power 243