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