xref: /openbmc/openpower-hw-diags/util/pdbg.cpp (revision 35171d90)
1 #include <assert.h>
2 
3 #include <hei_main.hpp>
4 #include <util/pdbg.hpp>
5 #include <util/trace.hpp>
6 
7 namespace util
8 {
9 
10 namespace pdbg
11 {
12 
13 //------------------------------------------------------------------------------
14 
15 pdbg_target* getTrgt(const libhei::Chip& i_chip)
16 {
17     return (pdbg_target*)i_chip.getChip();
18 }
19 
20 //------------------------------------------------------------------------------
21 
22 const char* getPath(pdbg_target* i_trgt)
23 {
24     return pdbg_target_path(i_trgt);
25 }
26 
27 const char* getPath(const libhei::Chip& i_chip)
28 {
29     return getPath(getTrgt(i_chip));
30 }
31 
32 //------------------------------------------------------------------------------
33 
34 uint32_t getChipPos(pdbg_target* i_trgt)
35 {
36     uint32_t attr = 0;
37     pdbg_target_get_attribute(i_trgt, "ATTR_FAPI_POS", 4, 1, &attr);
38     return attr;
39 }
40 
41 uint32_t getChipPos(const libhei::Chip& i_chip)
42 {
43     return getChipPos(getTrgt(i_chip));
44 }
45 
46 //------------------------------------------------------------------------------
47 
48 uint8_t getTrgtType(pdbg_target* i_trgt)
49 {
50     uint8_t attr = 0;
51     pdbg_target_get_attribute(i_trgt, "ATTR_TYPE", 1, 1, &attr);
52     return attr;
53 }
54 
55 uint8_t getTrgtType(const libhei::Chip& i_chip)
56 {
57     return getTrgtType(getTrgt(i_chip));
58 }
59 
60 //------------------------------------------------------------------------------
61 
62 pdbg_target* getPibTrgt(pdbg_target* i_procTrgt)
63 {
64     // The input target must be a processor.
65     assert(TYPE_PROC == getTrgtType(i_procTrgt));
66 
67     // Get the pib path.
68     char path[16];
69     sprintf(path, "/proc%d/pib", pdbg_target_index(i_procTrgt));
70 
71     // Return the pib target.
72     pdbg_target* pibTrgt = pdbg_target_from_path(nullptr, path);
73     assert(nullptr != pibTrgt);
74 
75     return pibTrgt;
76 }
77 
78 //------------------------------------------------------------------------------
79 
80 pdbg_target* getFsiTrgt(pdbg_target* i_procTrgt)
81 {
82     // The input target must be a processor.
83     assert(TYPE_PROC == getTrgtType(i_procTrgt));
84 
85     // Get the fsi path.
86     char path[16];
87     sprintf(path, "/proc%d/fsi", pdbg_target_index(i_procTrgt));
88 
89     // Return the fsi target.
90     pdbg_target* fsiTrgt = pdbg_target_from_path(nullptr, path);
91     assert(nullptr != fsiTrgt);
92 
93     return fsiTrgt;
94 }
95 
96 //------------------------------------------------------------------------------
97 
98 int getCfam(pdbg_target* i_trgt, uint32_t i_addr, uint32_t& o_val)
99 {
100     // Only processor targets are supported.
101     assert(TYPE_PROC == getTrgtType(i_trgt));
102 
103     auto fsiTrgt = util::pdbg::getFsiTrgt(i_trgt);
104 
105     int rc = fsi_read(fsiTrgt, i_addr, &o_val);
106 
107     if (0 != rc)
108     {
109         trace::err("fsi_read failure: trgt=%s addr=0x%08x",
110                    util::pdbg::getPath(fsiTrgt), i_addr);
111     }
112 
113     return rc;
114 }
115 
116 //------------------------------------------------------------------------------
117 
118 // IMPORTANT:
119 // The ATTR_CHIP_ID attribute will be synced from Hostboot to the BMC at some
120 // point during the IPL. It is possible that this information is needed before
121 // the sync occurs, in which case the value will return 0.
122 uint32_t __getChipId(pdbg_target* i_trgt)
123 {
124     uint32_t attr = 0;
125     pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_ID", 4, 1, &attr);
126     return attr;
127 }
128 
129 // IMPORTANT:
130 // The ATTR_EC attribute will be synced from Hostboot to the BMC at some point
131 // during the IPL. It is possible that this information is needed before the
132 // sync occurs, in which case the value will return 0.
133 uint8_t __getChipEc(pdbg_target* i_trgt)
134 {
135     uint8_t attr = 0;
136     pdbg_target_get_attribute(i_trgt, "ATTR_EC", 1, 1, &attr);
137     return attr;
138 }
139 
140 uint32_t __getChipIdEc(pdbg_target* i_trgt)
141 {
142     auto chipId = __getChipId(i_trgt);
143     auto chipEc = __getChipEc(i_trgt);
144 
145     if (((0 == chipId) || (0 == chipEc)) && (TYPE_PROC == getTrgtType(i_trgt)))
146     {
147         // There is a special case where the model/level attributes have not
148         // been initialized in the devtree. This is possible on the epoch IPL
149         // where an attention occurs before Hostboot is able to update the
150         // devtree information on the BMC. It may is still possible to get this
151         // information from chips with CFAM access (i.e. a processor) via the
152         // CFAM chip ID register.
153 
154         uint32_t val = 0;
155         if (0 == getCfam(i_trgt, 0x100a, val))
156         {
157             chipId = ((val & 0x0F0FF000) >> 12);
158             chipEc = ((val & 0xF0000000) >> 24) | ((val & 0x00F00000) >> 20);
159         }
160     }
161 
162     return ((chipId & 0xffff) << 16) | (chipEc & 0xff);
163 }
164 
165 void __addChip(std::vector<libhei::Chip>& o_chips, pdbg_target* i_trgt,
166                libhei::ChipType_t i_type)
167 {
168     // Trace each chip for debug. It is important to show the type just in case
169     // the model/EC does not exist. See note below.
170     trace::inf("Chip found: type=0x%08" PRIx32 " chip=%s", i_type,
171                getPath(i_trgt));
172 
173     if (0 == i_type)
174     {
175         // This is a special case. See the details in __getChipIdEC(). There is
176         // nothing more we can do with this chip since we don't know what it is.
177         // So ignore the chip for now.
178     }
179     else
180     {
181         o_chips.emplace_back(i_trgt, i_type);
182     }
183 }
184 
185 void getActiveChips(std::vector<libhei::Chip>& o_chips)
186 {
187     o_chips.clear();
188 
189     // Iterate each processor.
190     pdbg_target* procTrgt;
191     pdbg_for_each_class_target("proc", procTrgt)
192     {
193         // We cannot use the proc target to determine if the chip is active.
194         // There is some design limitation in pdbg that requires the proc
195         // targets to always be active. Instead, we must get the associated pib
196         // target and check if it is active.
197 
198         // Active processors only.
199         if (PDBG_TARGET_ENABLED != pdbg_target_probe(getPibTrgt(procTrgt)))
200             continue;
201 
202         // Add the processor to the list.
203         __addChip(o_chips, procTrgt, __getChipIdEc(procTrgt));
204 
205         // Iterate the connected OCMBs, if they exist.
206         pdbg_target* ocmbTrgt;
207         pdbg_for_each_target("ocmb", procTrgt, ocmbTrgt)
208         {
209             // Active OCMBs only.
210             if (PDBG_TARGET_ENABLED != pdbg_target_probe(ocmbTrgt))
211                 continue;
212 
213             // Add the OCMB to the list.
214             __addChip(o_chips, ocmbTrgt, __getChipIdEc(ocmbTrgt));
215         }
216     }
217 }
218 
219 //------------------------------------------------------------------------------
220 
221 bool queryHardwareAnalysisSupported()
222 {
223     // Hardware analysis is only supported on P10 systems and up.
224     return (PDBG_PROC_P9 < pdbg_get_proc());
225 }
226 
227 //------------------------------------------------------------------------------
228 
229 } // namespace pdbg
230 
231 } // namespace util
232