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