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