1 /**
2  * Copyright © 2022 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "extensions/phal/clock_logger.hpp"
18 
19 #include "util.hpp"
20 
21 #include <attributes_info.H>
22 #include <libphal.H>
23 
24 #include <phosphor-logging/lg2.hpp>
25 #include <sdeventplus/event.hpp>
26 #include <sdeventplus/utility/timer.hpp>
27 
28 #include <chrono>
29 
30 using namespace openpower::pel;
31 
32 PHOSPHOR_LOG2_USING;
33 
34 namespace openpower::phal::clock
35 {
36 constexpr auto CLOCK_DAILY_LOGGER_TIMEOUT_IN_HOUR = 24;
37 
38 Manager::Manager(const sdeventplus::Event& event) :
39     _event(event), timer(event, std::bind(&Manager::timerExpired, this))
40 
41 {
42     try
43     {
44         // pdbg initialisation
45         openpower::phal::pdbg::init();
46 
47         // Create clock data log.
48         createClockDataLog();
49     }
50     catch (const std::exception& e)
51     {
52         error("Clock Data Log exception ({ERROR})", "ERROR", e);
53     }
54 
55     addTimer();
56 }
57 
58 void Manager::addTimer()
59 {
60     // Set timer for 24 hours.
61     timer.restart(std::chrono::hours(CLOCK_DAILY_LOGGER_TIMEOUT_IN_HOUR));
62 }
63 
64 void Manager::timerExpired()
65 {
66     info("Clock daily logging started");
67 
68     try
69     {
70         // Create clock data log.
71         createClockDataLog();
72     }
73     catch (const std::exception& e)
74     {
75         error("createClockDataLog exception ({ERROR})", "ERROR", e);
76     }
77 }
78 
79 void Manager::createClockDataLog()
80 {
81     // check chassis power state.
82     auto powerState = openpower::util::getChassisPowerState();
83 
84     if (powerState != "xyz.openbmc_project.State.Chassis.PowerState.On")
85     {
86         warning("The chassis power state({POWERSTATE}) is not ON, Skipping "
87                 "clock data "
88                 "logging",
89                 "POWERSTATE", powerState);
90         return;
91     }
92 
93     // Data logger storage
94     FFDCData clockDataLog;
95 
96     struct pdbg_target* procTarget;
97     ATTR_HWAS_STATE_Type hwasState;
98     pdbg_for_each_class_target("proc", procTarget)
99     {
100         if (DT_GET_PROP(ATTR_HWAS_STATE, procTarget, hwasState))
101         {
102             error("{TARGET} Could not read HWAS_STATE attribute", "TARGET",
103                   pdbg_target_path(procTarget));
104             continue;
105         }
106         if (!hwasState.present)
107         {
108             continue;
109         }
110 
111         auto index = std::to_string(pdbg_target_index(procTarget));
112 
113         // update functional State
114         std::string funState = "Non Functional";
115 
116         if (hwasState.functional)
117         {
118             funState = "Functional";
119         }
120         std::stringstream ssState;
121         ssState << "Proc" << index;
122         clockDataLog.push_back(std::make_pair(ssState.str(), funState));
123 
124         // update location code information
125         ATTR_LOCATION_CODE_Type locationCode;
126         memset(&locationCode, '\0', sizeof(locationCode));
127         try
128         {
129             openpower::phal::pdbg::getLocationCode(procTarget, locationCode);
130         }
131         catch (const std::exception& e)
132         {
133             error("getLocationCode on {TARGET} thrown exception ({ERROR})",
134                   "TARGET", pdbg_target_path(procTarget), "ERROR", e);
135         }
136         std::stringstream ssLoc;
137         ssLoc << "Proc" << index << " Location Code";
138         clockDataLog.push_back(std::make_pair(ssLoc.str(), locationCode));
139 
140         // Update Processor EC level
141         ATTR_EC_Type ecVal = 0;
142         if (DT_GET_PROP(ATTR_EC, procTarget, ecVal))
143         {
144             error("Could not read ATTR_EC  attribute");
145         }
146         std::stringstream ssEC;
147         ssEC << "Proc" << index << " EC";
148 
149         std::stringstream ssECVal;
150         ssECVal << "0x" << std::setfill('0') << std::setw(10) << std::hex
151                 << (uint16_t)ecVal;
152         clockDataLog.push_back(std::make_pair(ssEC.str(), ssECVal.str()));
153 
154         // Add CFAM register information.
155         addCFAMData(procTarget, clockDataLog);
156     }
157 
158     openpower::pel::createPEL("org.open_power.PHAL.Info.ClockDailyLog",
159                               clockDataLog);
160 }
161 
162 void Manager::addCFAMData(struct pdbg_target* proc,
163                           openpower::pel::FFDCData& clockDataLog)
164 {
165 
166     // collect Processor CFAM register data
167     const std::vector<int> procCFAMAddr = {
168         0x1007, 0x2804, 0x2810, 0x2813, 0x2814, 0x2815, 0x2816, 0x281D, 0x281E};
169 
170     auto index = std::to_string(pdbg_target_index(proc));
171 
172     for (int addr : procCFAMAddr)
173     {
174         auto val = 0xDEADBEEF;
175         try
176         {
177             val = openpower::phal::pdbg::getCFAM(proc, addr);
178         }
179         catch (const std::exception& e)
180         {
181             error("getCFAM on {TARGET} thrown exception({ERROR}): Addr ({REG})",
182                   "TARGET", pdbg_target_path(proc), "ERROR", e, "REG", addr);
183         }
184         std::stringstream ssData;
185         ssData << "0x" << std::setfill('0') << std::setw(8) << std::hex << val;
186         std::stringstream ssAddr;
187         ssAddr << "Proc" << index << " REG 0x" << std::hex << addr;
188         // update the data
189         clockDataLog.push_back(make_pair(ssAddr.str(), ssData.str()));
190     }
191 }
192 
193 } // namespace openpower::phal::clock
194