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