1 #pragma once
2 
3 #include <string.h>
4 
5 #include <analyzer/service_data.hpp>
6 #include <hei_chip.hpp>
7 #include <util/trace.hpp>
8 
9 #include <functional>
10 #include <map>
11 
12 namespace analyzer
13 {
14 
15 // A plugin is special function called by the RAS data files specifically for
16 // service actions that cannot be characterized by the RAS data files.
17 //
18 // IMPORTANT:
19 //   Use of these plugins should be limited to avoid maintaining chip specific
20 //   functionality in this repository.
21 //
22 // Each plugin must be defined in a specific form. See PluginFunction below.
23 // Then the plugin must registered in the PluginMap using the PLUGIN_DEFINE or
24 // PLUGIN_DEFINE_NS macros below.
25 
26 // All plugins will have the following parameters:
27 //  - The plugin instance for plugins that may be defined for a chip that has
28 //    multiple instance of a unit/register.
29 //  - The chip containing the root cause attention.
30 //  - The service data object containing service actions and FFDC for the root
31 //    cause attention.
32 using PluginFunction =
33     std::function<void(unsigned int, const libhei::Chip&, ServiceData&)>;
34 
35 // These are provided as know chip types for plugin definitions.
36 constexpr libhei::ChipType_t EXPLORER_11 = 0x60d20011;
37 constexpr libhei::ChipType_t EXPLORER_20 = 0x60d20020;
38 constexpr libhei::ChipType_t P10_10      = 0x20da0010;
39 constexpr libhei::ChipType_t P10_20      = 0x20da0020;
40 
41 /**
42  * @brief This is simply a global container for all of the registered plugins.
43  *
44  * @note  This class cannot be instantiated. Instead, use the getSingleton()
45  *        function to access.
46  */
47 class PluginMap
48 {
49   private:
50     /** @brief Default constructor. */
51     PluginMap() = default;
52 
53     /** @brief Destructor. */
54     ~PluginMap() = default;
55 
56     /** @brief Copy constructor. */
57     PluginMap(const PluginMap&) = delete;
58 
59     /** @brief Assignment operator. */
60     PluginMap& operator=(const PluginMap&) = delete;
61 
62   public:
63     /** @brief Provides access to a singleton instance of this object. */
64     static PluginMap& getSingleton()
65     {
66         static PluginMap thePluginMap;
67         return thePluginMap;
68     }
69 
70   private:
71     /** A nested map that contains the function for each chip type and plugin
72      *  name. */
73     std::map<libhei::ChipType_t, std::map<std::string, PluginFunction>> iv_map;
74 
75   public:
76     /**
77      * @brief Registers a plugin with the plugin map.
78      *
79      * @param i_type   The chip type associated with the plugin.
80      * @param i_name   The name of the plugin.
81      * @param i_plugin The plugin function.
82      *
83      * @throw std::logic_error if a plugin is defined more than once.
84      */
85     void add(libhei::ChipType_t i_type, const std::string& i_name,
86              PluginFunction i_plugin)
87     {
88         auto itr = iv_map.find(i_type);
89         if (iv_map.end() == itr ||
90             itr->second.end() == itr->second.find(i_name))
91         {
92             iv_map[i_type][i_name] = i_plugin;
93         }
94         else
95         {
96             throw std::logic_error("Duplicate plugin found");
97         }
98     }
99 
100     /**
101      * @return The plugin function for the target plugin.
102      *
103      * @param i_type The chip type associated with the plugin.
104      * @param i_name The name of the plugin.
105      *
106      * @throw std::out_of_range if the target plugin does not exist.
107      */
108     PluginFunction get(libhei::ChipType_t i_type,
109                        const std::string& i_name) const
110     {
111         PluginFunction func;
112 
113         try
114         {
115             func = iv_map.at(i_type).at(i_name);
116         }
117         catch (const std::out_of_range& e)
118         {
119             trace::err("Plugin not defined: i_type=0x%08x i_name=%s", i_type,
120                        i_name.c_str());
121             throw; // caught later downstream
122         }
123 
124         return func;
125     }
126 };
127 
128 // These defines a unique class and a global variable for each plugin. Because
129 // the variables are defined in the global scope, they will be initialized with
130 // the default constructor before execution of the program. This allows all of
131 // the plugins to be registered in the plugin map before execution.
132 
133 #define __PLUGIN_MAKE(X, Y, Z) X##Y##Z
134 
135 #define __PLUGIN_DEFINE(CHIP, NAME, FUNC)                                      \
136     class __PLUGIN_MAKE(Plugin_, CHIP, NAME)                                   \
137     {                                                                          \
138       public:                                                                  \
139         __PLUGIN_MAKE(Plugin_, CHIP, NAME)                                     \
140         ()                                                                     \
141         {                                                                      \
142             PluginMap::getSingleton().add(CHIP, #NAME, &FUNC);                 \
143         }                                                                      \
144     };                                                                         \
145     __PLUGIN_MAKE(Plugin_, CHIP, NAME) __PLUGIN_MAKE(g_Plugin_, CHIP, NAME)
146 
147 #define PLUGIN_DEFINE(CHIP, NAME) __PLUGIN_DEFINE(CHIP, NAME, CHIP::NAME)
148 
149 #define PLUGIN_DEFINE_NS(CHIP, NS, NAME) __PLUGIN_DEFINE(CHIP, NAME, NS::NAME)
150 
151 // Regarding the use of PLUGIN_DEFINE_NS. This is provided for cases where the
152 // same plugin needs to be defined differently for different chips. Example:
153 //
154 //    namespace A
155 //    {
156 //        void foo(...) { /* definition for chip A */ }
157 //    };
158 //
159 //    namespace B
160 //    {
161 //        void foo(...) { /* definition for chip B */ }
162 //    };
163 //
164 //    PLUGIN_DEFINE_NS(CHIP_A, A, foo);
165 //    PLUGIN_DEFINE_NS(CHIP_B, B, foo);
166 //
167 // Also, it is important that the plugin definitions should be declared outside
168 // of the function namespaces (see the example above). This helps find
169 // duplicate plugin definitions at compile time. Otherwise, if you do something
170 // like this:
171 //
172 //    namespace A
173 //    {
174 //        void foo(...) { /* definition for chip A */ }
175 //        PLUGIN_DEFINE_NS(CHIP_A, A, foo);
176 //    };
177 //
178 //    namespace B
179 //    {
180 //        void foo(...) { /* definition again for chip A */ }
181 //        PLUGIN_DEFINE_NS(CHIP_A, B, foo);
182 //    };
183 //
184 // The compiler will not find the duplicate and instead it will be found during
185 // program execution, which will result in an exception.
186 
187 } // namespace analyzer
188