1bcf65a8bSBen Tyner #include <libpdbg.h>
2bcf65a8bSBen Tyner
3bcf65a8bSBen Tyner #include <attn/attn_common.hpp>
4135793a8SBen Tyner #include <attn/attn_handler.hpp>
5b8335568SBen Tyner #include <attn/attn_logging.hpp>
6bcf65a8bSBen Tyner #include <sdbusplus/bus.hpp>
7b8335568SBen Tyner #include <util/pdbg.hpp>
8bfa831a8Saustinfcui #include <util/trace.hpp>
9bcf65a8bSBen Tyner
10b8335568SBen Tyner #include <iomanip>
11b8335568SBen Tyner #include <iostream>
12bcf65a8bSBen Tyner #include <map>
13bcf65a8bSBen Tyner
14bcf65a8bSBen Tyner namespace attn
15bcf65a8bSBen Tyner {
16bcf65a8bSBen Tyner
17b8335568SBen Tyner /** @brief Traces some regs for hostboot */
addHbStatusRegs()18b8335568SBen Tyner void addHbStatusRegs()
19b8335568SBen Tyner {
20b8335568SBen Tyner // Only do this for P10 systems
21b8335568SBen Tyner if (util::pdbg::queryHardwareAnalysisSupported())
22b8335568SBen Tyner {
23b8335568SBen Tyner // We only need this for PRIMARY processor
24b8335568SBen Tyner pdbg_target* pibTarget = pdbg_target_from_path(nullptr, "/proc0/pib");
25b8335568SBen Tyner pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, "/proc0/fsi");
26b8335568SBen Tyner
27b8335568SBen Tyner uint32_t l_cfamData = 0xFFFFFFFF;
28b8335568SBen Tyner uint64_t l_scomData1 = 0xFFFFFFFFFFFFFFFFull;
29b8335568SBen Tyner uint64_t l_scomData2 = 0xFFFFFFFFFFFFFFFFull;
30b8335568SBen Tyner uint32_t l_cfamAddr = 0x283C;
31b8335568SBen Tyner uint64_t l_scomAddr1 = 0x4602F489;
32b8335568SBen Tyner uint64_t l_scomAddr2 = 0x4602F487;
33b8335568SBen Tyner
34b8335568SBen Tyner if ((nullptr != fsiTarget) && (nullptr != pibTarget))
35b8335568SBen Tyner {
36b8335568SBen Tyner // get first debug reg (CFAM)
37b8335568SBen Tyner if (RC_SUCCESS != fsi_read(fsiTarget, l_cfamAddr, &l_cfamData))
38b8335568SBen Tyner {
39bfa831a8Saustinfcui trace::err("cfam read error: 0x%08x", l_cfamAddr);
40b8335568SBen Tyner l_cfamData = 0xFFFFFFFF;
41b8335568SBen Tyner }
42b8335568SBen Tyner
43b8335568SBen Tyner // Get SCOM regs next (just 2 of them)
44b8335568SBen Tyner if (RC_SUCCESS != pib_read(pibTarget, l_scomAddr1, &l_scomData1))
45b8335568SBen Tyner {
46bfa831a8Saustinfcui trace::err("scom read error: 0x%016" PRIx64 "", l_scomAddr1);
47b8335568SBen Tyner l_scomData1 = 0xFFFFFFFFFFFFFFFFull;
48b8335568SBen Tyner }
49b8335568SBen Tyner
50b8335568SBen Tyner if (RC_SUCCESS != pib_read(pibTarget, l_scomAddr2, &l_scomData2))
51b8335568SBen Tyner {
52bfa831a8Saustinfcui trace::err("scom read error: 0x%016" PRIx64 "", l_scomAddr2);
53b8335568SBen Tyner l_scomData2 = 0xFFFFFFFFFFFFFFFFull;
54b8335568SBen Tyner }
55b8335568SBen Tyner }
56b8335568SBen Tyner
57b8335568SBen Tyner // Trace out the results here of all 3 regs
58b8335568SBen Tyner // (Format should resemble FSP: HostBoot Reg:0000283C Data:AA801504
59b8335568SBen Tyner // 00000000 Proc:00050001 )
60bfa831a8Saustinfcui trace::inf("HostBoot Reg:%08x Data:%08x Proc:00000000", l_cfamAddr,
61bfa831a8Saustinfcui l_cfamData);
62ebddb421SZane Shelley trace::inf("HostBoot Reg:%08" PRIx64 " Data:%016" PRIx64
63ebddb421SZane Shelley " Proc:00000000",
64bfa831a8Saustinfcui l_scomAddr1, l_scomData1);
65ebddb421SZane Shelley trace::inf("HostBoot Reg:%08" PRIx64 " Data:%016" PRIx64
66ebddb421SZane Shelley " Proc:00000000",
67bfa831a8Saustinfcui l_scomAddr2, l_scomData2);
68b8335568SBen Tyner }
69b8335568SBen Tyner
70b8335568SBen Tyner return;
71b8335568SBen Tyner
72b8335568SBen Tyner } // end addHbStatusRegs
73b8335568SBen Tyner
7421cc6270SBen Tyner /** @brief Capture some scratch registers for PRD */
addPrdScratchRegs(std::vector<util::FFDCFile> & o_files)7521cc6270SBen Tyner void addPrdScratchRegs(std::vector<util::FFDCFile>& o_files)
7621cc6270SBen Tyner {
7721cc6270SBen Tyner // Get primary processor FSI target for CFAM reads
7821cc6270SBen Tyner pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, "/proc0/fsi");
7921cc6270SBen Tyner
8021cc6270SBen Tyner if (nullptr == fsiTarget)
8121cc6270SBen Tyner {
8221cc6270SBen Tyner trace::err("error getting scratch register target");
8321cc6270SBen Tyner }
8421cc6270SBen Tyner else
8521cc6270SBen Tyner {
8621cc6270SBen Tyner uint32_t chipId = 0;
8721cc6270SBen Tyner uint32_t signatureId = 0;
8821cc6270SBen Tyner
8921cc6270SBen Tyner // get scratch register 9 (CFAM)
9021cc6270SBen Tyner if (RC_SUCCESS != fsi_read(fsiTarget, 0x2980, &chipId))
9121cc6270SBen Tyner {
9221cc6270SBen Tyner trace::err("error reading scratch register 9");
9321cc6270SBen Tyner chipId = 0;
9421cc6270SBen Tyner }
9521cc6270SBen Tyner
9621cc6270SBen Tyner // get scratch register 10 (CFAM)
9721cc6270SBen Tyner if (RC_SUCCESS != fsi_read(fsiTarget, 0x2981, &signatureId))
9821cc6270SBen Tyner {
9921cc6270SBen Tyner trace::err("error reading scratch register 10");
10021cc6270SBen Tyner signatureId = 0;
10121cc6270SBen Tyner }
10221cc6270SBen Tyner
10321cc6270SBen Tyner // Add data to traces and create user data section
10421cc6270SBen Tyner if (0 != chipId || 0 != signatureId)
10521cc6270SBen Tyner {
10621cc6270SBen Tyner // trace scratch register data
10721cc6270SBen Tyner trace::inf("PRD scratch Proc0, Chip ID: %08x, Signature ID: %08x",
10821cc6270SBen Tyner chipId, signatureId);
10921cc6270SBen Tyner
11021cc6270SBen Tyner // create ffdc data for user data section
11121cc6270SBen Tyner try
11221cc6270SBen Tyner {
11321cc6270SBen Tyner util::FFDCFile file{util::FFDCFormat::Text};
11421cc6270SBen Tyner int fd = file.getFileDescriptor();
11521cc6270SBen Tyner char buffer[150];
11621cc6270SBen Tyner int len = sprintf(buffer,
11721cc6270SBen Tyner "Scratch Register Error Signature\n"
11821cc6270SBen Tyner "Processor : 0\n"
11921cc6270SBen Tyner "Chip ID : %08x\n"
12021cc6270SBen Tyner "Signature ID : %08x\n",
12121cc6270SBen Tyner chipId, signatureId);
12221cc6270SBen Tyner if (write(fd, buffer, len) < 0)
12321cc6270SBen Tyner {
12421cc6270SBen Tyner trace::err("error writing scratch register user data");
12521cc6270SBen Tyner }
12621cc6270SBen Tyner else
12721cc6270SBen Tyner {
12821cc6270SBen Tyner o_files.push_back(std::move(file));
12921cc6270SBen Tyner }
13021cc6270SBen Tyner }
13121cc6270SBen Tyner catch (const std::exception& e)
13221cc6270SBen Tyner {
13321cc6270SBen Tyner trace::err(
13421cc6270SBen Tyner "exception when creating scratch register user data");
13521cc6270SBen Tyner trace::inf(e.what());
13621cc6270SBen Tyner }
13721cc6270SBen Tyner }
13821cc6270SBen Tyner }
13921cc6270SBen Tyner
14021cc6270SBen Tyner return;
14121cc6270SBen Tyner }
14221cc6270SBen Tyner
143135793a8SBen Tyner /** @brief Check for recoverable errors present */
recoverableErrors()144135793a8SBen Tyner bool recoverableErrors()
145135793a8SBen Tyner {
146135793a8SBen Tyner bool recoverableErrors = false; // assume no recoverable attentions
147135793a8SBen Tyner
148135793a8SBen Tyner pdbg_target* target;
149135793a8SBen Tyner pdbg_for_each_class_target("proc", target)
150135793a8SBen Tyner {
151135793a8SBen Tyner if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
152135793a8SBen Tyner {
153135793a8SBen Tyner auto proc = pdbg_target_index(target); // get processor number
154135793a8SBen Tyner
155135793a8SBen Tyner // Use PIB target to determine if a processor is enabled
156135793a8SBen Tyner char path[16];
157135793a8SBen Tyner sprintf(path, "/proc%d/pib", proc);
158135793a8SBen Tyner pdbg_target* pibTarget = pdbg_target_from_path(nullptr, path);
159135793a8SBen Tyner
160135793a8SBen Tyner // sanity check
161135793a8SBen Tyner if (nullptr == pibTarget)
162135793a8SBen Tyner {
163bfa831a8Saustinfcui trace::inf("pib path or target not found");
164135793a8SBen Tyner continue;
165135793a8SBen Tyner }
166135793a8SBen Tyner
167135793a8SBen Tyner // check if pib target is enabled - indicates proc is enabled
168135793a8SBen Tyner if (PDBG_TARGET_ENABLED == pdbg_target_probe(pibTarget))
169135793a8SBen Tyner {
170135793a8SBen Tyner // The processor FSI target is required for CFAM read
171135793a8SBen Tyner sprintf(path, "/proc%d/fsi", proc);
172135793a8SBen Tyner pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path);
173135793a8SBen Tyner
174135793a8SBen Tyner // sanity check
175135793a8SBen Tyner if (nullptr == fsiTarget)
176135793a8SBen Tyner {
177bfa831a8Saustinfcui trace::inf("fsi path or target not found");
178135793a8SBen Tyner continue;
179135793a8SBen Tyner }
180135793a8SBen Tyner
181135793a8SBen Tyner uint32_t isr_val = 0xffffffff; // invalid isr value
182135793a8SBen Tyner
183135793a8SBen Tyner // get active attentions on processor
184135793a8SBen Tyner if (RC_SUCCESS != fsi_read(fsiTarget, 0x1007, &isr_val))
185135793a8SBen Tyner {
186135793a8SBen Tyner // log cfam read error
187bfa831a8Saustinfcui trace::err("cfam read 0x1007 FAILED");
188*a0c724d3SPatrick Williams eventAttentionFail(
189*a0c724d3SPatrick Williams (int)AttnSection::attnHandler | ATTN_PDBG_CFAM);
190135793a8SBen Tyner }
191135793a8SBen Tyner // check for invalid/stale value
192135793a8SBen Tyner else if (0xffffffff == isr_val)
193135793a8SBen Tyner {
194bfa831a8Saustinfcui trace::err("cfam read 0x1007 INVALID");
195135793a8SBen Tyner continue;
196135793a8SBen Tyner }
197135793a8SBen Tyner // check recoverable error status bit
198135793a8SBen Tyner else if (0 != (isr_val & RECOVERABLE_ATTN))
199135793a8SBen Tyner {
200135793a8SBen Tyner recoverableErrors = true;
201135793a8SBen Tyner break;
202135793a8SBen Tyner }
203135793a8SBen Tyner } // fsi target enabled
204135793a8SBen Tyner } // pib target enabled
205135793a8SBen Tyner } // next processor
206135793a8SBen Tyner
207135793a8SBen Tyner return recoverableErrors;
208135793a8SBen Tyner }
209135793a8SBen Tyner
21007ebb9beSBen Tyner /** @brief timesec less-than-equal-to compare */
operator <=(const timespec & lhs,const timespec & rhs)21107ebb9beSBen Tyner bool operator<=(const timespec& lhs, const timespec& rhs)
21207ebb9beSBen Tyner {
21307ebb9beSBen Tyner if (lhs.tv_sec == rhs.tv_sec)
21407ebb9beSBen Tyner return lhs.tv_nsec <= rhs.tv_nsec;
21507ebb9beSBen Tyner else
21607ebb9beSBen Tyner return lhs.tv_sec <= rhs.tv_sec;
21707ebb9beSBen Tyner }
21807ebb9beSBen Tyner
21907ebb9beSBen Tyner /** @brief sleep for n-seconds */
sleepSeconds(const unsigned int seconds)22007ebb9beSBen Tyner void sleepSeconds(const unsigned int seconds)
22107ebb9beSBen Tyner {
22207ebb9beSBen Tyner auto count = seconds;
22307ebb9beSBen Tyner struct timespec requested, remaining;
22407ebb9beSBen Tyner
22507ebb9beSBen Tyner while (0 < count)
22607ebb9beSBen Tyner {
22707ebb9beSBen Tyner requested.tv_sec = 1;
22807ebb9beSBen Tyner requested.tv_nsec = 0;
22907ebb9beSBen Tyner remaining = requested;
23007ebb9beSBen Tyner
23107ebb9beSBen Tyner while (-1 == nanosleep(&requested, &remaining))
23207ebb9beSBen Tyner {
23307ebb9beSBen Tyner // if not changing or implausible then abort
23407ebb9beSBen Tyner if (requested <= remaining)
23507ebb9beSBen Tyner {
23607ebb9beSBen Tyner break;
23707ebb9beSBen Tyner }
23807ebb9beSBen Tyner
23907ebb9beSBen Tyner // back to sleep
24007ebb9beSBen Tyner requested = remaining;
24107ebb9beSBen Tyner }
24207ebb9beSBen Tyner count--;
24307ebb9beSBen Tyner }
24407ebb9beSBen Tyner }
24507ebb9beSBen Tyner
246bcf65a8bSBen Tyner } // namespace attn
247