1 #include <libpdbg.h>
2
3 #include <attn/attn_common.hpp>
4 #include <attn/attn_handler.hpp>
5 #include <attn/attn_logging.hpp>
6 #include <sdbusplus/bus.hpp>
7 #include <util/pdbg.hpp>
8 #include <util/trace.hpp>
9
10 #include <iomanip>
11 #include <iostream>
12 #include <map>
13
14 namespace attn
15 {
16
17 /** @brief Traces some regs for hostboot */
addHbStatusRegs()18 void addHbStatusRegs()
19 {
20 // Only do this for P10 systems
21 if (util::pdbg::queryHardwareAnalysisSupported())
22 {
23 // We only need this for PRIMARY processor
24 pdbg_target* pibTarget = pdbg_target_from_path(nullptr, "/proc0/pib");
25 pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, "/proc0/fsi");
26
27 uint32_t l_cfamData = 0xFFFFFFFF;
28 uint64_t l_scomData1 = 0xFFFFFFFFFFFFFFFFull;
29 uint64_t l_scomData2 = 0xFFFFFFFFFFFFFFFFull;
30 uint32_t l_cfamAddr = 0x283C;
31 uint64_t l_scomAddr1 = 0x4602F489;
32 uint64_t l_scomAddr2 = 0x4602F487;
33
34 if ((nullptr != fsiTarget) && (nullptr != pibTarget))
35 {
36 // get first debug reg (CFAM)
37 if (RC_SUCCESS != fsi_read(fsiTarget, l_cfamAddr, &l_cfamData))
38 {
39 trace::err("cfam read error: 0x%08x", l_cfamAddr);
40 l_cfamData = 0xFFFFFFFF;
41 }
42
43 // Get SCOM regs next (just 2 of them)
44 if (RC_SUCCESS != pib_read(pibTarget, l_scomAddr1, &l_scomData1))
45 {
46 trace::err("scom read error: 0x%016" PRIx64 "", l_scomAddr1);
47 l_scomData1 = 0xFFFFFFFFFFFFFFFFull;
48 }
49
50 if (RC_SUCCESS != pib_read(pibTarget, l_scomAddr2, &l_scomData2))
51 {
52 trace::err("scom read error: 0x%016" PRIx64 "", l_scomAddr2);
53 l_scomData2 = 0xFFFFFFFFFFFFFFFFull;
54 }
55 }
56
57 // Trace out the results here of all 3 regs
58 // (Format should resemble FSP: HostBoot Reg:0000283C Data:AA801504
59 // 00000000 Proc:00050001 )
60 trace::inf("HostBoot Reg:%08x Data:%08x Proc:00000000", l_cfamAddr,
61 l_cfamData);
62 trace::inf("HostBoot Reg:%08" PRIx64 " Data:%016" PRIx64
63 " Proc:00000000",
64 l_scomAddr1, l_scomData1);
65 trace::inf("HostBoot Reg:%08" PRIx64 " Data:%016" PRIx64
66 " Proc:00000000",
67 l_scomAddr2, l_scomData2);
68 }
69
70 return;
71
72 } // end addHbStatusRegs
73
74 /** @brief Capture some scratch registers for PRD */
addPrdScratchRegs(std::vector<util::FFDCFile> & o_files)75 void addPrdScratchRegs(std::vector<util::FFDCFile>& o_files)
76 {
77 // Get primary processor FSI target for CFAM reads
78 pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, "/proc0/fsi");
79
80 if (nullptr == fsiTarget)
81 {
82 trace::err("error getting scratch register target");
83 }
84 else
85 {
86 uint32_t chipId = 0;
87 uint32_t signatureId = 0;
88
89 // get scratch register 9 (CFAM)
90 if (RC_SUCCESS != fsi_read(fsiTarget, 0x2980, &chipId))
91 {
92 trace::err("error reading scratch register 9");
93 chipId = 0;
94 }
95
96 // get scratch register 10 (CFAM)
97 if (RC_SUCCESS != fsi_read(fsiTarget, 0x2981, &signatureId))
98 {
99 trace::err("error reading scratch register 10");
100 signatureId = 0;
101 }
102
103 // Add data to traces and create user data section
104 if (0 != chipId || 0 != signatureId)
105 {
106 // trace scratch register data
107 trace::inf("PRD scratch Proc0, Chip ID: %08x, Signature ID: %08x",
108 chipId, signatureId);
109
110 // create ffdc data for user data section
111 try
112 {
113 util::FFDCFile file{util::FFDCFormat::Text};
114 int fd = file.getFileDescriptor();
115 char buffer[150];
116 int len = sprintf(buffer,
117 "Scratch Register Error Signature\n"
118 "Processor : 0\n"
119 "Chip ID : %08x\n"
120 "Signature ID : %08x\n",
121 chipId, signatureId);
122 if (write(fd, buffer, len) < 0)
123 {
124 trace::err("error writing scratch register user data");
125 }
126 else
127 {
128 o_files.push_back(std::move(file));
129 }
130 }
131 catch (const std::exception& e)
132 {
133 trace::err(
134 "exception when creating scratch register user data");
135 trace::inf(e.what());
136 }
137 }
138 }
139
140 return;
141 }
142
143 /** @brief Check for recoverable errors present */
recoverableErrors()144 bool recoverableErrors()
145 {
146 bool recoverableErrors = false; // assume no recoverable attentions
147
148 pdbg_target* target;
149 pdbg_for_each_class_target("proc", target)
150 {
151 if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
152 {
153 auto proc = pdbg_target_index(target); // get processor number
154
155 // Use PIB target to determine if a processor is enabled
156 char path[16];
157 sprintf(path, "/proc%d/pib", proc);
158 pdbg_target* pibTarget = pdbg_target_from_path(nullptr, path);
159
160 // sanity check
161 if (nullptr == pibTarget)
162 {
163 trace::inf("pib path or target not found");
164 continue;
165 }
166
167 // check if pib target is enabled - indicates proc is enabled
168 if (PDBG_TARGET_ENABLED == pdbg_target_probe(pibTarget))
169 {
170 // The processor FSI target is required for CFAM read
171 sprintf(path, "/proc%d/fsi", proc);
172 pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path);
173
174 // sanity check
175 if (nullptr == fsiTarget)
176 {
177 trace::inf("fsi path or target not found");
178 continue;
179 }
180
181 uint32_t isr_val = 0xffffffff; // invalid isr value
182
183 // get active attentions on processor
184 if (RC_SUCCESS != fsi_read(fsiTarget, 0x1007, &isr_val))
185 {
186 // log cfam read error
187 trace::err("cfam read 0x1007 FAILED");
188 eventAttentionFail(
189 (int)AttnSection::attnHandler | ATTN_PDBG_CFAM);
190 }
191 // check for invalid/stale value
192 else if (0xffffffff == isr_val)
193 {
194 trace::err("cfam read 0x1007 INVALID");
195 continue;
196 }
197 // check recoverable error status bit
198 else if (0 != (isr_val & RECOVERABLE_ATTN))
199 {
200 recoverableErrors = true;
201 break;
202 }
203 } // fsi target enabled
204 } // pib target enabled
205 } // next processor
206
207 return recoverableErrors;
208 }
209
210 /** @brief timesec less-than-equal-to compare */
operator <=(const timespec & lhs,const timespec & rhs)211 bool operator<=(const timespec& lhs, const timespec& rhs)
212 {
213 if (lhs.tv_sec == rhs.tv_sec)
214 return lhs.tv_nsec <= rhs.tv_nsec;
215 else
216 return lhs.tv_sec <= rhs.tv_sec;
217 }
218
219 /** @brief sleep for n-seconds */
sleepSeconds(const unsigned int seconds)220 void sleepSeconds(const unsigned int seconds)
221 {
222 auto count = seconds;
223 struct timespec requested, remaining;
224
225 while (0 < count)
226 {
227 requested.tv_sec = 1;
228 requested.tv_nsec = 0;
229 remaining = requested;
230
231 while (-1 == nanosleep(&requested, &remaining))
232 {
233 // if not changing or implausible then abort
234 if (requested <= remaining)
235 {
236 break;
237 }
238
239 // back to sleep
240 requested = remaining;
241 }
242 count--;
243 }
244 }
245
246 } // namespace attn
247