1ed7fb7aeSJayanth Othayoth /**
2ed7fb7aeSJayanth Othayoth  * Copyright © 2022 IBM Corporation
3ed7fb7aeSJayanth Othayoth  *
4ed7fb7aeSJayanth Othayoth  * Licensed under the Apache License, Version 2.0 (the "License");
5ed7fb7aeSJayanth Othayoth  * you may not use this file except in compliance with the License.
6ed7fb7aeSJayanth Othayoth  * You may obtain a copy of the License at
7ed7fb7aeSJayanth Othayoth  *
8ed7fb7aeSJayanth Othayoth  *     http://www.apache.org/licenses/LICENSE-2.0
9ed7fb7aeSJayanth Othayoth  *
10ed7fb7aeSJayanth Othayoth  * Unless required by applicable law or agreed to in writing, software
11ed7fb7aeSJayanth Othayoth  * distributed under the License is distributed on an "AS IS" BASIS,
12ed7fb7aeSJayanth Othayoth  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ed7fb7aeSJayanth Othayoth  * See the License for the specific language governing permissions and
14ed7fb7aeSJayanth Othayoth  * limitations under the License.
15ed7fb7aeSJayanth Othayoth  */
16ed7fb7aeSJayanth Othayoth 
17ed7fb7aeSJayanth Othayoth #include "extensions/phal/clock_logger.hpp"
18ed7fb7aeSJayanth Othayoth 
19ed7fb7aeSJayanth Othayoth #include "util.hpp"
20ed7fb7aeSJayanth Othayoth 
21ed7fb7aeSJayanth Othayoth #include <attributes_info.H>
22ed7fb7aeSJayanth Othayoth #include <libphal.H>
23ed7fb7aeSJayanth Othayoth 
24ed7fb7aeSJayanth Othayoth #include <phosphor-logging/lg2.hpp>
25ed7fb7aeSJayanth Othayoth #include <sdeventplus/event.hpp>
26ed7fb7aeSJayanth Othayoth #include <sdeventplus/utility/timer.hpp>
27ed7fb7aeSJayanth Othayoth 
28ed7fb7aeSJayanth Othayoth #include <chrono>
29ed7fb7aeSJayanth Othayoth 
30ed7fb7aeSJayanth Othayoth using namespace openpower::pel;
31ed7fb7aeSJayanth Othayoth 
32ed7fb7aeSJayanth Othayoth PHOSPHOR_LOG2_USING;
33ed7fb7aeSJayanth Othayoth 
34ed7fb7aeSJayanth Othayoth namespace openpower::phal::clock
35ed7fb7aeSJayanth Othayoth {
36ed7fb7aeSJayanth Othayoth constexpr auto CLOCK_DAILY_LOGGER_TIMEOUT_IN_HOUR = 24;
37ed7fb7aeSJayanth Othayoth 
38ed7fb7aeSJayanth Othayoth Manager::Manager(const sdeventplus::Event& event) :
39ed7fb7aeSJayanth Othayoth     _event(event), timer(event, std::bind(&Manager::timerExpired, this))
40ed7fb7aeSJayanth Othayoth 
41ed7fb7aeSJayanth Othayoth {
42ed7fb7aeSJayanth Othayoth     try
43ed7fb7aeSJayanth Othayoth     {
44ed7fb7aeSJayanth Othayoth         // pdbg initialisation
45ed7fb7aeSJayanth Othayoth         openpower::phal::pdbg::init();
46ed7fb7aeSJayanth Othayoth 
47ed7fb7aeSJayanth Othayoth         // Create clock data log.
48ed7fb7aeSJayanth Othayoth         createClockDataLog();
49ed7fb7aeSJayanth Othayoth     }
50ed7fb7aeSJayanth Othayoth     catch (const std::exception& e)
51ed7fb7aeSJayanth Othayoth     {
52ed7fb7aeSJayanth Othayoth         error("Clock Data Log exception ({ERROR})", "ERROR", e);
53ed7fb7aeSJayanth Othayoth     }
54ed7fb7aeSJayanth Othayoth 
55ed7fb7aeSJayanth Othayoth     addTimer();
56ed7fb7aeSJayanth Othayoth }
57ed7fb7aeSJayanth Othayoth 
58ed7fb7aeSJayanth Othayoth void Manager::addTimer()
59ed7fb7aeSJayanth Othayoth {
60ed7fb7aeSJayanth Othayoth     // Set timer for 24 hours.
61ed7fb7aeSJayanth Othayoth     timer.restart(std::chrono::hours(CLOCK_DAILY_LOGGER_TIMEOUT_IN_HOUR));
62ed7fb7aeSJayanth Othayoth }
63ed7fb7aeSJayanth Othayoth 
64ed7fb7aeSJayanth Othayoth void Manager::timerExpired()
65ed7fb7aeSJayanth Othayoth {
66ed7fb7aeSJayanth Othayoth     info("Clock daily logging started");
67ed7fb7aeSJayanth Othayoth 
68ed7fb7aeSJayanth Othayoth     try
69ed7fb7aeSJayanth Othayoth     {
70ed7fb7aeSJayanth Othayoth         // Create clock data log.
71ed7fb7aeSJayanth Othayoth         createClockDataLog();
72ed7fb7aeSJayanth Othayoth     }
73ed7fb7aeSJayanth Othayoth     catch (const std::exception& e)
74ed7fb7aeSJayanth Othayoth     {
75ed7fb7aeSJayanth Othayoth         error("createClockDataLog exception ({ERROR})", "ERROR", e);
76ed7fb7aeSJayanth Othayoth     }
77ed7fb7aeSJayanth Othayoth }
78ed7fb7aeSJayanth Othayoth 
79ed7fb7aeSJayanth Othayoth void Manager::createClockDataLog()
80ed7fb7aeSJayanth Othayoth {
81ed7fb7aeSJayanth Othayoth     // check chassis power state.
82ed7fb7aeSJayanth Othayoth     auto powerState = openpower::util::getChassisPowerState();
83ed7fb7aeSJayanth Othayoth 
84ed7fb7aeSJayanth Othayoth     if (powerState != "xyz.openbmc_project.State.Chassis.PowerState.On")
85ed7fb7aeSJayanth Othayoth     {
86ed7fb7aeSJayanth Othayoth         warning("The chassis power state({POWERSTATE}) is not ON, Skipping "
87ed7fb7aeSJayanth Othayoth                 "clock data "
88ed7fb7aeSJayanth Othayoth                 "logging",
89ed7fb7aeSJayanth Othayoth                 "POWERSTATE", powerState);
90ed7fb7aeSJayanth Othayoth         return;
91ed7fb7aeSJayanth Othayoth     }
92ed7fb7aeSJayanth Othayoth 
93ed7fb7aeSJayanth Othayoth     // Data logger storage
94ed7fb7aeSJayanth Othayoth     FFDCData clockDataLog;
95ed7fb7aeSJayanth Othayoth 
96ed7fb7aeSJayanth Othayoth     struct pdbg_target* procTarget;
97ed7fb7aeSJayanth Othayoth     ATTR_HWAS_STATE_Type hwasState;
98ed7fb7aeSJayanth Othayoth     pdbg_for_each_class_target("proc", procTarget)
99ed7fb7aeSJayanth Othayoth     {
100ed7fb7aeSJayanth Othayoth         if (DT_GET_PROP(ATTR_HWAS_STATE, procTarget, hwasState))
101ed7fb7aeSJayanth Othayoth         {
102ed7fb7aeSJayanth Othayoth             error("{TARGET} Could not read HWAS_STATE attribute", "TARGET",
103ed7fb7aeSJayanth Othayoth                   pdbg_target_path(procTarget));
104ed7fb7aeSJayanth Othayoth             continue;
105ed7fb7aeSJayanth Othayoth         }
106ed7fb7aeSJayanth Othayoth         if (!hwasState.present)
107ed7fb7aeSJayanth Othayoth         {
108ed7fb7aeSJayanth Othayoth             continue;
109ed7fb7aeSJayanth Othayoth         }
110ed7fb7aeSJayanth Othayoth 
111ed7fb7aeSJayanth Othayoth         auto index = std::to_string(pdbg_target_index(procTarget));
112ed7fb7aeSJayanth Othayoth 
113ed7fb7aeSJayanth Othayoth         // update functional State
114ed7fb7aeSJayanth Othayoth         std::string funState = "Non Functional";
115ed7fb7aeSJayanth Othayoth 
116ed7fb7aeSJayanth Othayoth         if (hwasState.functional)
117ed7fb7aeSJayanth Othayoth         {
118ed7fb7aeSJayanth Othayoth             funState = "Functional";
119ed7fb7aeSJayanth Othayoth         }
120ed7fb7aeSJayanth Othayoth         std::stringstream ssState;
121ed7fb7aeSJayanth Othayoth         ssState << "Proc" << index;
122ed7fb7aeSJayanth Othayoth         clockDataLog.push_back(std::make_pair(ssState.str(), funState));
123ed7fb7aeSJayanth Othayoth 
124ed7fb7aeSJayanth Othayoth         // update location code information
125ed7fb7aeSJayanth Othayoth         ATTR_LOCATION_CODE_Type locationCode;
126ed7fb7aeSJayanth Othayoth         memset(&locationCode, '\0', sizeof(locationCode));
127ed7fb7aeSJayanth Othayoth         try
128ed7fb7aeSJayanth Othayoth         {
129ed7fb7aeSJayanth Othayoth             openpower::phal::pdbg::getLocationCode(procTarget, locationCode);
130ed7fb7aeSJayanth Othayoth         }
131ed7fb7aeSJayanth Othayoth         catch (const std::exception& e)
132ed7fb7aeSJayanth Othayoth         {
133ed7fb7aeSJayanth Othayoth             error("getLocationCode on {TARGET} thrown exception ({ERROR})",
134ed7fb7aeSJayanth Othayoth                   "TARGET", pdbg_target_path(procTarget), "ERROR", e);
135ed7fb7aeSJayanth Othayoth         }
136ed7fb7aeSJayanth Othayoth         std::stringstream ssLoc;
137ed7fb7aeSJayanth Othayoth         ssLoc << "Proc" << index << " Location Code";
138ed7fb7aeSJayanth Othayoth         clockDataLog.push_back(std::make_pair(ssLoc.str(), locationCode));
139ed7fb7aeSJayanth Othayoth 
140ed7fb7aeSJayanth Othayoth         // Update Processor EC level
141ed7fb7aeSJayanth Othayoth         ATTR_EC_Type ecVal = 0;
142ed7fb7aeSJayanth Othayoth         if (DT_GET_PROP(ATTR_EC, procTarget, ecVal))
143ed7fb7aeSJayanth Othayoth         {
144ed7fb7aeSJayanth Othayoth             error("Could not read ATTR_EC  attribute");
145ed7fb7aeSJayanth Othayoth         }
146ed7fb7aeSJayanth Othayoth         std::stringstream ssEC;
147ed7fb7aeSJayanth Othayoth         ssEC << "Proc" << index << " EC";
148ed7fb7aeSJayanth Othayoth 
149ed7fb7aeSJayanth Othayoth         std::stringstream ssECVal;
150ed7fb7aeSJayanth Othayoth         ssECVal << "0x" << std::setfill('0') << std::setw(10) << std::hex
151ed7fb7aeSJayanth Othayoth                 << (uint16_t)ecVal;
152ed7fb7aeSJayanth Othayoth         clockDataLog.push_back(std::make_pair(ssEC.str(), ssECVal.str()));
15391bf93e0SJayanth Othayoth 
15491bf93e0SJayanth Othayoth         // Add CFAM register information.
15591bf93e0SJayanth Othayoth         addCFAMData(procTarget, clockDataLog);
156ed7fb7aeSJayanth Othayoth     }
157ed7fb7aeSJayanth Othayoth 
1585ffe7fb7SJayanth Othayoth     // Add clock register information
1595ffe7fb7SJayanth Othayoth     addClockRegData(clockDataLog);
1605ffe7fb7SJayanth Othayoth 
161ed7fb7aeSJayanth Othayoth     openpower::pel::createPEL("org.open_power.PHAL.Info.ClockDailyLog",
162*be14ec2dSMatt Spinler                               clockDataLog, Severity::Informational);
163ed7fb7aeSJayanth Othayoth }
164ed7fb7aeSJayanth Othayoth 
16591bf93e0SJayanth Othayoth void Manager::addCFAMData(struct pdbg_target* proc,
16691bf93e0SJayanth Othayoth                           openpower::pel::FFDCData& clockDataLog)
16791bf93e0SJayanth Othayoth {
16891bf93e0SJayanth Othayoth 
16991bf93e0SJayanth Othayoth     // collect Processor CFAM register data
17091bf93e0SJayanth Othayoth     const std::vector<int> procCFAMAddr = {
17191bf93e0SJayanth Othayoth         0x1007, 0x2804, 0x2810, 0x2813, 0x2814, 0x2815, 0x2816, 0x281D, 0x281E};
17291bf93e0SJayanth Othayoth 
17391bf93e0SJayanth Othayoth     auto index = std::to_string(pdbg_target_index(proc));
17491bf93e0SJayanth Othayoth 
17591bf93e0SJayanth Othayoth     for (int addr : procCFAMAddr)
17691bf93e0SJayanth Othayoth     {
17791bf93e0SJayanth Othayoth         auto val = 0xDEADBEEF;
17891bf93e0SJayanth Othayoth         try
17991bf93e0SJayanth Othayoth         {
18091bf93e0SJayanth Othayoth             val = openpower::phal::pdbg::getCFAM(proc, addr);
18191bf93e0SJayanth Othayoth         }
18291bf93e0SJayanth Othayoth         catch (const std::exception& e)
18391bf93e0SJayanth Othayoth         {
18491bf93e0SJayanth Othayoth             error("getCFAM on {TARGET} thrown exception({ERROR}): Addr ({REG})",
18591bf93e0SJayanth Othayoth                   "TARGET", pdbg_target_path(proc), "ERROR", e, "REG", addr);
18691bf93e0SJayanth Othayoth         }
18791bf93e0SJayanth Othayoth         std::stringstream ssData;
18891bf93e0SJayanth Othayoth         ssData << "0x" << std::setfill('0') << std::setw(8) << std::hex << val;
18991bf93e0SJayanth Othayoth         std::stringstream ssAddr;
19091bf93e0SJayanth Othayoth         ssAddr << "Proc" << index << " REG 0x" << std::hex << addr;
19191bf93e0SJayanth Othayoth         // update the data
19291bf93e0SJayanth Othayoth         clockDataLog.push_back(make_pair(ssAddr.str(), ssData.str()));
19391bf93e0SJayanth Othayoth     }
19491bf93e0SJayanth Othayoth }
19591bf93e0SJayanth Othayoth 
1965ffe7fb7SJayanth Othayoth void Manager::addClockRegData(openpower::pel::FFDCData& clockDataLog)
1975ffe7fb7SJayanth Othayoth {
1985ffe7fb7SJayanth Othayoth     info("Adding clock register information to daily logger");
1995ffe7fb7SJayanth Othayoth 
2005ffe7fb7SJayanth Othayoth     struct pdbg_target* clockTarget;
2015ffe7fb7SJayanth Othayoth     pdbg_for_each_class_target("oscrefclk", clockTarget)
2025ffe7fb7SJayanth Othayoth     {
2035ffe7fb7SJayanth Othayoth         ATTR_HWAS_STATE_Type hwasState;
2045ffe7fb7SJayanth Othayoth         if (DT_GET_PROP(ATTR_HWAS_STATE, clockTarget, hwasState))
2055ffe7fb7SJayanth Othayoth         {
2065ffe7fb7SJayanth Othayoth             error("({TARGET}) Could not read HWAS_STATE attribute", "TARGET",
2075ffe7fb7SJayanth Othayoth                   pdbg_target_path(clockTarget));
2085ffe7fb7SJayanth Othayoth             continue;
2095ffe7fb7SJayanth Othayoth         }
2105ffe7fb7SJayanth Othayoth 
2115ffe7fb7SJayanth Othayoth         if (!hwasState.present)
2125ffe7fb7SJayanth Othayoth         {
2135ffe7fb7SJayanth Othayoth             continue;
2145ffe7fb7SJayanth Othayoth         }
2155ffe7fb7SJayanth Othayoth 
2165ffe7fb7SJayanth Othayoth         std::string funState = "Non Functional";
2175ffe7fb7SJayanth Othayoth 
2185ffe7fb7SJayanth Othayoth         if (hwasState.functional)
2195ffe7fb7SJayanth Othayoth         {
2205ffe7fb7SJayanth Othayoth             funState = "Functional";
2215ffe7fb7SJayanth Othayoth         }
2225ffe7fb7SJayanth Othayoth 
2235ffe7fb7SJayanth Othayoth         auto index = std::to_string(pdbg_target_index(clockTarget));
2245ffe7fb7SJayanth Othayoth 
2255ffe7fb7SJayanth Othayoth         std::stringstream ssState;
2265ffe7fb7SJayanth Othayoth         ssState << "Clock" << index;
2275ffe7fb7SJayanth Othayoth         clockDataLog.push_back(std::make_pair(ssState.str(), funState));
2285ffe7fb7SJayanth Othayoth 
2295ffe7fb7SJayanth Othayoth         // Add clcok device path information
2305ffe7fb7SJayanth Othayoth         std::stringstream ssName;
2315ffe7fb7SJayanth Othayoth         ssName << "Clock" << index << " path";
2325ffe7fb7SJayanth Othayoth         clockDataLog.push_back(
2335ffe7fb7SJayanth Othayoth             std::make_pair(ssName.str(), pdbg_target_path(clockTarget)));
2345ffe7fb7SJayanth Othayoth 
2355ffe7fb7SJayanth Othayoth         auto status = pdbg_target_probe(clockTarget);
2365ffe7fb7SJayanth Othayoth         if (status != PDBG_TARGET_ENABLED)
2375ffe7fb7SJayanth Othayoth         {
2385ffe7fb7SJayanth Othayoth             continue;
2395ffe7fb7SJayanth Othayoth         }
2405ffe7fb7SJayanth Othayoth 
2415ffe7fb7SJayanth Othayoth         // Update Buffer with clock I2C register data.
2425ffe7fb7SJayanth Othayoth         auto constexpr I2C_READ_SIZE = 0x08;
2435ffe7fb7SJayanth Othayoth         auto constexpr I2C_ADDR_MAX = 0xFF;
2445ffe7fb7SJayanth Othayoth 
2455ffe7fb7SJayanth Othayoth         for (auto addr = 0; addr <= I2C_ADDR_MAX; addr += I2C_READ_SIZE)
2465ffe7fb7SJayanth Othayoth         {
2475ffe7fb7SJayanth Othayoth             std::stringstream ssData;
2485ffe7fb7SJayanth Othayoth 
2495ffe7fb7SJayanth Othayoth             uint8_t data[0x8];
2505ffe7fb7SJayanth Othayoth             auto i2cRc = i2c_read(clockTarget, 0, addr, I2C_READ_SIZE, data);
2515ffe7fb7SJayanth Othayoth             if (i2cRc)
2525ffe7fb7SJayanth Othayoth             {
2535ffe7fb7SJayanth Othayoth                 error("({TARGET}) I2C read error({ERROR}) reported {ADDRESS} ",
2545ffe7fb7SJayanth Othayoth                       "TARGET", pdbg_target_path(clockTarget), "ERROR", i2cRc,
2555ffe7fb7SJayanth Othayoth                       "ADDRESS", addr);
2565ffe7fb7SJayanth Othayoth                 continue;
2575ffe7fb7SJayanth Othayoth             }
2585ffe7fb7SJayanth Othayoth 
2595ffe7fb7SJayanth Othayoth             for (auto i = 0; i < I2C_READ_SIZE; i++)
2605ffe7fb7SJayanth Othayoth             {
2615ffe7fb7SJayanth Othayoth                 ssData << " " << std::hex << std::setfill('0') << std::setw(2)
2625ffe7fb7SJayanth Othayoth                        << (uint16_t)data[i];
2635ffe7fb7SJayanth Othayoth             }
2645ffe7fb7SJayanth Othayoth             std::stringstream ssAddr;
2655ffe7fb7SJayanth Othayoth             ssAddr << "Clock" << index << "_0x" << std::hex << std::setfill('0')
2665ffe7fb7SJayanth Othayoth                    << std::setw(2) << addr;
2675ffe7fb7SJayanth Othayoth             clockDataLog.push_back(make_pair(ssAddr.str(), ssData.str()));
2685ffe7fb7SJayanth Othayoth         }
2695ffe7fb7SJayanth Othayoth     }
2705ffe7fb7SJayanth Othayoth }
2715ffe7fb7SJayanth Othayoth 
272ed7fb7aeSJayanth Othayoth } // namespace openpower::phal::clock
273