xref: /openbmc/openpower-occ-control/occ_status.hpp (revision 17257673579b66c6e5c2769fc0a1ffd2decc71d2)
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 
15 #include <functional>
16 
17 namespace open_power
18 {
19 namespace occ
20 {
21 
22 class Manager;
23 namespace Base = sdbusplus::org::open_power::OCC::server;
24 using Interface = sdbusplus::server::object::object<Base::Status>;
25 
26 // IPMID's host control application
27 namespace Control = sdbusplus::org::open_power::Control::server;
28 
29 // For waiting on signals
30 namespace sdbusRule = sdbusplus::bus::match::rules;
31 
32 // OCC status instance. Ex. for "occ0", the instance is 0
33 using instanceID = int;
34 
35 // IPMI sensor ID for a given OCC instance
36 using sensorID = uint8_t;
37 
38 // Human readable sensor name for DBus tree. E.g. "CPU0_OCC"
39 using sensorName = std::string;
40 
41 // OCC sensors definitions in the map
42 using sensorDefs = std::tuple<sensorID, sensorName>;
43 
44 // OCC sysfs name prefix
45 const std::string sysfsName = "occ-hwmon";
46 
47 /** @class Status
48  *  @brief Implementation of OCC Active Status
49  */
50 class Status : public Interface
51 {
52   public:
53     Status() = delete;
54     ~Status() = default;
55     Status(const Status&) = delete;
56     Status& operator=(const Status&) = delete;
57     Status(Status&&) = default;
58     Status& operator=(Status&&) = default;
59 
60     /** @brief Constructs the Status object and
61      *         the underlying device object
62      *
63      *  @param[in] event    - sd_event unique pointer reference
64      *  @param[in] path     - DBus object path
65      *  @param[in] manager  - OCC manager instance
66      *  @param[in] callBack - Callback handler to invoke during
67      *                        property change
68      *  @param[in] resetCallBack - callback handler to invoke for resetting the
69      *                             OCC if PLDM is the host communication
70      *                             protocol
71      */
72     Status(EventPtr& event, const char* path, Manager& managerRef,
73            std::function<void(bool)> callBack = nullptr
74 #ifdef PLDM
75            ,
76            std::function<void(instanceID)> resetCallBack = nullptr
77 #endif
78            ) :
79 
80         Interface(utils::getBus(), getDbusPath(path).c_str(), true),
81         path(path), callBack(callBack), instance(getInstance(path)),
82         manager(managerRef),
83         device(event,
84 #ifdef I2C_OCC
85                fs::path(DEV_PATH) / i2c_occ::getI2cDeviceName(path),
86 #else
87                fs::path(DEV_PATH) /
88                    fs::path(sysfsName + "." + std::to_string(instance + 1)),
89 #endif
90                managerRef, *this, instance),
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     /** @brief Called when device errors are detected */
166     void deviceError();
167 
168 #ifdef POWER10
169     /** @brief Handle additional tasks when the OCCs reach active state */
170     void occsWentActive();
171 
172     /** @brief Send mode change command to the master OCC
173      *  @return SUCCESS on success
174      */
175     CmdStatus sendModeChange();
176 
177     /** @brief Send Idle Power Saver config data to the master OCC
178      *  @return SUCCESS on success
179      */
180     CmdStatus sendIpsData();
181 
182     /** @brief Send Ambient & Altitude data to OCC
183      *
184      *  @param[in] ambient - temperature to send (0xFF will force read
185      *                       of current temperature and altitude)
186      *  @param[in] altitude - altitude to send (0xFFFF = unavailable)
187      *
188      *  @return SUCCESS on success
189      */
190     CmdStatus sendAmbient(const uint8_t ambient = 0xFF,
191                           const uint16_t altitude = 0xFFFF);
192 #endif // POWER10
193 
194   private:
195     /** @brief OCC dbus object path */
196     std::string path;
197 
198     /** @brief Callback handler to be invoked during property change.
199      *         This is a handler in Manager class
200      */
201     std::function<void(bool)> callBack;
202 
203     /** @brief OCC instance number. Ex, 0,1, etc */
204     unsigned int instance;
205 
206     /** @brief The last state read from the OCC */
207     unsigned int lastState = 0;
208 
209     /** @brief OCC instance to Sensor definitions mapping */
210     static const std::map<instanceID, sensorDefs> sensorMap;
211 
212     /** @brief OCC manager object */
213     const Manager& manager;
214 
215     /** @brief OCC device object to do bind and unbind */
216     Device device;
217 
218     /** @brief Subscribe to host control signal
219      *
220      *  Once the OCC reset is requested, BMC sends that message to host.
221      *  If the host does not ack the message, then there would be a timeout
222      *  and we need to catch that to log an error
223      **/
224     sdbusplus::bus::match_t hostControlSignal;
225 
226     /** @brief Command object to send commands to the OCC */
227     OccCommand occCmd;
228 
229     /** @brief Callback function on host control signals
230      *
231      *  @param[in]  msg - Data associated with subscribed signal
232      */
233     void hostControlEvent(sdbusplus::message::message& msg);
234 
235     /** @brief Sends a message to host control command handler to reset OCC
236      */
237     void resetOCC();
238 
239     /** @brief Determines the instance ID by specified object path.
240      *  @param[in]  path  Estimated OCC Dbus object path
241      *  @return  Instance number
242      */
243     static int getInstance(const std::string& path)
244     {
245         return (path.empty() ? 0 : path.back() - '0');
246     }
247 
248 #ifdef POWER10
249     /** @brief Query the current Hypervisor target
250      * @return true if the current Hypervisor target is PowerVM
251      */
252     bool isPowerVM();
253 
254     /** @brief Get the requested power mode property
255      * @return Power mode
256      */
257     SysPwrMode getMode();
258 
259     /** @brief Get the Idle Power Saver properties
260      * @return true if IPS is enabled
261      */
262     bool getIPSParms(uint8_t& enterUtil, uint16_t& enterTime, uint8_t& exitUtil,
263                      uint16_t& exitTime);
264 #endif // POWER10
265 
266     /** @brief Override the sensor name with name from the definition.
267      *  @param[in]  estimatedPath - Estimated OCC Dbus object path
268      *  @return  Fixed OCC DBus object path
269      */
270     static std::string getDbusPath(const std::string& estimatedPath)
271     {
272         if (!estimatedPath.empty())
273         {
274             auto it = sensorMap.find(getInstance(estimatedPath));
275             if (sensorMap.end() != it)
276             {
277                 auto& name = std::get<1>(it->second);
278                 if (!name.empty() && name != "None")
279                 {
280                     auto path = fs::path(estimatedPath);
281                     path.replace_filename(name);
282                     return path.string();
283                 }
284             }
285         }
286 
287         return estimatedPath;
288     }
289 #ifdef PLDM
290     std::function<void(instanceID)> resetCallBack = nullptr;
291 #endif
292 };
293 
294 } // namespace occ
295 } // namespace open_power
296