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 */ Status(EventPtr & event,const char * path,Manager & managerRef,std::unique_ptr<powermode::PowerMode> & powerModeRef,std::function<void (instanceID,bool)> callBack=nullptr,std::function<void (instanceID)> resetCallBack=nullptr)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 #endif 137 138 #ifdef PLDM 139 , 140 resetCallBack(resetCallBack) 141 #endif 142 { 143 // Announce that we are ready 144 this->emit_object_added(); 145 } 146 147 /** @brief Since we are overriding the setter-occActive but not the 148 * getter-occActive, we need to have this using in order to 149 * allow passthrough usage of the getter-occActive 150 */ 151 using Base::Status::occActive; 152 153 /** @brief SET OccActive to True or False 154 * 155 * @param[in] value - Intended value 156 * 157 * @return - Updated value of the property 158 */ 159 bool occActive(bool value) override; 160 161 /** @brief Starts OCC error detection */ addErrorWatch()162 inline void addErrorWatch() 163 { 164 return device.addErrorWatch(); 165 } 166 167 /** @brief Stops OCC error detection */ removeErrorWatch()168 inline void removeErrorWatch() 169 { 170 return device.removeErrorWatch(); 171 } 172 173 /** @brief Starts to watch how many OCCs are present on the master */ addPresenceWatchMaster()174 inline void addPresenceWatchMaster() 175 { 176 return device.addPresenceWatchMaster(); 177 } 178 179 /** @brief Gets the occ instance number */ getOccInstanceID()180 unsigned int getOccInstanceID() 181 { 182 return instance; 183 } 184 185 /** @brief Is this OCC the master OCC */ isMasterOcc()186 bool isMasterOcc() 187 { 188 return device.master(); 189 } 190 191 /** @brief Read OCC state (will trigger kernel to poll the OCC) */ 192 void readOccState(); 193 194 /** @brief Called when device errors are detected 195 * 196 * @param[in] d - description of the error that occurred 197 */ 198 void deviceError(Error::Descriptor d = Error::Descriptor()); 199 200 #ifdef POWER10 201 /** @brief Handle additional tasks when the OCCs reach active state */ 202 void occsWentActive(); 203 204 /** @brief Send Ambient & Altitude data to OCC 205 * 206 * @param[in] ambient - temperature to send (0xFF will force read 207 * of current temperature and altitude) 208 * @param[in] altitude - altitude to send (0xFFFF = unavailable) 209 * 210 * @return SUCCESS on success 211 */ 212 CmdStatus sendAmbient(const uint8_t ambient = 0xFF, 213 const uint16_t altitude = 0xFFFF); 214 215 /** @brief Set flag indicating if PLDM sensor has been received 216 * 217 * @param[in] wasReceived - true if PLDM sensor was read 218 */ setPldmSensorReceived(const bool wasReceived)219 void setPldmSensorReceived(const bool wasReceived) 220 { 221 pldmSensorStateReceived = wasReceived; 222 } 223 224 /** @brief Read flag indicating if PLDM sensor has been read 225 * 226 * @return true if sensor has been read 227 */ getPldmSensorReceived()228 bool getPldmSensorReceived() 229 { 230 return pldmSensorStateReceived; 231 } 232 #endif // POWER10 233 234 /** @brief Return the HWMON path for this OCC 235 * 236 * @return path or empty path if not found 237 */ 238 fs::path getHwmonPath(); 239 240 /** @brief Update the processor path associated with this OCC 241 */ updateProcAssociation()242 void updateProcAssociation() 243 { 244 readProcAssociation(); 245 if (nullptr != throttleHandle) 246 { 247 throttleHandle.reset(); 248 } 249 if (!procPath.empty()) 250 { 251 throttleHandle = std::make_unique<ThrottleInterface>( 252 utils::getBus(), procPath.c_str()); 253 } 254 } 255 256 /** @brief Update the processor throttle status on dbus 257 */ 258 void updateThrottle(const bool isThrottled, const uint8_t reason); 259 260 private: 261 /** @brief OCC dbus object path */ 262 std::string path; 263 264 /** @brief Processor path associated with this OCC */ 265 std::string procPath; 266 267 /** @brief Callback handler to be invoked during property change. 268 * This is a handler in Manager class 269 */ 270 std::function<void(instanceID, bool)> managerCallBack; 271 272 /** @brief OCC instance number. Ex, 0,1, etc */ 273 unsigned int instance; 274 275 /** @brief The last state read from the OCC */ 276 unsigned int lastState = 0; 277 278 /** @brief The last OCC read status (0 = no error) */ 279 int lastOccReadStatus = 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 */ getInstance(const std::string & path)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 #endif // POWER10 357 358 /** @brief Callback for timer that is started when OCC state 359 * was not able to be read. Called to attempt another read when needed. 360 */ 361 void occReadStateNow(); 362 363 /** @brief Override the sensor name with name from the definition. 364 * @param[in] estimatedPath - Estimated OCC Dbus object path 365 * @return Fixed OCC DBus object path 366 */ getDbusPath(const std::string & estimatedPath)367 static std::string getDbusPath(const std::string& estimatedPath) 368 { 369 if (!estimatedPath.empty()) 370 { 371 auto it = sensorMap.find(getInstance(estimatedPath)); 372 if (sensorMap.end() != it) 373 { 374 auto& name = std::get<1>(it->second); 375 if (!name.empty() && name != "None") 376 { 377 auto objectPath = fs::path(estimatedPath); 378 objectPath.replace_filename(name); 379 return objectPath.string(); 380 } 381 } 382 } 383 384 return estimatedPath; 385 } 386 #ifdef PLDM 387 std::function<void(instanceID)> resetCallBack = nullptr; 388 #endif 389 390 /** @brief Current throttle reason(s) for this processor */ 391 uint8_t throttleCause = THROTTLED_NONE; 392 393 /** @brief Throttle interface for the processor associated with this OCC */ 394 std::unique_ptr<ThrottleInterface> throttleHandle; 395 396 /** @brief Read the processor path associated with this OCC */ 397 void readProcAssociation(); 398 }; 399 400 } // namespace occ 401 } // namespace open_power 402