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