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 #endif // POWER10 205 206 /** @brief Return the HWMON path for this OCC 207 * 208 * @return path or empty path if not found 209 */ 210 fs::path getHwmonPath(); 211 212 private: 213 /** @brief OCC dbus object path */ 214 std::string path; 215 216 /** @brief Callback handler to be invoked during property change. 217 * This is a handler in Manager class 218 */ 219 std::function<void(instanceID, bool)> managerCallBack; 220 221 /** @brief OCC instance number. Ex, 0,1, etc */ 222 unsigned int instance; 223 224 /** @brief The last state read from the OCC */ 225 unsigned int lastState = 0; 226 227 /** @brief Number of retry attempts to open file and update state. */ 228 const unsigned int occReadRetries = 1; 229 230 /** @brief Current number of retries attempted towards occReadRetries. */ 231 size_t currentOccReadRetriesCount = 0; 232 233 /** @brief The Trigger to indicate OCC State is valid or not. */ 234 bool stateValid = false; 235 236 /** @brief OCC instance to Sensor definitions mapping */ 237 static const std::map<instanceID, sensorDefs> sensorMap; 238 239 /** @brief OCC manager object */ 240 const Manager& manager; 241 242 #ifdef POWER10 243 /** @brief OCC PowerMode object */ 244 std::unique_ptr<powermode::PowerMode>& pmode; 245 #endif 246 247 /** @brief OCC device object to do bind and unbind */ 248 Device device; 249 250 /** @brief Subscribe to host control signal 251 * 252 * Once the OCC reset is requested, BMC sends that message to host. 253 * If the host does not ack the message, then there would be a timeout 254 * and we need to catch that to log an error 255 **/ 256 sdbusplus::bus::match_t hostControlSignal; 257 258 /** @brief Command object to send commands to the OCC */ 259 OccCommand occCmd; 260 261 #ifdef POWER10 262 /** @brief timer event */ 263 sdeventplus::Event sdpEvent; 264 #endif 265 266 /** @brief hwmon path for this OCC */ 267 fs::path hwmonPath; 268 269 /** @brief Callback function on host control signals 270 * 271 * @param[in] msg - Data associated with subscribed signal 272 */ 273 void hostControlEvent(sdbusplus::message::message& msg); 274 275 /** @brief Sends a message to host control command handler to reset OCC 276 */ 277 void resetOCC(); 278 279 /** @brief Determines the instance ID by specified object path. 280 * @param[in] path Estimated OCC Dbus object path 281 * @return Instance number 282 */ 283 static int getInstance(const std::string& path) 284 { 285 return (path.empty() ? 0 : path.back() - '0'); 286 } 287 288 #ifdef POWER10 289 /** 290 * @brief Timer that is started when OCC is detected to be in safe mode 291 */ 292 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> 293 safeStateDelayTimer; 294 295 /** @brief Callback for timer that is started when OCC was detected to be in 296 * safe mode. Called to verify and then disable and reset the OCCs. 297 */ 298 void safeStateDelayExpired(); 299 300 /** 301 * @brief Timer that is started when OCC read Valid state failed. 302 */ 303 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> 304 occReadStateFailTimer; 305 306 #endif // POWER10 307 /** @brief Callback for timer that is started when OCC state 308 * was not able to be read. Called to attempt another read when needed. 309 */ 310 void occReadStateNow(); 311 312 /** @brief Override the sensor name with name from the definition. 313 * @param[in] estimatedPath - Estimated OCC Dbus object path 314 * @return Fixed OCC DBus object path 315 */ 316 static std::string getDbusPath(const std::string& estimatedPath) 317 { 318 if (!estimatedPath.empty()) 319 { 320 auto it = sensorMap.find(getInstance(estimatedPath)); 321 if (sensorMap.end() != it) 322 { 323 auto& name = std::get<1>(it->second); 324 if (!name.empty() && name != "None") 325 { 326 auto objectPath = fs::path(estimatedPath); 327 objectPath.replace_filename(name); 328 return objectPath.string(); 329 } 330 } 331 } 332 333 return estimatedPath; 334 } 335 #ifdef PLDM 336 std::function<void(instanceID)> resetCallBack = nullptr; 337 #endif 338 }; 339 340 } // namespace occ 341 } // namespace open_power 342