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 ODYSSEY_10 = 0x60c00010;
39 constexpr libhei::ChipType_t P10_10 = 0x20da0010;
40 constexpr libhei::ChipType_t P10_20 = 0x20da0020;
41 
42 /**
43  * @brief This is simply a global container for all of the registered plugins.
44  *
45  * @note  This class cannot be instantiated. Instead, use the getSingleton()
46  *        function to access.
47  */
48 class PluginMap
49 {
50   private:
51     /** @brief Default constructor. */
52     PluginMap() = default;
53 
54     /** @brief Destructor. */
55     ~PluginMap() = default;
56 
57     /** @brief Copy constructor. */
58     PluginMap(const PluginMap&) = delete;
59 
60     /** @brief Assignment operator. */
61     PluginMap& operator=(const PluginMap&) = delete;
62 
63   public:
64     /** @brief Provides access to a singleton instance of this object. */
getSingleton()65     static PluginMap& getSingleton()
66     {
67         static PluginMap thePluginMap;
68         return thePluginMap;
69     }
70 
71   private:
72     /** A nested map that contains the function for each chip type and plugin
73      *  name. */
74     std::map<libhei::ChipType_t, std::map<std::string, PluginFunction>> iv_map;
75 
76   public:
77     /**
78      * @brief Registers a plugin with the plugin map.
79      *
80      * @param i_type   The chip type associated with the plugin.
81      * @param i_name   The name of the plugin.
82      * @param i_plugin The plugin function.
83      *
84      * @throw std::logic_error if a plugin is defined more than once.
85      */
add(libhei::ChipType_t i_type,const std::string & i_name,PluginFunction i_plugin)86     void add(libhei::ChipType_t i_type, const std::string& i_name,
87              PluginFunction i_plugin)
88     {
89         auto itr = iv_map.find(i_type);
90         if (iv_map.end() == itr ||
91             itr->second.end() == itr->second.find(i_name))
92         {
93             iv_map[i_type][i_name] = i_plugin;
94         }
95         else
96         {
97             throw std::logic_error("Duplicate plugin found");
98         }
99     }
100 
101     /**
102      * @return The plugin function for the target plugin.
103      *
104      * @param i_type The chip type associated with the plugin.
105      * @param i_name The name of the plugin.
106      *
107      * @throw std::out_of_range if the target plugin does not exist.
108      */
get(libhei::ChipType_t i_type,const std::string & i_name) const109     PluginFunction get(libhei::ChipType_t i_type,
110                        const std::string& i_name) const
111     {
112         PluginFunction func;
113 
114         try
115         {
116             func = iv_map.at(i_type).at(i_name);
117         }
118         catch (const std::out_of_range& e)
119         {
120             trace::err("Plugin not defined: i_type=0x%08x i_name=%s", i_type,
121                        i_name.c_str());
122             throw; // caught later downstream
123         }
124 
125         return func;
126     }
127 };
128 
129 // These defines a unique class and a global variable for each plugin. Because
130 // the variables are defined in the global scope, they will be initialized with
131 // the default constructor before execution of the program. This allows all of
132 // the plugins to be registered in the plugin map before execution.
133 
134 #define __PLUGIN_MAKE(X, Y, Z) X##Y##Z
135 
136 #define __PLUGIN_DEFINE(CHIP, NAME, FUNC)                                      \
137     class __PLUGIN_MAKE(Plugin_, CHIP, NAME)                                   \
138     {                                                                          \
139       public:                                                                  \
140         __PLUGIN_MAKE(Plugin_, CHIP, NAME)                                     \
141         ()                                                                     \
142         {                                                                      \
143             PluginMap::getSingleton().add(CHIP, #NAME, &FUNC);                 \
144         }                                                                      \
145     };                                                                         \
146     __PLUGIN_MAKE(Plugin_, CHIP, NAME) __PLUGIN_MAKE(g_Plugin_, CHIP, NAME)
147 
148 #define PLUGIN_DEFINE(CHIP, NAME) __PLUGIN_DEFINE(CHIP, NAME, CHIP::NAME)
149 
150 #define PLUGIN_DEFINE_NS(CHIP, NS, NAME) __PLUGIN_DEFINE(CHIP, NAME, NS::NAME)
151 
152 // Regarding the use of PLUGIN_DEFINE_NS. This is provided for cases where the
153 // same plugin needs to be defined differently for different chips. Example:
154 //
155 //    namespace A
156 //    {
157 //        void foo(...) { /* definition for chip A */ }
158 //    };
159 //
160 //    namespace B
161 //    {
162 //        void foo(...) { /* definition for chip B */ }
163 //    };
164 //
165 //    PLUGIN_DEFINE_NS(CHIP_A, A, foo);
166 //    PLUGIN_DEFINE_NS(CHIP_B, B, foo);
167 //
168 // Also, it is important that the plugin definitions should be declared outside
169 // of the function namespaces (see the example above). This helps find
170 // duplicate plugin definitions at compile time. Otherwise, if you do something
171 // like this:
172 //
173 //    namespace A
174 //    {
175 //        void foo(...) { /* definition for chip A */ }
176 //        PLUGIN_DEFINE_NS(CHIP_A, A, foo);
177 //    };
178 //
179 //    namespace B
180 //    {
181 //        void foo(...) { /* definition again for chip A */ }
182 //        PLUGIN_DEFINE_NS(CHIP_A, B, foo);
183 //    };
184 //
185 // The compiler will not find the duplicate and instead it will be found during
186 // program execution, which will result in an exception.
187 
188 } // namespace analyzer
189