xref: /openbmc/phosphor-logging/extensions/openpower-pels/host_notifier.hpp (revision a19b6234410703c3b45d30636978e35f07f18394)
1f60ac27eSMatt Spinler #pragma once
2f60ac27eSMatt Spinler 
3f60ac27eSMatt Spinler #include "host_interface.hpp"
4f60ac27eSMatt Spinler #include "pel.hpp"
5f60ac27eSMatt Spinler #include "repository.hpp"
6f60ac27eSMatt Spinler 
7f60ac27eSMatt Spinler #include <deque>
8f869fcf8SMatt Spinler #include <sdeventplus/clock.hpp>
97d800a4eSMatt Spinler #include <sdeventplus/source/event.hpp>
10f869fcf8SMatt Spinler #include <sdeventplus/utility/timer.hpp>
11f60ac27eSMatt Spinler 
12f60ac27eSMatt Spinler namespace openpower::pels
13f60ac27eSMatt Spinler {
14f60ac27eSMatt Spinler 
15f60ac27eSMatt Spinler /**
16f60ac27eSMatt Spinler  * @class HostNotifier
17f60ac27eSMatt Spinler  *
18f60ac27eSMatt Spinler  * This class handles notifying the host firmware of new PELs.
19f60ac27eSMatt Spinler  */
20f60ac27eSMatt Spinler class HostNotifier
21f60ac27eSMatt Spinler {
22f60ac27eSMatt Spinler   public:
23f60ac27eSMatt Spinler     HostNotifier() = delete;
24f60ac27eSMatt Spinler     HostNotifier(const HostNotifier&) = delete;
25f60ac27eSMatt Spinler     HostNotifier& operator=(const HostNotifier&) = delete;
26f60ac27eSMatt Spinler     HostNotifier(HostNotifier&&) = delete;
27f60ac27eSMatt Spinler     HostNotifier& operator=(HostNotifier&&) = delete;
28f60ac27eSMatt Spinler 
29f60ac27eSMatt Spinler     /**
30f60ac27eSMatt Spinler      * @brief Constructor
31f60ac27eSMatt Spinler      *
32f60ac27eSMatt Spinler      * @param[in] repo - The PEL repository object
33f60ac27eSMatt Spinler      * @param[in] dataIface - The data interface object
34f60ac27eSMatt Spinler      * @param[in] hostIface - The host interface object
35f60ac27eSMatt Spinler      */
36f60ac27eSMatt Spinler     HostNotifier(Repository& repo, DataInterfaceBase& dataIface,
37f60ac27eSMatt Spinler                  std::unique_ptr<HostInterface> hostIface);
38f60ac27eSMatt Spinler 
39f60ac27eSMatt Spinler     /**
40f60ac27eSMatt Spinler      * @brief Destructor
41f60ac27eSMatt Spinler      */
42f60ac27eSMatt Spinler     ~HostNotifier();
43f60ac27eSMatt Spinler 
44f60ac27eSMatt Spinler     /**
45f60ac27eSMatt Spinler      * @brief Returns the PEL queue size.
46f60ac27eSMatt Spinler      *
47f60ac27eSMatt Spinler      * For testing.
48f60ac27eSMatt Spinler      *
49f60ac27eSMatt Spinler      * @return size_t - The queue size
50f60ac27eSMatt Spinler      */
51f60ac27eSMatt Spinler     size_t queueSize() const
52f60ac27eSMatt Spinler     {
53f60ac27eSMatt Spinler         return _pelQueue.size();
54f60ac27eSMatt Spinler     }
55f60ac27eSMatt Spinler 
56f60ac27eSMatt Spinler     /**
57f60ac27eSMatt Spinler      * @brief Specifies if the PEL needs to go onto the queue to be
58f60ac27eSMatt Spinler      *        set to the host.
59f60ac27eSMatt Spinler      *
60a943b15bSMatt Spinler      * Only returns false if:
61a943b15bSMatt Spinler      *  - Already acked by the host (or they didn't like it)
62a943b15bSMatt Spinler      *  - Hidden and the HMC already got it
63a943b15bSMatt Spinler      *  - The 'do not report to host' bit is set
64a943b15bSMatt Spinler      *
65f60ac27eSMatt Spinler      * @param[in] id - The PEL ID
66f60ac27eSMatt Spinler      *
67f60ac27eSMatt Spinler      * @return bool - If enqueue is required
68f60ac27eSMatt Spinler      */
69f60ac27eSMatt Spinler     bool enqueueRequired(uint32_t id) const;
70f60ac27eSMatt Spinler 
71f77debb9SMatt Spinler     /**
72f77debb9SMatt Spinler      * @brief If the host still needs to be notified of the PEL
73f77debb9SMatt Spinler      *        at the time of the notification.
74f77debb9SMatt Spinler      *
75f77debb9SMatt Spinler      * Only returns false if:
76f77debb9SMatt Spinler      *  - Already acked by the host
77f77debb9SMatt Spinler      *  - It's hidden, and the HMC already got or will get it.
78f77debb9SMatt Spinler      *
79f77debb9SMatt Spinler      * @param[in] id - The PEL ID
80f77debb9SMatt Spinler      *
81f77debb9SMatt Spinler      * @return bool - If the notify is required
82f77debb9SMatt Spinler      */
83f77debb9SMatt Spinler     bool notifyRequired(uint32_t id) const;
84f77debb9SMatt Spinler 
85cc3b64aeSMatt Spinler     /**
86cc3b64aeSMatt Spinler      * @brief Called when the host sends the 'ack' PLDM command.
87cc3b64aeSMatt Spinler      *
88cc3b64aeSMatt Spinler      * This means the PEL never needs to be sent up again.
89cc3b64aeSMatt Spinler      *
9041293cb8SMatt Spinler      * If the host was previously full, it is also an indication
9141293cb8SMatt Spinler      * it no longer is.
9241293cb8SMatt Spinler      *
93cc3b64aeSMatt Spinler      * @param[in] id - The PEL ID
94cc3b64aeSMatt Spinler      */
95cc3b64aeSMatt Spinler     void ackPEL(uint32_t id);
96cc3b64aeSMatt Spinler 
9741293cb8SMatt Spinler     /**
9841293cb8SMatt Spinler      * @brief Called when the host does not have room for more
9941293cb8SMatt Spinler      *        PELs at this time.
10041293cb8SMatt Spinler      *
10141293cb8SMatt Spinler      * This can happen when an OS isn't running yet, and the
10241293cb8SMatt Spinler      * staging area to hold the PELs before sending them up
10341293cb8SMatt Spinler      * to the OS is full.  This will stop future PEls from being
10441293cb8SMatt Spinler      * sent up, as explained below.
10541293cb8SMatt Spinler      *
10641293cb8SMatt Spinler      * The PEL with this ID will need to be sent again, so its
10741293cb8SMatt Spinler      * state is set back to 'new', and it is removed from the list
10841293cb8SMatt Spinler      * of already sent PELs.
10941293cb8SMatt Spinler      *
11041293cb8SMatt Spinler      * A timer will be started, if it isn't already running, to
11141293cb8SMatt Spinler      * issue another send in the hopes that space has been freed
11241293cb8SMatt Spinler      * up by then (Receiving an ackPEL response is also an
11341293cb8SMatt Spinler      * indication of this if there happened to have been other
11441293cb8SMatt Spinler      * PELs in flight).
11541293cb8SMatt Spinler      *
11641293cb8SMatt Spinler      * @param[in] id - The PEL ID
11741293cb8SMatt Spinler      */
11841293cb8SMatt Spinler     void setHostFull(uint32_t id);
11941293cb8SMatt Spinler 
120*a19b6234SMatt Spinler     /**
121*a19b6234SMatt Spinler      * @brief Called when the host receives a malformed PEL.
122*a19b6234SMatt Spinler      *
123*a19b6234SMatt Spinler      * Ideally this will never happen, as the Repository
124*a19b6234SMatt Spinler      * class already purges malformed PELs.
125*a19b6234SMatt Spinler      *
126*a19b6234SMatt Spinler      * The PEL should never be sent up again.
127*a19b6234SMatt Spinler      *
128*a19b6234SMatt Spinler      * @param[in] id - The PEL ID
129*a19b6234SMatt Spinler      */
130*a19b6234SMatt Spinler     void setBadPEL(uint32_t id);
131*a19b6234SMatt Spinler 
132f60ac27eSMatt Spinler   private:
133f60ac27eSMatt Spinler     /**
134f60ac27eSMatt Spinler      * @brief This function gets called by the Repository class
135f60ac27eSMatt Spinler      *        when a new PEL is added to it.
136f60ac27eSMatt Spinler      *
1377d800a4eSMatt Spinler      * This function puts the PEL on the queue to be sent up if it
1387d800a4eSMatt Spinler      * needs it, and possibly dispatch the send if the conditions call
1397d800a4eSMatt Spinler      * for it.
1407d800a4eSMatt Spinler      *
141f60ac27eSMatt Spinler      * @param[in] pel - The new PEL
142f60ac27eSMatt Spinler      */
143f60ac27eSMatt Spinler     void newLogCallback(const PEL& pel);
144f60ac27eSMatt Spinler 
145f60ac27eSMatt Spinler     /**
146f60ac27eSMatt Spinler      * @brief This function runs on every existing PEL at startup
147f60ac27eSMatt Spinler      *        and puts the PEL on the queue to send if necessary.
148f60ac27eSMatt Spinler      *
149f60ac27eSMatt Spinler      * @param[in] pel - The PEL
150f60ac27eSMatt Spinler      *
151f60ac27eSMatt Spinler      * @return bool - This is an indicator to the Repository::for_each
152f60ac27eSMatt Spinler      *                function to traverse every PEL.  Always false.
153f60ac27eSMatt Spinler      */
154f60ac27eSMatt Spinler     bool addPELToQueue(const PEL& pel);
155f60ac27eSMatt Spinler 
156f60ac27eSMatt Spinler     /**
157f77debb9SMatt Spinler      * @brief Takes the first PEL from the queue that needs to be
158f77debb9SMatt Spinler      *        sent, and issues the send if conditions are right.
159f60ac27eSMatt Spinler      */
160f60ac27eSMatt Spinler     void doNewLogNotify();
161f60ac27eSMatt Spinler 
162f60ac27eSMatt Spinler     /**
1637d800a4eSMatt Spinler      * @brief Creates the event object to handle sending the PLDM
1647d800a4eSMatt Spinler      *        command from the event loop.
1657d800a4eSMatt Spinler      */
1667d800a4eSMatt Spinler     void scheduleDispatch();
1677d800a4eSMatt Spinler 
1687d800a4eSMatt Spinler     /**
1697d800a4eSMatt Spinler      * @brief Kicks off the PLDM send, but called from the event
1707d800a4eSMatt Spinler      *        loop.
1717d800a4eSMatt Spinler      *
1727d800a4eSMatt Spinler      * @param[in] source - The event source object
1737d800a4eSMatt Spinler      */
1747d800a4eSMatt Spinler     void dispatch(sdeventplus::source::EventBase& source);
1757d800a4eSMatt Spinler 
1767d800a4eSMatt Spinler     /**
177f60ac27eSMatt Spinler      * @brief Called when the host changes state.
178f60ac27eSMatt Spinler      *
1793019c6fbSMatt Spinler      * If the new state is host up and there are PELs to send, it
1803019c6fbSMatt Spinler      * will trigger the first command.  If the new state is off, then
1813019c6fbSMatt Spinler      * it will transfer any PELs that were sent but not acked yet back
1823019c6fbSMatt Spinler      * to the queue to be sent again.
1833019c6fbSMatt Spinler      *
184f60ac27eSMatt Spinler      * @param[in] hostUp - The new host state
185f60ac27eSMatt Spinler      */
186f60ac27eSMatt Spinler     void hostStateChange(bool hostUp);
187f60ac27eSMatt Spinler 
188f60ac27eSMatt Spinler     /**
189f60ac27eSMatt Spinler      * @brief The callback function invoked after the asynchronous
190f60ac27eSMatt Spinler      *        PLDM receive function is complete.
191f60ac27eSMatt Spinler      *
192f869fcf8SMatt Spinler      * If the command was successful, the state of that PEL will
193f869fcf8SMatt Spinler      * be set to 'sent', and the next send will be triggered.
194f869fcf8SMatt Spinler      *
195f869fcf8SMatt Spinler      * If the command failed, a retry timer will be started so it
196f869fcf8SMatt Spinler      * can be sent again.
197f869fcf8SMatt Spinler      *
198f60ac27eSMatt Spinler      * @param[in] status - The response status
199f60ac27eSMatt Spinler      */
200f60ac27eSMatt Spinler     void commandResponse(ResponseStatus status);
201f60ac27eSMatt Spinler 
202f60ac27eSMatt Spinler     /**
203f869fcf8SMatt Spinler      * @brief The function called when the command failure retry
204f869fcf8SMatt Spinler      *        time is up.
205f869fcf8SMatt Spinler      *
206f869fcf8SMatt Spinler      * It will issue a send of the previous PEL and increment the
207f869fcf8SMatt Spinler      * retry count.
208f869fcf8SMatt Spinler      */
209f869fcf8SMatt Spinler     void retryTimerExpired();
210f869fcf8SMatt Spinler 
211f869fcf8SMatt Spinler     /**
21241293cb8SMatt Spinler      * @brief The function called when the 'host full' retry timer
21341293cb8SMatt Spinler      *        expires.
21441293cb8SMatt Spinler      *
21541293cb8SMatt Spinler      * This will re-issue a command to try again with the PEL at
21641293cb8SMatt Spinler      * the front of the queue.
21741293cb8SMatt Spinler      */
21841293cb8SMatt Spinler     void hostFullTimerExpired();
21941293cb8SMatt Spinler 
22041293cb8SMatt Spinler     /**
2213019c6fbSMatt Spinler      * @brief Stops an in progress command
2223019c6fbSMatt Spinler      *
2233019c6fbSMatt Spinler      * In progress meaning after the send but before the response.
2243019c6fbSMatt Spinler      */
2253019c6fbSMatt Spinler     void stopCommand();
2263019c6fbSMatt Spinler 
2273019c6fbSMatt Spinler     /**
228f60ac27eSMatt Spinler      * @brief The PEL repository object
229f60ac27eSMatt Spinler      */
230f60ac27eSMatt Spinler     Repository& _repo;
231f60ac27eSMatt Spinler 
232f60ac27eSMatt Spinler     /**
233f60ac27eSMatt Spinler      * @brief The data interface object
234f60ac27eSMatt Spinler      */
235f60ac27eSMatt Spinler     DataInterfaceBase& _dataIface;
236f60ac27eSMatt Spinler 
237f60ac27eSMatt Spinler     /**
238f60ac27eSMatt Spinler      * @brief Base class pointer for the host command interface
239f60ac27eSMatt Spinler      */
240f60ac27eSMatt Spinler     std::unique_ptr<HostInterface> _hostIface;
241f60ac27eSMatt Spinler 
242f60ac27eSMatt Spinler     /**
243f60ac27eSMatt Spinler      * @brief The list of PEL IDs that need to be sent.
244f60ac27eSMatt Spinler      */
245f60ac27eSMatt Spinler     std::deque<uint32_t> _pelQueue;
246f869fcf8SMatt Spinler 
247f869fcf8SMatt Spinler     /**
248f869fcf8SMatt Spinler      * @brief The list of IDs that were sent, but not acked yet.
249f869fcf8SMatt Spinler      *
250f869fcf8SMatt Spinler      * These move back to _pelQueue on a power off.
251f869fcf8SMatt Spinler      */
252f869fcf8SMatt Spinler     std::vector<uint32_t> _sentPELs;
253f869fcf8SMatt Spinler 
254f869fcf8SMatt Spinler     /**
255f869fcf8SMatt Spinler      * @brief The ID the PEL where the notification has
256f869fcf8SMatt Spinler      *        been kicked off but the asynchronous response
257f869fcf8SMatt Spinler      *        hasn't been received yet.
258f869fcf8SMatt Spinler      */
259f869fcf8SMatt Spinler     uint32_t _inProgressPEL = 0;
260f869fcf8SMatt Spinler 
261f869fcf8SMatt Spinler     /**
262f869fcf8SMatt Spinler      * @brief The command retry count
263f869fcf8SMatt Spinler      */
264f869fcf8SMatt Spinler     size_t _retryCount = 0;
265f869fcf8SMatt Spinler 
266f869fcf8SMatt Spinler     /**
26741293cb8SMatt Spinler      * @brief Indicates if the host has said it is full and does not
26841293cb8SMatt Spinler      *        currently have the space for more PELs.
26941293cb8SMatt Spinler      */
27041293cb8SMatt Spinler     bool _hostFull = false;
27141293cb8SMatt Spinler 
27241293cb8SMatt Spinler     /**
273f869fcf8SMatt Spinler      * @brief The command retry timer.
274f869fcf8SMatt Spinler      */
275f869fcf8SMatt Spinler     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _retryTimer;
2767d800a4eSMatt Spinler 
2777d800a4eSMatt Spinler     /**
27841293cb8SMatt Spinler      * @brief The host full timer, used to retry sending a PEL if the host
27941293cb8SMatt Spinler      *        said it is full.
28041293cb8SMatt Spinler      */
28141293cb8SMatt Spinler     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _hostFullTimer;
28241293cb8SMatt Spinler 
28341293cb8SMatt Spinler     /**
2847d800a4eSMatt Spinler      * @brief The object used to dispatch a new PEL send from the
2857d800a4eSMatt Spinler      *        event loop, so the calling function can be returned from
2867d800a4eSMatt Spinler      *        first.
2877d800a4eSMatt Spinler      */
2887d800a4eSMatt Spinler     std::unique_ptr<sdeventplus::source::Defer> _dispatcher;
289f60ac27eSMatt Spinler };
290f60ac27eSMatt Spinler 
291f60ac27eSMatt Spinler } // namespace openpower::pels
292