xref: /openbmc/openpower-hw-diags/util/pdbg.cpp (revision c18ba8fb)
1 #include <assert.h>
2 #include <config.h>
3 
4 #include <hei_main.hpp>
5 #include <util/pdbg.hpp>
6 #include <util/trace.hpp>
7 
8 #ifdef CONFIG_PHAL_API
9 #include <attributes_info.H>
10 #endif
11 
12 namespace util
13 {
14 
15 namespace pdbg
16 {
17 
18 //------------------------------------------------------------------------------
19 
20 pdbg_target* getTrgt(const libhei::Chip& i_chip)
21 {
22     return (pdbg_target*)i_chip.getChip();
23 }
24 
25 //------------------------------------------------------------------------------
26 
27 pdbg_target* getTrgt(const std::string& i_path)
28 {
29     return pdbg_target_from_path(nullptr, i_path.c_str());
30 }
31 
32 //------------------------------------------------------------------------------
33 
34 const char* getPath(pdbg_target* i_trgt)
35 {
36     return pdbg_target_path(i_trgt);
37 }
38 
39 const char* getPath(const libhei::Chip& i_chip)
40 {
41     return getPath(getTrgt(i_chip));
42 }
43 
44 //------------------------------------------------------------------------------
45 
46 uint32_t getChipPos(pdbg_target* i_trgt)
47 {
48     uint32_t attr = 0;
49     pdbg_target_get_attribute(i_trgt, "ATTR_FAPI_POS", 4, 1, &attr);
50     return attr;
51 }
52 
53 uint32_t getChipPos(const libhei::Chip& i_chip)
54 {
55     return getChipPos(getTrgt(i_chip));
56 }
57 
58 //------------------------------------------------------------------------------
59 
60 uint8_t getTrgtType(pdbg_target* i_trgt)
61 {
62     uint8_t attr = 0;
63     pdbg_target_get_attribute(i_trgt, "ATTR_TYPE", 1, 1, &attr);
64     return attr;
65 }
66 
67 uint8_t getTrgtType(const libhei::Chip& i_chip)
68 {
69     return getTrgtType(getTrgt(i_chip));
70 }
71 
72 //------------------------------------------------------------------------------
73 
74 pdbg_target* getPibTrgt(pdbg_target* i_procTrgt)
75 {
76     // The input target must be a processor.
77     assert(TYPE_PROC == getTrgtType(i_procTrgt));
78 
79     // Get the pib path.
80     char path[16];
81     sprintf(path, "/proc%d/pib", pdbg_target_index(i_procTrgt));
82 
83     // Return the pib target.
84     pdbg_target* pibTrgt = pdbg_target_from_path(nullptr, path);
85     assert(nullptr != pibTrgt);
86 
87     return pibTrgt;
88 }
89 
90 //------------------------------------------------------------------------------
91 
92 pdbg_target* getFsiTrgt(pdbg_target* i_procTrgt)
93 {
94     // The input target must be a processor.
95     assert(TYPE_PROC == getTrgtType(i_procTrgt));
96 
97     // Get the fsi path.
98     char path[16];
99     sprintf(path, "/proc%d/fsi", pdbg_target_index(i_procTrgt));
100 
101     // Return the fsi target.
102     pdbg_target* fsiTrgt = pdbg_target_from_path(nullptr, path);
103     assert(nullptr != fsiTrgt);
104 
105     return fsiTrgt;
106 }
107 
108 //------------------------------------------------------------------------------
109 
110 int getScom(pdbg_target* i_trgt, uint64_t i_addr, uint64_t& o_val)
111 {
112     // Only processor targets are supported.
113     // TODO: Will need to add OCMB support later.
114     assert(TYPE_PROC == getTrgtType(i_trgt));
115 
116     auto pibTrgt = util::pdbg::getPibTrgt(i_trgt);
117 
118     int rc = pib_read(pibTrgt, i_addr, &o_val);
119 
120     if (0 != rc)
121     {
122         trace::err("pib_read failure: target=%s addr=0x%0" PRIx64,
123                    util::pdbg::getPath(pibTrgt), i_addr);
124     }
125 
126     return rc;
127 }
128 
129 //------------------------------------------------------------------------------
130 
131 int getCfam(pdbg_target* i_trgt, uint32_t i_addr, uint32_t& o_val)
132 {
133     // Only processor targets are supported.
134     assert(TYPE_PROC == getTrgtType(i_trgt));
135 
136     auto fsiTrgt = util::pdbg::getFsiTrgt(i_trgt);
137 
138     int rc = fsi_read(fsiTrgt, i_addr, &o_val);
139 
140     if (0 != rc)
141     {
142         trace::err("fsi_read failure: target=%s addr=0x%08x",
143                    util::pdbg::getPath(fsiTrgt), i_addr);
144     }
145 
146     return rc;
147 }
148 
149 //------------------------------------------------------------------------------
150 
151 // IMPORTANT:
152 // The ATTR_CHIP_ID attribute will be synced from Hostboot to the BMC at some
153 // point during the IPL. It is possible that this information is needed before
154 // the sync occurs, in which case the value will return 0.
155 uint32_t __getChipId(pdbg_target* i_trgt)
156 {
157     uint32_t attr = 0;
158     pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_ID", 4, 1, &attr);
159     return attr;
160 }
161 
162 // IMPORTANT:
163 // The ATTR_EC attribute will be synced from Hostboot to the BMC at some point
164 // during the IPL. It is possible that this information is needed before the
165 // sync occurs, in which case the value will return 0.
166 uint8_t __getChipEc(pdbg_target* i_trgt)
167 {
168     uint8_t attr = 0;
169     pdbg_target_get_attribute(i_trgt, "ATTR_EC", 1, 1, &attr);
170     return attr;
171 }
172 
173 uint32_t __getChipIdEc(pdbg_target* i_trgt)
174 {
175     auto chipId = __getChipId(i_trgt);
176     auto chipEc = __getChipEc(i_trgt);
177 
178     if (((0 == chipId) || (0 == chipEc)) && (TYPE_PROC == getTrgtType(i_trgt)))
179     {
180         // There is a special case where the model/level attributes have not
181         // been initialized in the devtree. This is possible on the epoch IPL
182         // where an attention occurs before Hostboot is able to update the
183         // devtree information on the BMC. It may is still possible to get this
184         // information from chips with CFAM access (i.e. a processor) via the
185         // CFAM chip ID register.
186 
187         uint32_t val = 0;
188         if (0 == getCfam(i_trgt, 0x100a, val))
189         {
190             chipId = ((val & 0x0F0FF000) >> 12);
191             chipEc = ((val & 0xF0000000) >> 24) | ((val & 0x00F00000) >> 20);
192         }
193     }
194 
195     return ((chipId & 0xffff) << 16) | (chipEc & 0xff);
196 }
197 
198 void __addChip(std::vector<libhei::Chip>& o_chips, pdbg_target* i_trgt,
199                libhei::ChipType_t i_type)
200 {
201     // Trace each chip for debug. It is important to show the type just in case
202     // the model/EC does not exist. See note below.
203     trace::inf("Chip found: type=0x%08" PRIx32 " chip=%s", i_type,
204                getPath(i_trgt));
205 
206     if (0 == i_type)
207     {
208         // This is a special case. See the details in __getChipIdEC(). There is
209         // nothing more we can do with this chip since we don't know what it is.
210         // So ignore the chip for now.
211     }
212     else
213     {
214         o_chips.emplace_back(i_trgt, i_type);
215     }
216 }
217 
218 void getActiveChips(std::vector<libhei::Chip>& o_chips)
219 {
220     o_chips.clear();
221 
222     // Iterate each processor.
223     pdbg_target* procTrgt;
224     pdbg_for_each_class_target("proc", procTrgt)
225     {
226         // We cannot use the proc target to determine if the chip is active.
227         // There is some design limitation in pdbg that requires the proc
228         // targets to always be active. Instead, we must get the associated pib
229         // target and check if it is active.
230 
231         // Active processors only.
232         if (PDBG_TARGET_ENABLED != pdbg_target_probe(getPibTrgt(procTrgt)))
233             continue;
234 
235         // Add the processor to the list.
236         __addChip(o_chips, procTrgt, __getChipIdEc(procTrgt));
237 
238         // Iterate the connected OCMBs, if they exist.
239         pdbg_target* ocmbTrgt;
240         pdbg_for_each_target("ocmb", procTrgt, ocmbTrgt)
241         {
242             // Active OCMBs only.
243             if (PDBG_TARGET_ENABLED != pdbg_target_probe(ocmbTrgt))
244                 continue;
245 
246             // Add the OCMB to the list.
247             __addChip(o_chips, ocmbTrgt, __getChipIdEc(ocmbTrgt));
248         }
249     }
250 }
251 
252 //------------------------------------------------------------------------------
253 
254 pdbg_target* getPrimaryProcessor()
255 {
256     // TODO: For at least P10, the primary processor (the one connected directly
257     //       to the BMC), will always be PROC 0. We will need to update this
258     //       later if we ever support an alternate primary processor.
259     return getTrgt("/proc0");
260 }
261 
262 //------------------------------------------------------------------------------
263 
264 bool queryHardwareAnalysisSupported()
265 {
266     // Hardware analysis is only supported on P10 systems and up.
267     return (PDBG_PROC_P9 < pdbg_get_proc());
268 }
269 
270 //------------------------------------------------------------------------------
271 
272 std::string getLocationCode(pdbg_target* trgt)
273 {
274     if (nullptr == trgt)
275     {
276         // Either the path is wrong or the attribute doesn't exist.
277         return std::string{};
278     }
279 
280 #ifdef CONFIG_PHAL_API
281 
282     ATTR_LOCATION_CODE_Type val;
283     if (DT_GET_PROP(ATTR_LOCATION_CODE, trgt, val))
284     {
285         // Get the immediate parent in the devtree path and try again.
286         return getLocationCode(pdbg_target_parent(nullptr, trgt));
287     }
288 
289     // Attribute found.
290     return std::string{val};
291 
292 #else
293 
294     return std::string{getPath(trgt)};
295 
296 #endif
297 }
298 
299 //------------------------------------------------------------------------------
300 
301 std::string getPhysDevPath(pdbg_target* trgt)
302 {
303     if (nullptr == trgt)
304     {
305         // Either the path is wrong or the attribute doesn't exist.
306         return std::string{};
307     }
308 
309 #ifdef CONFIG_PHAL_API
310 
311     ATTR_PHYS_DEV_PATH_Type val;
312     if (DT_GET_PROP(ATTR_PHYS_DEV_PATH, trgt, val))
313     {
314         // Get the immediate parent in the devtree path and try again.
315         return getPhysDevPath(pdbg_target_parent(nullptr, trgt));
316     }
317 
318     // Attribute found.
319     return std::string{val};
320 
321 #else
322 
323     return std::string{getPath(trgt)};
324 
325 #endif
326 }
327 
328 //------------------------------------------------------------------------------
329 
330 std::vector<uint8_t> getPhysBinPath(pdbg_target* target)
331 {
332     std::vector<uint8_t> binPath;
333 
334     if (nullptr != target)
335     {
336 #ifdef CONFIG_PHAL_API
337 
338         ATTR_PHYS_BIN_PATH_Type value;
339         if (DT_GET_PROP(ATTR_PHYS_BIN_PATH, target, value))
340         {
341             // The attrirbute for this target does not exist. Get the immediate
342             // parent in the devtree path and try again. Note that if there is
343             // no parent target, nullptr will be returned and that will be
344             // checked above.
345             return getPhysBinPath(pdbg_target_parent(nullptr, target));
346         }
347 
348         // Attribute was found. Copy the attribute array to the returned
349         // vector. Note that the reason we return the vector instead of just
350         // returning the array is because the array type and details only
351         // exists in this specific configuration.
352         binPath.insert(binPath.end(), value, value + sizeof(value));
353 
354 #endif
355     }
356 
357     return binPath;
358 }
359 
360 //------------------------------------------------------------------------------
361 
362 } // namespace pdbg
363 
364 } // namespace util
365