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