xref: /openbmc/openpower-proc-control/procedures/phal/start_host.cpp (revision 1a9a5a6a144e81d8b61e6f999d8de7cba731ae6e)
1 extern "C"
2 {
3 #include <libpdbg.h>
4 }
5 
6 #include "attributes_info.H"
7 
8 #include "extensions/phal/common_utils.hpp"
9 #include "extensions/phal/phal_error.hpp"
10 #include "util.hpp"
11 
12 #include <fmt/format.h>
13 #include <libekb.H>
14 
15 #include <ext_interface.hpp>
16 #include <phosphor-logging/log.hpp>
17 #include <registration.hpp>
18 
19 namespace openpower
20 {
21 namespace phal
22 {
23 
24 using namespace phosphor::logging;
25 
26 /**
27  *  @brief  Select BOOT SEEPROM and Measurement SEEPROM(PRIMARY/BACKUP) on POWER
28  *          processor position 0/1 depending on boot count before kicking off
29  *          the boot.
30  *
31  *  @return void
32  */
33 void selectBootSeeprom()
34 {
35     struct pdbg_target* procTarget;
36     ATTR_BACKUP_SEEPROM_SELECT_Enum bkpSeePromSelect;
37     ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_Enum bkpMeaSeePromSelect;
38 
39     pdbg_for_each_class_target("proc", procTarget)
40     {
41         if (!isPrimaryProc(procTarget))
42         {
43             continue;
44         }
45 
46         // Choose seeprom side to boot from based on boot count
47         if (getBootCount() > 0)
48         {
49             log<level::INFO>("Setting SBE seeprom side to 0",
50                              entry("SBE_SIDE_SELECT=%d",
51                                    ENUM_ATTR_BACKUP_SEEPROM_SELECT_PRIMARY));
52 
53             bkpSeePromSelect = ENUM_ATTR_BACKUP_SEEPROM_SELECT_PRIMARY;
54             bkpMeaSeePromSelect =
55                 ENUM_ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_PRIMARY;
56         }
57         else
58         {
59             log<level::INFO>("Setting SBE seeprom side to 1",
60                              entry("SBE_SIDE_SELECT=%d",
61                                    ENUM_ATTR_BACKUP_SEEPROM_SELECT_SECONDARY));
62             bkpSeePromSelect = ENUM_ATTR_BACKUP_SEEPROM_SELECT_SECONDARY;
63             bkpMeaSeePromSelect =
64                 ENUM_ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_SECONDARY;
65         }
66 
67         // Set the Attribute as per bootcount policy for boot seeprom
68         if (DT_SET_PROP(ATTR_BACKUP_SEEPROM_SELECT, procTarget,
69                         bkpSeePromSelect))
70         {
71             log<level::ERR>(
72                 "Attribute [ATTR_BACKUP_SEEPROM_SELECT] set failed");
73             throw std::runtime_error(
74                 "Attribute [ATTR_BACKUP_SEEPROM_SELECT] set failed");
75         }
76 
77         // Set the Attribute as per bootcount policy for measurement seeprom
78         if (DT_SET_PROP(ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT, procTarget,
79                         bkpMeaSeePromSelect))
80         {
81             log<level::ERR>(
82                 "Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] set "
83                 "failed");
84             throw std::runtime_error(
85                 "Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] set "
86                 "failed");
87         }
88     }
89 }
90 
91 /**
92  * @brief Read the HW Level from VPD and set CLK NE termination site
93  * Note any failure in this function will result startHost failure.
94  */
95 void setClkNETerminationSite()
96 {
97     // Get Motherborad VINI Recored "HW" keyword
98     constexpr auto objPath =
99         "/xyz/openbmc_project/inventory/system/chassis/motherboard";
100     constexpr auto kwdVpdInf = "com.ibm.ipzvpd.VINI";
101     constexpr auto hwKwd = "HW";
102 
103     auto bus = sdbusplus::bus::new_default();
104 
105     std::string service = util::getService(bus, objPath, kwdVpdInf);
106 
107     auto properties = bus.new_method_call(
108         service.c_str(), objPath, "org.freedesktop.DBus.Properties", "Get");
109     properties.append(kwdVpdInf);
110     properties.append(hwKwd);
111 
112     // Store "HW" Keyword data.
113     std::variant<std::vector<uint8_t>> val;
114     try
115     {
116         auto result = bus.call(properties);
117         result.read(val);
118     }
119     catch (const sdbusplus::exception::exception& e)
120     {
121         log<level::ERR>("Get HW Keyword read from VINI Failed");
122         throw std::runtime_error("Get HW Keyword read from VINI Failed");
123     }
124 
125     auto hwData = std::get<std::vector<uint8_t>>(val);
126 
127     //"HW" Keyword size is 2 as per VPD spec.
128     constexpr auto hwKwdSize = 2;
129     if (hwKwdSize != hwData.size())
130     {
131         log<level::ERR>(
132             fmt::format("Incorrect VINI records HW Keyword data size({})",
133                         hwData.size())
134                 .c_str());
135         throw std::runtime_error("Incorrect VINI records HW Keyword data size");
136     }
137 
138     log<level::DEBUG>(fmt::format("VINI Records HW[0]:{} HW[1]:{}",
139                                   hwData.at(0), hwData.at(1))
140                           .c_str());
141 
142     // VINI Record "HW" keyword's Byte 0's MSB bit indicates
143     // proc or planar type need to choose.
144     constexpr uint8_t SYS_CLK_NE_TERMINATION_ON_MASK = 0x80;
145 
146     ATTR_SYS_CLK_NE_TERMINATION_SITE_Type clockTerm =
147         ENUM_ATTR_SYS_CLK_NE_TERMINATION_SITE_PLANAR;
148 
149     if (SYS_CLK_NE_TERMINATION_ON_MASK & hwData.at(0))
150     {
151         clockTerm = ENUM_ATTR_SYS_CLK_NE_TERMINATION_SITE_PROC;
152     }
153 
154     // update all the processor attributes
155     struct pdbg_target* procTarget;
156     pdbg_for_each_class_target("proc", procTarget)
157     {
158 
159         if (DT_SET_PROP(ATTR_SYS_CLK_NE_TERMINATION_SITE, procTarget,
160                         clockTerm))
161         {
162             log<level::ERR>(
163                 "Attribute ATTR_SYS_CLK_NE_TERMINATION_SITE set failed");
164             throw std::runtime_error(
165                 "Attribute ATTR_SYS_CLK_NE_TERMINATION_SITE set failed");
166         }
167     }
168 }
169 
170 /**
171  * @brief Starts the self boot engine on POWER processor position 0
172  *        to kick off a boot.
173  * @return void
174  */
175 void startHost(enum ipl_type iplType = IPL_TYPE_NORMAL)
176 {
177     try
178     {
179         phal_init();
180         ipl_set_type(iplType);
181     }
182     catch (const std::exception& ex)
183     {
184         log<level::ERR>("Exception raised during init PHAL",
185                         entry("EXCEPTION=%s", ex.what()));
186         openpower::pel::detail::processBootError(false);
187         throw std::runtime_error("PHAL initialization failed");
188     }
189 
190     // To clear trace if success
191     openpower::pel::detail::processBootError(true);
192 
193     setClkNETerminationSite();
194 
195     // callback method will be called upon failure which will create the PEL
196     int rc = ipl_run_major(0);
197     if (rc > 0)
198     {
199         log<level::ERR>("step 0 failed to start the host");
200         throw std::runtime_error("Failed to execute host start boot step");
201     }
202 }
203 
204 /**
205  * @brief Starts the reboot with type memory preserving reboot.
206  * @return void
207  */
208 void startHostMpReboot()
209 {
210     // set ipl type as mpipl
211     startHost(IPL_TYPE_MPIPL);
212 }
213 
214 /**
215  * @brief Starts the normal boot type.
216  * @return void
217  */
218 void startHostNormal()
219 {
220     // Run select seeprom before poweron
221     try
222     {
223         selectBootSeeprom();
224 
225         // To clear trace as it is success
226         openpower::pel::detail::processBootError(true);
227     }
228     catch (const std::exception& ex)
229     {
230         // create PEL in failure
231         openpower::pel::detail::processBootError(false);
232         log<level::ERR>("SEEPROM selection failed", entry("ERR=%s", ex.what()));
233         throw ex;
234     }
235 
236     startHost();
237 }
238 
239 REGISTER_PROCEDURE("startHost", startHostNormal)
240 REGISTER_PROCEDURE("startHostMpReboot", startHostMpReboot)
241 
242 } // namespace phal
243 } // namespace openpower
244