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 // Data logger storage 82 FFDCData clockDataLog; 83 84 struct pdbg_target* procTarget; 85 ATTR_HWAS_STATE_Type hwasState; 86 pdbg_for_each_class_target("proc", procTarget) 87 { 88 if (DT_GET_PROP(ATTR_HWAS_STATE, procTarget, hwasState)) 89 { 90 error("{TARGET} Could not read HWAS_STATE attribute", "TARGET", 91 pdbg_target_path(procTarget)); 92 continue; 93 } 94 if (!hwasState.present) 95 { 96 continue; 97 } 98 99 auto index = std::to_string(pdbg_target_index(procTarget)); 100 101 // update functional State 102 std::string funState = "Non Functional"; 103 104 if (hwasState.functional) 105 { 106 funState = "Functional"; 107 } 108 std::stringstream ssState; 109 ssState << "Proc" << index; 110 clockDataLog.push_back(std::make_pair(ssState.str(), funState)); 111 112 // update location code information 113 ATTR_LOCATION_CODE_Type locationCode; 114 memset(&locationCode, '\0', sizeof(locationCode)); 115 try 116 { 117 openpower::phal::pdbg::getLocationCode(procTarget, locationCode); 118 } 119 catch (const std::exception& e) 120 { 121 error("getLocationCode on {TARGET} thrown exception ({ERROR})", 122 "TARGET", pdbg_target_path(procTarget), "ERROR", e); 123 } 124 std::stringstream ssLoc; 125 ssLoc << "Proc" << index << " Location Code"; 126 clockDataLog.push_back(std::make_pair(ssLoc.str(), locationCode)); 127 128 // Update Processor EC level 129 ATTR_EC_Type ecVal = 0; 130 if (DT_GET_PROP(ATTR_EC, procTarget, ecVal)) 131 { 132 error("Could not read ATTR_EC attribute"); 133 } 134 std::stringstream ssEC; 135 ssEC << "Proc" << index << " EC"; 136 137 std::stringstream ssECVal; 138 ssECVal << "0x" << std::setfill('0') << std::setw(10) << std::hex 139 << (uint16_t)ecVal; 140 clockDataLog.push_back(std::make_pair(ssEC.str(), ssECVal.str())); 141 142 // Add CFAM register information. 143 addCFAMData(procTarget, clockDataLog); 144 } 145 146 // Add clock register information 147 addClockRegData(clockDataLog); 148 149 openpower::pel::createPEL("org.open_power.PHAL.Info.ClockDailyLog", 150 clockDataLog, Severity::Informational); 151 } 152 153 void Manager::addCFAMData(struct pdbg_target* proc, 154 openpower::pel::FFDCData& clockDataLog) 155 { 156 // collect Processor CFAM register data 157 const std::vector<int> procCFAMAddr = { 158 0x1007, 0x2804, 0x2810, 0x2813, 0x2814, 0x2815, 0x2816, 0x281D, 0x281E}; 159 160 auto index = std::to_string(pdbg_target_index(proc)); 161 162 for (int addr : procCFAMAddr) 163 { 164 auto val = 0xDEADBEEF; 165 try 166 { 167 val = openpower::phal::pdbg::getCFAM(proc, addr); 168 } 169 catch (const std::exception& e) 170 { 171 error("getCFAM on {TARGET} thrown exception({ERROR}): Addr ({REG})", 172 "TARGET", pdbg_target_path(proc), "ERROR", e, "REG", addr); 173 } 174 std::stringstream ssData; 175 ssData << "0x" << std::setfill('0') << std::setw(8) << std::hex << val; 176 std::stringstream ssAddr; 177 ssAddr << "Proc" << index << " REG 0x" << std::hex << addr; 178 // update the data 179 clockDataLog.push_back(make_pair(ssAddr.str(), ssData.str())); 180 } 181 } 182 183 void Manager::addClockRegData(openpower::pel::FFDCData& clockDataLog) 184 { 185 info("Adding clock register information to daily logger"); 186 187 struct pdbg_target* clockTarget; 188 pdbg_for_each_class_target("oscrefclk", clockTarget) 189 { 190 ATTR_HWAS_STATE_Type hwasState; 191 if (DT_GET_PROP(ATTR_HWAS_STATE, clockTarget, hwasState)) 192 { 193 error("({TARGET}) Could not read HWAS_STATE attribute", "TARGET", 194 pdbg_target_path(clockTarget)); 195 continue; 196 } 197 198 if (!hwasState.present) 199 { 200 continue; 201 } 202 203 std::string funState = "Non Functional"; 204 205 if (hwasState.functional) 206 { 207 funState = "Functional"; 208 } 209 210 auto index = std::to_string(pdbg_target_index(clockTarget)); 211 212 std::stringstream ssState; 213 ssState << "Clock" << index; 214 clockDataLog.push_back(std::make_pair(ssState.str(), funState)); 215 216 // Add clcok device path information 217 std::stringstream ssName; 218 ssName << "Clock" << index << " path"; 219 clockDataLog.push_back( 220 std::make_pair(ssName.str(), pdbg_target_path(clockTarget))); 221 222 auto status = pdbg_target_probe(clockTarget); 223 if (status != PDBG_TARGET_ENABLED) 224 { 225 continue; 226 } 227 228 // Update Buffer with clock I2C register data. 229 auto constexpr I2C_READ_SIZE = 0x08; 230 auto constexpr I2C_ADDR_MAX = 0xFF; 231 232 for (auto addr = 0; addr <= I2C_ADDR_MAX; addr += I2C_READ_SIZE) 233 { 234 std::stringstream ssData; 235 236 uint8_t data[0x8]; 237 auto i2cRc = i2c_read(clockTarget, 0, addr, I2C_READ_SIZE, data); 238 if (i2cRc) 239 { 240 error("({TARGET}) I2C read error({ERROR}) reported {ADDRESS} ", 241 "TARGET", pdbg_target_path(clockTarget), "ERROR", i2cRc, 242 "ADDRESS", addr); 243 continue; 244 } 245 246 for (auto i = 0; i < I2C_READ_SIZE; i++) 247 { 248 ssData << " " << std::hex << std::setfill('0') << std::setw(2) 249 << (uint16_t)data[i]; 250 } 251 std::stringstream ssAddr; 252 ssAddr << "Clock" << index << "_0x" << std::hex << std::setfill('0') 253 << std::setw(2) << addr; 254 clockDataLog.push_back(make_pair(ssAddr.str(), ssData.str())); 255 } 256 } 257 } 258 259 } // namespace openpower::phal::clock 260