1 #pragma once 2 #include "config.h" 3 4 #include "i2c_occ.hpp" 5 #include "occ_command.hpp" 6 #include "occ_device.hpp" 7 #include "occ_events.hpp" 8 #include "powercap.hpp" 9 #include "powermode.hpp" 10 #include "utils.hpp" 11 12 #include <org/open_power/Control/Host/server.hpp> 13 #include <org/open_power/OCC/Status/server.hpp> 14 #include <sdbusplus/bus.hpp> 15 #include <sdbusplus/server/object.hpp> 16 #ifdef POWER10 17 #include <sdeventplus/event.hpp> 18 #include <sdeventplus/utility/timer.hpp> 19 #endif 20 #include <xyz/openbmc_project/Control/Power/Throttle/server.hpp> 21 22 #include <functional> 23 24 namespace open_power 25 { 26 namespace occ 27 { 28 29 class Manager; 30 namespace Base = sdbusplus::org::open_power::OCC::server; 31 using Interface = sdbusplus::server::object_t<Base::Status>; 32 33 namespace xyzBase = sdbusplus::xyz::openbmc_project::Control::Power::server; 34 using ThrottleInterface = sdbusplus::server::object_t<xyzBase::Throttle>; 35 36 // IPMID's host control application 37 namespace Control = sdbusplus::org::open_power::Control::server; 38 39 // For waiting on signals 40 namespace sdbusRule = sdbusplus::bus::match::rules; 41 42 // OCC status instance. Ex. for "occ0", the instance is 0 43 using instanceID = unsigned int; 44 45 // IPMI sensor ID for a given OCC instance 46 using sensorID = uint8_t; 47 48 // Human readable sensor name for DBus tree. E.g. "CPU0_OCC" 49 using sensorName = std::string; 50 51 // OCC sensors definitions in the map 52 using sensorDefs = std::tuple<sensorID, sensorName>; 53 54 // OCC sysfs name prefix 55 const std::string sysfsName = "occ-hwmon"; 56 57 const uint8_t THROTTLED_NONE = 0x00; 58 const uint8_t THROTTLED_POWER = 0x01; 59 const uint8_t THROTTLED_THERMAL = 0x02; 60 const uint8_t THROTTLED_SAFE = 0x04; 61 const uint8_t THROTTLED_ALL = 0xFF; 62 63 /** @class Status 64 * @brief Implementation of OCC Active Status 65 */ 66 class Status : public Interface 67 { 68 public: 69 Status() = delete; 70 ~Status() = default; 71 Status(const Status&) = delete; 72 Status& operator=(const Status&) = delete; 73 Status(Status&&) = default; 74 Status& operator=(Status&&) = default; 75 76 /** @brief Constructs the Status object and 77 * the underlying device object 78 * 79 * @param[in] event - sd_event unique pointer reference 80 * @param[in] path - DBus object path 81 * @param[in] manager - OCC manager instance 82 * @param[in] callBack - Callback handler to invoke during 83 * property change 84 * @param[in] resetCallBack - callback handler to invoke for resetting the 85 * OCC if PLDM is the host communication 86 * protocol 87 */ 88 Status(EventPtr& event, const char* path, Manager& managerRef, 89 #ifdef POWER10 90 std::unique_ptr<powermode::PowerMode>& powerModeRef, 91 #endif 92 std::function<void(instanceID, bool)> callBack = nullptr 93 #ifdef PLDM 94 , 95 std::function<void(instanceID)> resetCallBack = nullptr 96 #endif 97 ) : 98 99 Interface(utils::getBus(), getDbusPath(path).c_str(), 100 Interface::action::defer_emit), 101 path(path), managerCallBack(callBack), instance(getInstance(path)), 102 manager(managerRef), 103 #ifdef POWER10 104 pmode(powerModeRef), 105 #endif 106 device(event, 107 #ifdef I2C_OCC 108 fs::path(DEV_PATH) / i2c_occ::getI2cDeviceName(path), 109 #else 110 fs::path(DEV_PATH) / 111 fs::path(sysfsName + "." + std::to_string(instance + 1)), 112 #endif 113 managerRef, *this, 114 #ifdef POWER10 115 powerModeRef, 116 #endif 117 instance), 118 hostControlSignal( 119 utils::getBus(), 120 sdbusRule::type::signal() + sdbusRule::member("CommandComplete") + 121 sdbusRule::path("/org/open_power/control/host0") + 122 sdbusRule::interface("org.open_power.Control.Host") + 123 sdbusRule::argN(0, Control::convertForMessage( 124 Control::Host::Command::OCCReset)), 125 std::bind(std::mem_fn(&Status::hostControlEvent), this, 126 std::placeholders::_1)), 127 occCmd(instance, (fs::path(OCC_CONTROL_ROOT) / 128 (std::string(OCC_NAME) + std::to_string(instance))) 129 .c_str()) 130 #ifdef POWER10 131 , 132 sdpEvent(sdeventplus::Event::get_default()), 133 safeStateDelayTimer( 134 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>( 135 sdpEvent, std::bind(&Status::safeStateDelayExpired, this))), 136 occReadStateFailTimer( 137 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>( 138 sdpEvent, std::bind(&Status::occReadStateNow, this))) 139 #endif 140 141 #ifdef PLDM 142 , 143 resetCallBack(resetCallBack) 144 #endif 145 { 146 // Announce that we are ready 147 this->emit_object_added(); 148 } 149 150 /** @brief Since we are overriding the setter-occActive but not the 151 * getter-occActive, we need to have this using in order to 152 * allow passthrough usage of the getter-occActive 153 */ 154 using Base::Status::occActive; 155 156 /** @brief SET OccActive to True or False 157 * 158 * @param[in] value - Intended value 159 * 160 * @return - Updated value of the property 161 */ 162 bool occActive(bool value) override; 163 164 /** @brief Starts OCC error detection */ 165 inline void addErrorWatch() 166 { 167 return device.addErrorWatch(); 168 } 169 170 /** @brief Stops OCC error detection */ 171 inline void removeErrorWatch() 172 { 173 return device.removeErrorWatch(); 174 } 175 176 /** @brief Starts to watch how many OCCs are present on the master */ 177 inline void addPresenceWatchMaster() 178 { 179 return device.addPresenceWatchMaster(); 180 } 181 182 /** @brief Gets the occ instance number */ 183 unsigned int getOccInstanceID() 184 { 185 return instance; 186 } 187 188 /** @brief Is this OCC the master OCC */ 189 bool isMasterOcc() 190 { 191 return device.master(); 192 } 193 194 /** @brief Read OCC state (will trigger kernel to poll the OCC) */ 195 void readOccState(); 196 197 /** @brief Called when device errors are detected 198 * 199 * @param[in] d - description of the error that occurred 200 */ 201 void deviceError(Error::Descriptor d = Error::Descriptor()); 202 203 #ifdef POWER10 204 /** @brief Handle additional tasks when the OCCs reach active state */ 205 void occsWentActive(); 206 207 /** @brief Send Ambient & Altitude data to OCC 208 * 209 * @param[in] ambient - temperature to send (0xFF will force read 210 * of current temperature and altitude) 211 * @param[in] altitude - altitude to send (0xFFFF = unavailable) 212 * 213 * @return SUCCESS on success 214 */ 215 CmdStatus sendAmbient(const uint8_t ambient = 0xFF, 216 const uint16_t altitude = 0xFFFF); 217 218 /** @brief Set flag indicating if PLDM sensor has been received 219 * 220 * @param[in] wasReceived - true if PLDM sensor was read 221 */ 222 void setPldmSensorReceived(const bool wasReceived) 223 { 224 pldmSensorStateReceived = wasReceived; 225 } 226 227 /** @brief Read flag indicating if PLDM sensor has been read 228 * 229 * @return true if sensor has been read 230 */ 231 bool getPldmSensorReceived() 232 { 233 return pldmSensorStateReceived; 234 } 235 #endif // POWER10 236 237 /** @brief Return the HWMON path for this OCC 238 * 239 * @return path or empty path if not found 240 */ 241 fs::path getHwmonPath(); 242 243 /** @brief Update the processor path associated with this OCC 244 */ 245 void updateProcAssociation() 246 { 247 readProcAssociation(); 248 if (nullptr != throttleHandle) 249 { 250 throttleHandle.reset(); 251 } 252 if (!procPath.empty()) 253 { 254 throttleHandle = std::make_unique<ThrottleInterface>( 255 utils::getBus(), procPath.c_str()); 256 } 257 } 258 259 /** @brief Update the processor throttle status on dbus 260 */ 261 void updateThrottle(const bool isThrottled, const uint8_t reason); 262 263 private: 264 /** @brief OCC dbus object path */ 265 std::string path; 266 267 /** @brief Processor path associated with this OCC */ 268 std::string procPath; 269 270 /** @brief Callback handler to be invoked during property change. 271 * This is a handler in Manager class 272 */ 273 std::function<void(instanceID, bool)> managerCallBack; 274 275 /** @brief OCC instance number. Ex, 0,1, etc */ 276 unsigned int instance; 277 278 /** @brief The last state read from the OCC */ 279 unsigned int lastState = 0; 280 281 /** @brief Number of retry attempts to open file and update state. */ 282 const unsigned int occReadRetries = 1; 283 284 /** @brief Current number of retries attempted towards occReadRetries. */ 285 size_t currentOccReadRetriesCount = 0; 286 287 /** @brief The Trigger to indicate OCC State is valid or not. */ 288 bool stateValid = false; 289 290 /** @brief OCC instance to Sensor definitions mapping */ 291 static const std::map<instanceID, sensorDefs> sensorMap; 292 293 /** @brief OCC manager object */ 294 const Manager& manager; 295 296 #ifdef POWER10 297 /** @brief OCC PowerMode object */ 298 std::unique_ptr<powermode::PowerMode>& pmode; 299 #endif 300 301 /** @brief OCC device object to do bind and unbind */ 302 Device device; 303 304 /** @brief Subscribe to host control signal 305 * 306 * Once the OCC reset is requested, BMC sends that message to host. 307 * If the host does not ack the message, then there would be a timeout 308 * and we need to catch that to log an error 309 **/ 310 sdbusplus::bus::match_t hostControlSignal; 311 312 /** @brief Command object to send commands to the OCC */ 313 OccCommand occCmd; 314 315 #ifdef POWER10 316 /** @brief timer event */ 317 sdeventplus::Event sdpEvent; 318 #endif 319 320 /** @brief hwmon path for this OCC */ 321 fs::path hwmonPath; 322 323 /** @brief flag indicating if the OCC sensor has been received */ 324 bool pldmSensorStateReceived = false; 325 326 /** @brief Callback function on host control signals 327 * 328 * @param[in] msg - Data associated with subscribed signal 329 */ 330 void hostControlEvent(sdbusplus::message_t& msg); 331 332 /** @brief Sends a message to host control command handler to reset OCC 333 */ 334 void resetOCC(); 335 336 /** @brief Determines the instance ID by specified object path. 337 * @param[in] path Estimated OCC Dbus object path 338 * @return Instance number 339 */ 340 static int getInstance(const std::string& path) 341 { 342 return (path.empty() ? 0 : path.back() - '0'); 343 } 344 345 #ifdef POWER10 346 /** 347 * @brief Timer that is started when OCC is detected to be in safe mode 348 */ 349 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> 350 safeStateDelayTimer; 351 352 /** @brief Callback for timer that is started when OCC was detected to be in 353 * safe mode. Called to verify and then disable and reset the OCCs. 354 */ 355 void safeStateDelayExpired(); 356 357 /** 358 * @brief Timer that is started when OCC read Valid state failed. 359 */ 360 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> 361 occReadStateFailTimer; 362 363 #endif // POWER10 364 /** @brief Callback for timer that is started when OCC state 365 * was not able to be read. Called to attempt another read when needed. 366 */ 367 void occReadStateNow(); 368 369 /** @brief Override the sensor name with name from the definition. 370 * @param[in] estimatedPath - Estimated OCC Dbus object path 371 * @return Fixed OCC DBus object path 372 */ 373 static std::string getDbusPath(const std::string& estimatedPath) 374 { 375 if (!estimatedPath.empty()) 376 { 377 auto it = sensorMap.find(getInstance(estimatedPath)); 378 if (sensorMap.end() != it) 379 { 380 auto& name = std::get<1>(it->second); 381 if (!name.empty() && name != "None") 382 { 383 auto objectPath = fs::path(estimatedPath); 384 objectPath.replace_filename(name); 385 return objectPath.string(); 386 } 387 } 388 } 389 390 return estimatedPath; 391 } 392 #ifdef PLDM 393 std::function<void(instanceID)> resetCallBack = nullptr; 394 #endif 395 396 /** @brief Current throttle reason(s) for this processor */ 397 uint8_t throttleCause = THROTTLED_NONE; 398 399 /** @brief Throttle interface for the processor associated with this OCC */ 400 std::unique_ptr<ThrottleInterface> throttleHandle; 401 402 /** @brief Read the processor path associated with this OCC */ 403 void readProcAssociation(); 404 }; 405 406 } // namespace occ 407 } // namespace open_power 408