1366 lines
42 KiB
C++
Executable File
1366 lines
42 KiB
C++
Executable File
/*
|
|
// Copyright (c) 2019 Intel Corporation
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
*/
|
|
#include "dimmSpdReader.hpp"
|
|
#include "i3cdev.h"
|
|
#include <gpiod.hpp>
|
|
#include <phosphor-logging/lg2.hpp>
|
|
#include <stdint.h>
|
|
|
|
#include <chrono>
|
|
#include <cmath>
|
|
#include <functional>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <numeric>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <ctime>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <unistd.h>
|
|
#include <nlohmann/json.hpp>
|
|
|
|
static constexpr bool debug = false;
|
|
|
|
#define PECI_MBX_INDEX_DDR_DIMM_TEMP 0x0E
|
|
constexpr auto dimmSensorInterface = "xyz.openbmc_project.Sensor.dimmLED";
|
|
constexpr auto dimmSensorPath = "/xyz/openbmc_project/sensors/temperature/";
|
|
constexpr auto HostMiscDbusName = "xyz.openbmc_project.Host.Misc.Manager";
|
|
constexpr auto platformStatePath = "/xyz/openbmc_project/misc/platform_state";
|
|
constexpr auto platformStateInterface = "xyz.openbmc_project.State.Host.Misc";
|
|
constexpr auto postCompleteProperty = "PostComplete";
|
|
static constexpr const char* dimmInfoPath = "/var/log/dimmInfo.json";
|
|
static constexpr const char* dimmInfoTempPath = "/usr/share/dimm-spd-reader/dimmInfo_template.json";
|
|
static int lastIndex = -1;
|
|
|
|
#define NUM_TO_SPD(n) (((n) % 3) * 2)
|
|
#define NUM_TO_PMIC(n) (((n) % 3) * 2 + 8)
|
|
#define I3C_ADDR(cpuid) ("/dev/i3c-" + std::to_string(cpuid) + "-3c00000000")
|
|
#define I3C_TS0_ADDR(cpuid) ("/dev/i3c-" + std::to_string(cpuid) + "-3c00000001")
|
|
#define I3C_TS1_ADDR(cpuid) ("/dev/i3c-" + std::to_string(cpuid) + "-3c00000003")
|
|
|
|
static boost::container::flat_map<std::string, DimmData> dimmDataTable;
|
|
|
|
const boost::container::flat_map<std::string, bool> cfgCpu0DimmABC = {
|
|
{"I3C_SPD_BMC_MUX0_SEL", false},
|
|
{"I3C_SPD_BMC_MUX0_EN", false},
|
|
{"I3C_SPD_BMC_MUX1_SEL", true},
|
|
{"I3C_SPD_BMC_MUX1_EN", true}};
|
|
|
|
const boost::container::flat_map<std::string, bool> cfgCpu0DimmDEF = {
|
|
{"I3C_SPD_BMC_MUX0_SEL", true},
|
|
{"I3C_SPD_BMC_MUX0_EN", false},
|
|
{"I3C_SPD_BMC_MUX1_SEL", true},
|
|
{"I3C_SPD_BMC_MUX1_EN", true}};
|
|
|
|
const boost::container::flat_map<std::string, bool> cfgCpu0DimmGHI = {
|
|
{"I3C_SPD_BMC_MUX0_SEL", true},
|
|
{"I3C_SPD_BMC_MUX0_EN", true},
|
|
{"I3C_SPD_BMC_MUX1_SEL", false},
|
|
{"I3C_SPD_BMC_MUX1_EN", false}};
|
|
|
|
const boost::container::flat_map<std::string, bool> cfgCpu0DimmJKL = {
|
|
{"I3C_SPD_BMC_MUX0_SEL", true},
|
|
{"I3C_SPD_BMC_MUX0_EN", true},
|
|
{"I3C_SPD_BMC_MUX1_SEL", true},
|
|
{"I3C_SPD_BMC_MUX1_EN", false}};
|
|
|
|
const boost::container::flat_map<std::string, bool> cfgCpu1DimmABC = {
|
|
{"I3C_SPD_BMC_MUX2_SEL", false},
|
|
{"I3C_SPD_BMC_MUX2_EN", false},
|
|
{"I3C_SPD_BMC_MUX3_SEL", true},
|
|
{"I3C_SPD_BMC_MUX3_EN", true}};
|
|
|
|
const boost::container::flat_map<std::string, bool> cfgCpu1DimmDEF = {
|
|
{"I3C_SPD_BMC_MUX2_SEL", true},
|
|
{"I3C_SPD_BMC_MUX2_EN", false},
|
|
{"I3C_SPD_BMC_MUX3_SEL", true},
|
|
{"I3C_SPD_BMC_MUX3_EN", true}};
|
|
|
|
const boost::container::flat_map<std::string, bool> cfgCpu1DimmGHI = {
|
|
{"I3C_SPD_BMC_MUX2_SEL", true},
|
|
{"I3C_SPD_BMC_MUX2_EN", true},
|
|
{"I3C_SPD_BMC_MUX3_SEL", false},
|
|
{"I3C_SPD_BMC_MUX3_EN", false}};
|
|
|
|
const boost::container::flat_map<std::string, bool> cfgCpu1DimmJKL = {
|
|
{"I3C_SPD_BMC_MUX2_SEL", true},
|
|
{"I3C_SPD_BMC_MUX2_EN", true},
|
|
{"I3C_SPD_BMC_MUX3_SEL", true},
|
|
{"I3C_SPD_BMC_MUX3_EN", false}};
|
|
|
|
|
|
static std::vector<boost::container::flat_map<std::string, bool>> cfgGPIO = {
|
|
cfgCpu0DimmABC,
|
|
cfgCpu0DimmDEF,
|
|
cfgCpu0DimmGHI,
|
|
cfgCpu0DimmJKL,
|
|
cfgCpu1DimmABC,
|
|
cfgCpu1DimmDEF,
|
|
cfgCpu1DimmGHI,
|
|
cfgCpu1DimmJKL
|
|
};
|
|
|
|
static inline std::string to_hex(int num) {
|
|
std::stringstream ss;
|
|
ss << std::hex << num;
|
|
return ss.str();
|
|
}
|
|
|
|
static inline std::string get_current_timestamp() {
|
|
auto now = std::chrono::system_clock::now();
|
|
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
|
|
|
|
std::tm tm = *std::localtime(&now_time);
|
|
std::stringstream ss;
|
|
ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); // 格式化为 "YYYY-MM-DD HH:MM:SS"
|
|
return ss.str();
|
|
}
|
|
|
|
static bool getDbusMsgState(sdbusplus::message_t& msg, bool& value)
|
|
{
|
|
std::string pltStateInterface;
|
|
std::string event;
|
|
boost::container::flat_map<std::string, std::variant<bool>>
|
|
propertiesChanged;
|
|
try
|
|
{
|
|
msg.read(pltStateInterface, propertiesChanged);
|
|
if (propertiesChanged.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::string property = propertiesChanged.begin()->first;
|
|
|
|
if (property.empty() || property != "dimmI3cSwitch")
|
|
{
|
|
return false;
|
|
}
|
|
|
|
value = std::get<bool>(propertiesChanged.begin()->second);
|
|
return true;
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
std::cerr << "exception while reading dbus property dimmI3cSwitch" << "\n";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static int getADCUpdateTime(int value) {
|
|
static const int updateTimes[] = {1, 2, 4, 8};
|
|
|
|
if (value >= 0 && value < 4) {
|
|
return updateTimes[value];
|
|
} else {
|
|
return 8;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void updateField(const std::string& dimmName, FieldType field, T newValues[], size_t size) {
|
|
auto it = dimmDataTable.find(dimmName);
|
|
if (it != dimmDataTable.end()) {
|
|
switch (field) {
|
|
case VOLTAGE:
|
|
if (size == STATUS_PMIC_RAIL_NUM) {
|
|
std::copy(newValues, newValues + size, std::begin(it->second.voltage));
|
|
} else {
|
|
std::cout << "Invalid size for voltage array!" << std::endl;
|
|
}
|
|
break;
|
|
|
|
case CURRENT:
|
|
if (size == STATUS_PMIC_RAIL_NUM) {
|
|
std::copy(newValues, newValues + size, std::begin(it->second.current));
|
|
} else {
|
|
std::cout << "Invalid size for current array!" << std::endl;
|
|
}
|
|
break;
|
|
|
|
case POWER:
|
|
if (size == STATUS_PMIC_RAIL_NUM) {
|
|
std::copy(newValues, newValues + size, std::begin(it->second.power));
|
|
} else {
|
|
std::cout << "Invalid size for power array!" << std::endl;
|
|
}
|
|
break;
|
|
|
|
case TEMP:
|
|
if (size == STATUS_TEMP_NUM) {
|
|
std::copy(newValues, newValues + size, std::begin(it->second.temp));
|
|
} else {
|
|
std::cout << "Invalid size for temp array!" << std::endl;
|
|
}
|
|
break;
|
|
|
|
case STATUS:
|
|
if (size == STATUS_REG_NUM) {
|
|
std::copy(newValues, newValues + size, std::begin(it->second.reg));
|
|
} else {
|
|
std::cout << "Invalid size for status array!" << std::endl;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
std::cout << "Unknown field type!" << std::endl;
|
|
break;
|
|
}
|
|
} else {
|
|
std::cout << "DIMM not found!" << std::endl;
|
|
}
|
|
}
|
|
|
|
void DIMMSpdReader::getdimmI3cSwitchState(const std::shared_ptr<sdbusplus::asio::connection>& conn,
|
|
size_t retries)
|
|
{
|
|
conn->async_method_call(
|
|
[conn, retries, this](boost::system::error_code ec,
|
|
const std::variant<bool>& state) {
|
|
if (ec)
|
|
{
|
|
if (retries != 0U)
|
|
{
|
|
auto timer = std::make_shared<boost::asio::steady_timer>(
|
|
conn->get_io_context());
|
|
timer->expires_after(std::chrono::seconds(15));
|
|
timer->async_wait(
|
|
[timer, conn, retries, this](boost::system::error_code) {
|
|
this->getdimmI3cSwitchState(conn, retries - 1);
|
|
});
|
|
return;
|
|
}
|
|
|
|
std::cerr << "error getting dimm I3cSwitchState" << ec.message() << "\n";
|
|
return;
|
|
}
|
|
bool i3cSwitchState = std::get<bool>(state);
|
|
std::cout << "i3cSwitch state: " << (int)i3cSwitchState << std::endl;
|
|
if(i3cSwitchState)
|
|
{
|
|
int ret = system("modprobe dw-i3c-master");
|
|
if (ret != 0) {
|
|
std::cout << "Failed to modprobe dw-i3c-master module" << std::endl;
|
|
return;
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
std::cout << "Start dimm spd reader" << std::endl;
|
|
this->startRead();
|
|
}
|
|
},
|
|
HostMiscDbusName, platformStatePath, "org.freedesktop.DBus.Properties", "Get",
|
|
platformStateInterface, "dimmI3cSwitch");
|
|
}
|
|
|
|
void DIMMSpdReader::dimmI3cSwitchMatcher(
|
|
std::vector<sdbusplus::bus::match_t>& matches, sdbusplus::bus_t& connection,
|
|
std::function<void(bool)>&& onMatch)
|
|
{
|
|
auto pulseEventMatcherCallback =
|
|
[onMatch{std::move(onMatch)}, this](sdbusplus::message_t& msg) {
|
|
bool value = false;
|
|
if (!getDbusMsgState(msg, value))
|
|
{
|
|
return;
|
|
}
|
|
onMatch(value);
|
|
};
|
|
|
|
matches.emplace_back(
|
|
connection,
|
|
"type='signal',interface='org.freedesktop.DBus.Properties',member='"
|
|
"PropertiesChanged',arg0='" +
|
|
std::string(platformStateInterface) + "'",
|
|
std::move(pulseEventMatcherCallback));
|
|
}
|
|
|
|
static bool setGPIOOutput(const std::string& name, const int value,
|
|
gpiod::line& gpioLine)
|
|
{
|
|
// Find the GPIO line
|
|
gpioLine = gpiod::find_line(name);
|
|
if (!gpioLine)
|
|
{
|
|
lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
|
|
return false;
|
|
}
|
|
|
|
// Request GPIO output to specified value
|
|
try
|
|
{
|
|
gpioLine.request({"dimm-spd-reader", gpiod::line_request::DIRECTION_OUTPUT, {}},
|
|
value);
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
|
|
name, "ERROR", e);
|
|
return false;
|
|
}
|
|
|
|
lg2::debug("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
|
|
"GPIO_VALUE", value);
|
|
return true;
|
|
}
|
|
|
|
static void setGPIOToSelectDimm(const boost::container::flat_map<std::string, bool>& cfgMap)
|
|
{
|
|
for(auto cfg : cfgMap)
|
|
{
|
|
gpiod::line line;
|
|
if (!setGPIOOutput(cfg.first, (int)cfg.second, line))
|
|
{
|
|
std::cerr << "Setting I3CSwitch GPIO failed \n";
|
|
return;
|
|
}
|
|
}
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
}
|
|
|
|
static int i3cWriteRead(std::string& i3cDev, uint8_t wBuf[], uint16_t wLen,
|
|
uint8_t rBuf[], uint16_t rLen)
|
|
{
|
|
struct i3c_ioc_priv_xfer xfers[2];
|
|
int nxfers = 0;
|
|
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "i3c data to write:" << std::endl;
|
|
for(int i=0; i<wLen; i++)
|
|
{
|
|
std::cout << "wBuf[" << i << "]: 0x" << std::hex << (int)wBuf[i] << std::dec << " ";
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
int fd = open(i3cDev.c_str(), O_RDWR);
|
|
if (fd < 0)
|
|
{
|
|
std::cerr << " unable to open i3c device " << i3cDev << "\n";
|
|
goto err;
|
|
}
|
|
|
|
memset(xfers, 0, sizeof(xfers));
|
|
if (wLen)
|
|
{
|
|
xfers[nxfers].len = wLen;
|
|
xfers[nxfers].rnw = 0;
|
|
xfers[nxfers].data = (uintptr_t)wBuf;
|
|
nxfers++;
|
|
}
|
|
|
|
if (rLen)
|
|
{
|
|
xfers[nxfers].len = rLen;
|
|
xfers[nxfers].rnw = 1;
|
|
xfers[nxfers].data = (uintptr_t)rBuf;
|
|
nxfers++;
|
|
}
|
|
|
|
if (ioctl(fd, I3C_IOC_PRIV_XFER(nxfers), xfers) < 0) {
|
|
if constexpr (debug)
|
|
{
|
|
std::cerr << "i3c transfer failed "<< "\n";
|
|
}
|
|
goto err;
|
|
}
|
|
|
|
for (int i = 0; i < nxfers; i++) {
|
|
if (xfers[i].rnw) {
|
|
memcpy((void *)rBuf, (void *)(uintptr_t)xfers[i].data, xfers[i].len * sizeof(uint8_t));
|
|
}
|
|
}
|
|
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "i3c received data:\n";
|
|
for (int i = 0; i < (int)rLen; i++)
|
|
{
|
|
std::cout << "rBuf[" << i << "]: 0x" << std::hex << (int)rBuf[i] << std::dec << " ";
|
|
}
|
|
std::cout << "\n";
|
|
}
|
|
|
|
close(fd);
|
|
return 0;
|
|
|
|
err:
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
void DIMMSpdReader::startRead()
|
|
{
|
|
waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
|
|
waitTimer.async_wait([this](const boost::system::error_code& ec) {
|
|
if (ec == boost::asio::error::operation_aborted)
|
|
{
|
|
return; // we're being cancelled
|
|
}
|
|
// read timer error
|
|
if (ec)
|
|
{
|
|
std::cerr << "timer error\n";
|
|
return;
|
|
}
|
|
|
|
readDimmInfo();
|
|
updateDbus();
|
|
updateToDimmInfoFile();
|
|
if(regCounter == 0)
|
|
{
|
|
regCounter = 6000; //read status registers per 10 minutes.
|
|
}
|
|
else
|
|
{
|
|
regCounter--;
|
|
}
|
|
|
|
if(pmicCounter == 0)
|
|
{
|
|
pmicCounter = 300; //read status registers per 30s.
|
|
}
|
|
else
|
|
{
|
|
pmicCounter--;
|
|
}
|
|
|
|
startRead();
|
|
});
|
|
}
|
|
|
|
int DIMMSpdReader::getPmicType(uint8_t cpuid, uint8_t rank)
|
|
{
|
|
int ret = -1;
|
|
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
|
|
|
|
if(gotType[cpuid][rank]) return 0;
|
|
|
|
uint8_t index[] = {0xc8, 0xcc, 0xd0};
|
|
uint16_t wLen = 2;
|
|
//Jim debug uint8_t wrBuf[] = {0, 0};
|
|
uint8_t wrBuf[] = {0, 0, 0}; //Jim debug
|
|
uint8_t rdBuf[] = {0};
|
|
uint16_t rLen = 1;
|
|
int spd = NUM_TO_SPD(rank);
|
|
const uint8_t memReg = 0x80;
|
|
|
|
std::string i3cSpdName = I3C_ADDR(cpuid) + to_hex(spd);
|
|
|
|
wrBuf[0] = 0xb;
|
|
ret = i3cWriteRead(i3cSpdName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
size_t size = sizeof(index) / sizeof(index[0]);
|
|
for(size_t i = 0; i < size; i++)
|
|
{
|
|
|
|
wrBuf[0] = static_cast<uint8_t>(memReg | (index[i] & 0x40) | (index[i] & 0x3F));
|
|
wrBuf[1] = static_cast<uint8_t>((index[i] >> 7) & 0x0F);
|
|
|
|
ret = i3cWriteRead(i3cSpdName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if((rdBuf[0] & 0xf) == 0x6)
|
|
{
|
|
pmicType[cpuid][rank] = PMIC5030;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(pmicType[cpuid][rank] == PMIC5030)
|
|
{
|
|
twoByteMode[cpuid][rank] = true;
|
|
}
|
|
|
|
gotType[cpuid][rank] = true;
|
|
|
|
//Jim debug+S
|
|
|
|
//----------------------------------------------------------------------------
|
|
//A. 1B Write R30 = 0x84 // 1 byte format, set 2 byte mode
|
|
//B. 2B Read R0030 //check 2 byte mode
|
|
// if(R0030 == 0x84)
|
|
// 2 byte mode + 1ms delay: R30 success
|
|
// Else // Original 2 byte mode
|
|
// C. 2B Write R0030 = 0x84
|
|
// D. 2B Read R0030
|
|
// if(R0030 == 0x84) //check 2 byte mode
|
|
// 2 byte mode + 1ms delay: R30 success
|
|
if (pmicType[cpuid][rank] == PMIC5030)
|
|
{
|
|
|
|
int pmic = NUM_TO_PMIC(rank);
|
|
std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
|
|
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "is PMIC5030"<< std::endl;
|
|
}
|
|
// 1. 1B Write R30 = 0x84
|
|
wLen = 2;
|
|
rLen = 0;
|
|
wrBuf[0] = 0x30; wrBuf[1] = 0x84;
|
|
rdBuf[0] = 0x00;
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "first 1B Write R30 = 0x84" << std::endl;
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(9));
|
|
|
|
// 2. 2B Read R0030
|
|
wLen = 2;
|
|
rLen = 1;
|
|
wrBuf[0] = 0x30; wrBuf[1] = 0x00;
|
|
rdBuf[0] = 0x00;
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "2B Read R0030 = 0x" << std::hex << (int)rdBuf[0] << std::endl;
|
|
}
|
|
|
|
|
|
// Successful switch to 2 Byte mode
|
|
if(rdBuf[0] == 0x84)
|
|
{
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "Is 2 Byte mode" << std::endl;
|
|
}
|
|
}
|
|
// It was originally 2 bytes mode
|
|
else
|
|
{
|
|
//C2-2. 2B Write R30 = 0x84
|
|
wrBuf[0] = 0x30; wrBuf[1] = 0x00; wrBuf[2] = 0x84;
|
|
wLen = 3;
|
|
rLen = 0;
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(9));
|
|
//C2-2. 2B Read R30 = 0x84
|
|
wrBuf[0] = 0x30; wrBuf[1] = 0x00;
|
|
wLen = 2;
|
|
rLen = 1;
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "2B Read R0030 = " << std::hex << (int)rdBuf[0] << std::endl;
|
|
}
|
|
|
|
//Force the use of 1-byte mode
|
|
if(rdBuf[0] != 0x84)
|
|
{
|
|
twoByteMode[cpuid][rank] = false;
|
|
std::cout << "Force the use of 1-byte mode" << std::endl;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//Jim debug+E
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "pmicType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)pmicType[cpuid][rank] << std::endl;
|
|
std::cout << "gotType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)gotType[cpuid][rank] << std::endl;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int DIMMSpdReader::getDIMMRegsTemp(uint8_t cpuid, uint8_t rank, DimmData& dimmData)
|
|
{
|
|
int ret = -1;
|
|
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
|
|
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "Start to get DIMM temperature "<< std::endl;
|
|
}
|
|
|
|
uint8_t wrBuf[] = {0x31};
|
|
uint16_t wLen = 1;
|
|
uint8_t rdBuf[] = {0, 0};
|
|
uint16_t rLen = 2;
|
|
uint16_t integerPart;
|
|
uint16_t fractionalPart;
|
|
int spd = NUM_TO_SPD(rank);
|
|
|
|
#if 0
|
|
std::string i3cSpdName = I3C_ADDR(cpuid) + to_hex(spd);
|
|
ret = i3cWriteRead(i3cSpdName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
integerPart = ((rdBuf[0] & 0xf0) >> 4) | ((rdBuf[1] & 0x0f) << 4);
|
|
fractionalPart = (rdBuf[0] & 0x0C) >> 2;
|
|
|
|
// check if a negative reading
|
|
if (rdBuf[1] & 0x10)
|
|
{
|
|
uint16_t tmp = (integerPart << 2) | fractionalPart;
|
|
tmp = ((~tmp) & 0x3ff) + 1;
|
|
fractionalPart = tmp & 0x3;
|
|
integerPart = tmp >> 2;
|
|
dimmData.temp[2] = -1.0 * (integerPart + fractionalPart * 0.25);
|
|
}
|
|
else
|
|
{
|
|
dimmData.temp[2] = integerPart + fractionalPart * 0.25;
|
|
}
|
|
#endif
|
|
|
|
std::string i3cTS0Name = I3C_TS0_ADDR(cpuid) + to_hex(spd);
|
|
memset(rdBuf, 0, sizeof(rdBuf));
|
|
ret = i3cWriteRead(i3cTS0Name, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
integerPart = ((rdBuf[0] & 0xf0) >> 4) | ((rdBuf[1] & 0x0f) << 4);
|
|
fractionalPart = (rdBuf[0] & 0x0C) >> 2;
|
|
|
|
// check if a negative reading
|
|
if (rdBuf[1] & 0x10)
|
|
{
|
|
uint16_t tmp = (integerPart << 2) | fractionalPart;
|
|
tmp = ((~tmp) & 0x3ff) + 1;
|
|
fractionalPart = tmp & 0x3;
|
|
integerPart = tmp >> 2;
|
|
dimmData.temp[0] = -1.0 * (integerPart + fractionalPart * 0.25);
|
|
}
|
|
else
|
|
{
|
|
dimmData.temp[0] = integerPart + fractionalPart * 0.25;
|
|
}
|
|
|
|
std::string i3cTS1Name = I3C_TS1_ADDR(cpuid) + to_hex(spd);
|
|
memset(rdBuf, 0, sizeof(rdBuf));
|
|
ret = i3cWriteRead(i3cTS1Name, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
integerPart = ((rdBuf[0] & 0xf0) >> 4) | ((rdBuf[1] & 0x0f) << 4);
|
|
fractionalPart = (rdBuf[0] & 0x0C) >> 2;
|
|
|
|
// check if a negative reading
|
|
if (rdBuf[1] & 0x10)
|
|
{
|
|
uint16_t tmp = (integerPart << 2) | fractionalPart;
|
|
tmp = ((~tmp) & 0x3ff) + 1;
|
|
fractionalPart = tmp & 0x3;
|
|
integerPart = tmp >> 2;
|
|
dimmData.temp[1] = -1.0 * (integerPart + fractionalPart * 0.25);
|
|
}
|
|
else
|
|
{
|
|
dimmData.temp[1] = integerPart + fractionalPart * 0.25;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int DIMMSpdReader::getDIMMRegsVol(uint8_t cpuid, uint8_t rank, DimmData& dimmData)
|
|
{
|
|
int ret = -1;
|
|
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
|
|
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "Start to get DIMM voltage "<< std::endl;
|
|
std::cout << "pmicType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)pmicType[cpuid][rank] << std::endl;
|
|
}
|
|
|
|
uint16_t wLen;
|
|
uint16_t rLen;
|
|
uint8_t adcSel[6] = {0x80, 0x88, 0x90, 0x98, 0xa0, 0xd0};
|
|
uint8_t adcOut[] = {0x31, 0};
|
|
uint8_t rdBuf[] = {0};
|
|
uint8_t wrBuf[3] = {0x30, 0, 0};
|
|
uint8_t adcValue = 0;
|
|
|
|
int pmic = NUM_TO_PMIC(rank);
|
|
std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
|
|
|
|
rLen = 1;
|
|
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, &adcValue, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
adcValue &= 0x7;
|
|
int adcValue10 = (int)(adcValue & 0x3);
|
|
adcDelay[cpuid][rank] = getADCUpdateTime(adcValue10);
|
|
|
|
int index = (pmicType[cpuid][rank] == PMIC5030) ? 6 : 4;
|
|
for(int i=0; i<index; i++) {
|
|
//Write R30
|
|
rLen = 0; //Jim debug, For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
|
|
if(twoByteMode[cpuid][rank])
|
|
{
|
|
adcValue = 0x4; //Jim debug, PMIC5030 fixed the 2 byte mode + 1ms
|
|
wrBuf[2] = adcValue | adcSel[i];
|
|
wLen = 3;
|
|
}
|
|
else
|
|
{
|
|
wrBuf[1] = adcValue | adcSel[i];
|
|
wLen = 2;
|
|
}
|
|
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
//Jim debug std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
|
|
//Jim debug+S
|
|
// For Renesas requirements, the JESD spec PMIC5030 needs a 9ms delay.
|
|
if(pmicType[cpuid][rank] == PMIC5030)
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(9));
|
|
else
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
|
|
//Jim debug+E
|
|
|
|
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
|
|
rLen = 1;
|
|
rdBuf[0] = 0;
|
|
ret = i3cWriteRead(i3cPmicName, adcOut, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
dimmData.voltage[i] = rdBuf[0] * 15.0 / 1000.0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static double calStep31CurPower(int index, const uint8_t (&temp)[8])
|
|
{
|
|
if (index < 0 || index > 5)
|
|
return 0.0;
|
|
|
|
uint8_t reg;
|
|
uint8_t shift;
|
|
if(index < 4)
|
|
{
|
|
reg = temp[0];
|
|
shift = 6 - index * 2;
|
|
}
|
|
else
|
|
{
|
|
reg = temp[1];
|
|
shift = 6 - (index - 4) * 2;
|
|
}
|
|
|
|
uint8_t msb = (reg >> shift) & 0x03;
|
|
uint8_t lsb = temp[2 + index];
|
|
uint16_t raw10 = (static_cast<uint16_t>(msb) << 8) | lsb;
|
|
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "calStep31CurPower raw10: " << (int)raw10 << std::endl;
|
|
}
|
|
|
|
double result = std::round(raw10 * 31.25) / 1000.0;
|
|
return result;
|
|
}
|
|
|
|
|
|
int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& dimmData)
|
|
{
|
|
int ret = -1;
|
|
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
|
|
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "Start to get DIMM current and power "<< std::endl;
|
|
std::cout << "pmicType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)pmicType[cpuid][rank] << std::endl;
|
|
}
|
|
|
|
int index = 0;
|
|
uint16_t wLen;
|
|
uint16_t rLen = 1;
|
|
bool accStep31 = false;
|
|
|
|
uint8_t adcSelect[] = {0x1b, 0, 0};
|
|
uint16_t curOut[8];
|
|
uint8_t temp[8];
|
|
uint8_t rdBuf[] = {0, 0, 0, 0, 0, 0, 0, 0}; //Jim debug, For Renesas requirements, I3C command: Continuously read R100~R107
|
|
//Jim debug uint8_t rdBuf[] = {0};
|
|
uint8_t wrBuf[] = {0, 0};
|
|
|
|
int pmic = NUM_TO_PMIC(rank);
|
|
std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
|
|
|
|
if(pmicType[cpuid][rank] == PMIC5030)
|
|
{
|
|
uint8_t adcAcc[] = {0x32, 0};
|
|
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
|
|
ret = i3cWriteRead(i3cPmicName, adcAcc, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
//std::cerr << " read word data failed. \n";
|
|
return -1;
|
|
}
|
|
if((rdBuf[0] & 0x3) == 1) accStep31 = true;
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "accStep31: " << (int)accStep31 << std::endl;
|
|
}
|
|
}
|
|
|
|
if(accStep31)
|
|
{
|
|
index = 8;
|
|
for(int i=0; i<index; i++)
|
|
{
|
|
curOut[i] = 0x100 + i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
index = 4;
|
|
for(int i=0; i<index; i++)
|
|
{
|
|
curOut[i] = 0xc + i;
|
|
}
|
|
}
|
|
|
|
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
|
|
ret = i3cWriteRead(i3cPmicName, adcSelect, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if(twoByteMode[cpuid][rank])
|
|
{
|
|
adcSelect[2] = rdBuf[0] & 0xbf; //Read current
|
|
wLen = 3;
|
|
}
|
|
else
|
|
{
|
|
adcSelect[1] = rdBuf[0] & 0xbf; //Read current
|
|
wLen = 2;
|
|
}
|
|
rLen = 0; //Jim debug, For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
|
|
ret = i3cWriteRead(i3cPmicName, adcSelect, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
|
|
|
|
|
|
if(accStep31)
|
|
{
|
|
rLen = 8;
|
|
memset(rdBuf, 0, sizeof(rdBuf));
|
|
if(twoByteMode[cpuid][rank])
|
|
{
|
|
wrBuf[0] = static_cast<uint8_t>(curOut[0] & 0xFF);
|
|
wrBuf[1] = static_cast<uint8_t>((curOut[0] >> 8) & 0xFF);
|
|
wLen = 2;
|
|
}
|
|
else
|
|
{
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "twoByteMode[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)twoByteMode[cpuid][rank] << std::endl;
|
|
}
|
|
if(pmicType[cpuid][rank] == PMIC5030)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
for(int i=0; i<6; i++)
|
|
{
|
|
dimmData.current[i] = calStep31CurPower(i, temp);
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
for(int i=0; i<index; i++) {
|
|
temp[i] = rdBuf[i];
|
|
}
|
|
|
|
for(int i=0; i<6; i++)
|
|
{
|
|
dimmData.current[i] = calStep31CurPower(i, temp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int i=0; i<index; i++) {
|
|
rLen = 1;
|
|
rdBuf[0] = 0;
|
|
if(twoByteMode[cpuid][rank])
|
|
{
|
|
wrBuf[0] = static_cast<uint8_t>(curOut[i] & 0xFF);
|
|
wrBuf[1] = static_cast<uint8_t>((curOut[i] >> 8) & 0xFF);
|
|
wLen = 2;
|
|
}
|
|
else
|
|
{
|
|
wrBuf[0] = static_cast<uint8_t>(curOut[i]);
|
|
wLen = 1;
|
|
}
|
|
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
dimmData.current[i] = rdBuf[0] * 125.0 / 1000.0;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//start to read power
|
|
if(twoByteMode[cpuid][rank])
|
|
{
|
|
adcSelect[2] |= 0x40;
|
|
wLen = 3;
|
|
}
|
|
else
|
|
{
|
|
adcSelect[1] |= 0x40;
|
|
wLen = 2;
|
|
}
|
|
rLen = 0; //Jim debug, For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
|
|
ret = i3cWriteRead(i3cPmicName, adcSelect, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
|
|
|
|
// For Renesas requirements, I3C command: Continuously read R100~R107
|
|
if(accStep31)
|
|
{
|
|
rLen = 8;
|
|
memset(rdBuf, 0, sizeof(rdBuf));
|
|
if(twoByteMode[cpuid][rank])
|
|
{
|
|
wrBuf[0] = static_cast<uint8_t>(curOut[0] & 0xFF);
|
|
wrBuf[1] = static_cast<uint8_t>((curOut[0] >> 8) & 0xFF);
|
|
wLen = 2;
|
|
}
|
|
else
|
|
{
|
|
if constexpr (debug)
|
|
{
|
|
std::cout << "twoByteMode[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)twoByteMode[cpuid][rank] << std::endl;
|
|
}
|
|
if(pmicType[cpuid][rank] == PMIC5030)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
for(int i=0; i<6; i++)
|
|
{
|
|
dimmData.current[i] = calStep31CurPower(i, temp);
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
for(int i=0; i<index; i++) {
|
|
temp[i] = rdBuf[i];
|
|
}
|
|
|
|
for(int i=0; i<6; i++)
|
|
{
|
|
dimmData.power[i] = calStep31CurPower(i, temp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int i=0; i<index; i++)
|
|
{
|
|
rLen = 1;
|
|
rdBuf[0] = 0;
|
|
if(twoByteMode[cpuid][rank])
|
|
{
|
|
wrBuf[0] = static_cast<uint8_t>(curOut[i] & 0xFF);
|
|
wrBuf[1] = static_cast<uint8_t>((curOut[i] >> 8) & 0xFF);
|
|
wLen = 2;
|
|
}
|
|
else
|
|
{
|
|
wrBuf[0] = static_cast<uint8_t>(curOut[i]);
|
|
wLen = 1;
|
|
}
|
|
|
|
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
dimmData.power[i] = rdBuf[0] * 125.0 / 1000.0;
|
|
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int DIMMSpdReader::getPmicStatusRegs(uint8_t cpuid, uint8_t rank, DimmData& dimmData)
|
|
{
|
|
int ret = -1;
|
|
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
|
|
|
|
uint16_t wLen = 1;
|
|
uint16_t rLen = 1;
|
|
uint8_t reg[] = {0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb};
|
|
uint8_t rdBuf[] = {0};
|
|
|
|
int pmic = NUM_TO_PMIC(rank);
|
|
std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
|
|
|
|
size_t index = sizeof(reg) / sizeof(reg[0]);
|
|
for(size_t i=0; i<index; i++) {
|
|
ret = i3cWriteRead(i3cPmicName, ®[i], wLen, rdBuf, rLen);
|
|
if (ret < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
dimmData.reg[i] = rdBuf[0];
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(2));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void DIMMSpdReader::init()
|
|
{
|
|
for(int cpuid=0; cpuid<MAX_CPU_ID; cpuid++) {
|
|
for(int i=0; i<MAX_DIMM_RANK; i++) {
|
|
DimmData dData = {
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
|
|
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
|
|
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
|
|
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN()}};
|
|
|
|
std::string dimmName = "DIMM_CPU" + std::string(1, '0' + cpuid) + "_" + std::string(1, 'A' + i);
|
|
|
|
dimmDataTable.insert_or_assign(dimmName, std::move(dData));
|
|
|
|
pmicType[cpuid][i] = PMIC5010;
|
|
gotType[cpuid][i] = false;
|
|
twoByteMode[cpuid][i] = false;
|
|
}
|
|
}
|
|
|
|
regCounter = 0;
|
|
pmicCounter = 0;
|
|
updateDbus();
|
|
updateToDimmInfoFile();
|
|
}
|
|
|
|
void DIMMSpdReader::readDimmInfo()
|
|
{
|
|
int ret = -1;
|
|
|
|
for(int cpuid=0; cpuid<MAX_CPU_ID; cpuid++) {
|
|
for(int i=0; i<MAX_DIMM_RANK; i++) {
|
|
DimmData dData = {
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
|
|
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
|
|
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
|
|
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
|
|
std::numeric_limits<double>::quiet_NaN()}};
|
|
|
|
std::string dimmName = "DIMM_CPU" + std::string(1, '0' + cpuid) + "_" + std::string(1, 'A' + i);
|
|
|
|
int index = cpuid * 4 + i / 3;
|
|
if(index != lastIndex) {
|
|
setGPIOToSelectDimm(cfgGPIO[index]);
|
|
lastIndex = index;
|
|
}
|
|
|
|
ret = getPmicType(cpuid, i);
|
|
if (ret < 0)
|
|
{
|
|
if constexpr (debug)
|
|
{
|
|
std::cerr << " get cpu" << cpuid << " rank" << i << " PMIC Type failed. \n";
|
|
}
|
|
}
|
|
|
|
ret = getDIMMRegsTemp(cpuid, i, dData);
|
|
if (ret < 0)
|
|
{
|
|
if constexpr (debug)
|
|
{
|
|
std::cerr << " read cpu" << cpuid << " rank" << i << " dimm temp failed. \n";
|
|
}
|
|
}
|
|
updateField(dimmName, TEMP, dData.temp, STATUS_TEMP_NUM);
|
|
#if 1
|
|
if(regCounter == 0)
|
|
{
|
|
ret = getPmicStatusRegs(cpuid, i, dData);
|
|
if (ret < 0)
|
|
{
|
|
if constexpr (debug)
|
|
{
|
|
std::cerr << " read cpu" << cpuid << " rank" << i << " status registers failed. \n";
|
|
}
|
|
}
|
|
|
|
updateField(dimmName, STATUS, dData.reg, STATUS_REG_NUM);
|
|
}
|
|
|
|
if(pmicCounter == 0)
|
|
{
|
|
ret = getDIMMRegsVol(cpuid, i, dData);
|
|
if (ret < 0)
|
|
{
|
|
if constexpr (debug)
|
|
{
|
|
std::cerr << " read cpu" << cpuid << " rank" << i << " dimm voltage failed. \n";
|
|
}
|
|
}
|
|
|
|
updateField(dimmName, VOLTAGE, dData.voltage, STATUS_PMIC_RAIL_NUM);
|
|
|
|
ret = getDIMMRegsCurAndPow(cpuid, i, dData);
|
|
if (ret < 0)
|
|
{
|
|
if constexpr (debug)
|
|
{
|
|
std::cerr << " read cpu" << cpuid << " rank" << i << " dimm current and power failed. \n";
|
|
}
|
|
|
|
}
|
|
|
|
updateField(dimmName, CURRENT, dData.current, STATUS_PMIC_RAIL_NUM);
|
|
updateField(dimmName, POWER, dData.power, STATUS_PMIC_RAIL_NUM);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void DIMMSpdReader::updateDbus()
|
|
{
|
|
for(auto data : dimmDataTable) {
|
|
if(dimm_temp_inf.find(data.first) != dimm_temp_inf.end()) {
|
|
dimm_temp_inf[data.first]->set_property("TS0", data.second.temp[0]);
|
|
dimm_temp_inf[data.first]->set_property("TS1", data.second.temp[1]);
|
|
dimm_temp_inf[data.first]->set_property("SPD_TS", data.second.temp[2]);
|
|
}
|
|
|
|
if(dimm_voltage_inf.find(data.first) != dimm_voltage_inf.end()) {
|
|
dimm_voltage_inf[data.first]->set_property("SWA", data.second.voltage[0]);
|
|
dimm_voltage_inf[data.first]->set_property("SWB", data.second.voltage[1]);
|
|
dimm_voltage_inf[data.first]->set_property("SWC", data.second.voltage[2]);
|
|
dimm_voltage_inf[data.first]->set_property("SWD", data.second.voltage[3]);
|
|
dimm_voltage_inf[data.first]->set_property("SWE", data.second.voltage[4]);
|
|
dimm_voltage_inf[data.first]->set_property("SWF", data.second.voltage[5]);
|
|
|
|
}
|
|
|
|
if(dimm_current_inf.find(data.first) != dimm_current_inf.end()) {
|
|
dimm_current_inf[data.first]->set_property("SWA", data.second.current[0]);
|
|
dimm_current_inf[data.first]->set_property("SWB", data.second.current[1]);
|
|
dimm_current_inf[data.first]->set_property("SWC", data.second.current[2]);
|
|
dimm_current_inf[data.first]->set_property("SWD", data.second.current[3]);
|
|
dimm_current_inf[data.first]->set_property("SWE", data.second.current[4]);
|
|
dimm_current_inf[data.first]->set_property("SWF", data.second.current[5]);
|
|
}
|
|
|
|
if(dimm_power_inf.find(data.first) != dimm_power_inf.end()) {
|
|
dimm_power_inf[data.first]->set_property("SWA", data.second.power[0]);
|
|
dimm_power_inf[data.first]->set_property("SWB", data.second.power[1]);
|
|
dimm_power_inf[data.first]->set_property("SWC", data.second.power[2]);
|
|
dimm_power_inf[data.first]->set_property("SWD", data.second.power[3]);
|
|
dimm_power_inf[data.first]->set_property("SWE", data.second.power[4]);
|
|
dimm_power_inf[data.first]->set_property("SWF", data.second.power[5]);
|
|
}
|
|
|
|
if(dimm_statusReg_inf.find(data.first) != dimm_statusReg_inf.end()) {
|
|
dimm_statusReg_inf[data.first]->set_property("0x04", data.second.reg[0]);
|
|
dimm_statusReg_inf[data.first]->set_property("0x05", data.second.reg[1]);
|
|
dimm_statusReg_inf[data.first]->set_property("0x06", data.second.reg[2]);
|
|
dimm_statusReg_inf[data.first]->set_property("0x07", data.second.reg[3]);
|
|
dimm_statusReg_inf[data.first]->set_property("0x08", data.second.reg[4]);
|
|
dimm_statusReg_inf[data.first]->set_property("0x09", data.second.reg[5]);
|
|
dimm_statusReg_inf[data.first]->set_property("0x0a", data.second.reg[6]);
|
|
dimm_statusReg_inf[data.first]->set_property("0x0b", data.second.reg[7]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DIMMSpdReader::updateToDimmInfoFile()
|
|
{
|
|
const std::filesystem::path outputPath(dimmInfoPath);
|
|
std::ofstream jsonOutputFile(outputPath);
|
|
if (!jsonOutputFile.is_open()) {
|
|
std::cout << "Failed to open dimmInfo json file" << std::endl;
|
|
return;
|
|
}
|
|
|
|
nlohmann::json js;
|
|
std::string timestamp = get_current_timestamp();
|
|
js["Current Time"] = timestamp;
|
|
//std::cout << "timestamp: " << timestamp << std::endl;
|
|
|
|
for(auto data : dimmDataTable) {
|
|
//update temperature
|
|
js[data.first]["Temperature_DegreesC"]["TS0"] = data.second.temp[0];
|
|
js[data.first]["Temperature_DegreesC"]["TS1"] = data.second.temp[1];
|
|
js[data.first]["Temperature_DegreesC"]["SPD_TS"] = data.second.temp[2];
|
|
|
|
//update voltage
|
|
js[data.first]["Voltage_Volt"]["SWA"] = data.second.voltage[0];
|
|
js[data.first]["Voltage_Volt"]["SWB"] = data.second.voltage[1];
|
|
js[data.first]["Voltage_Volt"]["SWC"] = data.second.voltage[2];
|
|
js[data.first]["Voltage_Volt"]["SWD"] = data.second.voltage[3];
|
|
js[data.first]["Voltage_Volt"]["SWE"] = data.second.voltage[4];
|
|
js[data.first]["Voltage_Volt"]["SWF"] = data.second.voltage[5];
|
|
//update current
|
|
js[data.first]["Current_Ampere"]["SWA"] = data.second.current[0];
|
|
js[data.first]["Current_Ampere"]["SWB"] = data.second.current[1];
|
|
js[data.first]["Current_Ampere"]["SWC"] = data.second.current[2];
|
|
js[data.first]["Current_Ampere"]["SWD"] = data.second.current[3];
|
|
js[data.first]["Current_Ampere"]["SWE"] = data.second.current[4];
|
|
js[data.first]["Current_Ampere"]["SWF"] = data.second.current[5];
|
|
//update power
|
|
js[data.first]["Power_Watt"]["SWA"] = data.second.power[0];
|
|
js[data.first]["Power_Watt"]["SWB"] = data.second.power[1];
|
|
js[data.first]["Power_Watt"]["SWC"] = data.second.power[2];
|
|
js[data.first]["Power_Watt"]["SWD"] = data.second.power[3];
|
|
js[data.first]["Power_Watt"]["SWE"] = data.second.power[4];
|
|
js[data.first]["Power_Watt"]["SWF"] = data.second.power[5];
|
|
|
|
//update status registers
|
|
js[data.first]["Status_Reg"]["0x04"] = data.second.reg[0];
|
|
js[data.first]["Status_Reg"]["0x05"] = data.second.reg[1];
|
|
js[data.first]["Status_Reg"]["0x06"] = data.second.reg[2];
|
|
js[data.first]["Status_Reg"]["0x07"] = data.second.reg[3];
|
|
js[data.first]["Status_Reg"]["0x08"] = data.second.reg[4];
|
|
js[data.first]["Status_Reg"]["0x09"] = data.second.reg[5];
|
|
js[data.first]["Status_Reg"]["0x0a"] = data.second.reg[6];
|
|
js[data.first]["Status_Reg"]["0x0b"] = data.second.reg[7];
|
|
}
|
|
|
|
jsonOutputFile << js.dump(4);
|
|
return;
|
|
}
|
|
|
|
void DIMMSpdReader::setupMatches(sdbusplus::bus_t& connection)
|
|
{
|
|
std::weak_ptr<DIMMSpdReader> weakRef = weak_from_this();
|
|
std::shared_ptr<DIMMSpdReader> sharedRef = weakRef.lock();
|
|
dimmI3cSwitchMatcher(matches, connection, [sharedRef](bool state)
|
|
{
|
|
if (!sharedRef)
|
|
{
|
|
return;
|
|
}
|
|
if (!state)
|
|
{
|
|
//switch dimm i3c to bios
|
|
sharedRef->waitTimer.cancel();
|
|
sharedRef->init();
|
|
std::cout << "waitTimer canceled" << std::endl;
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
int ret = system("rmmod dw-i3c-master");
|
|
if (ret != 0) {
|
|
std::cout << "Failed to rmmod dw-i3c-master module" << std::endl;
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
}
|
|
else
|
|
{
|
|
int ret = system("modprobe dw-i3c-master");
|
|
if (ret != 0) {
|
|
std::cout << "Failed to modprobe dw-i3c-master module" << std::endl;
|
|
return;
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
//switch dimm i3c to bmc
|
|
std::cout << "start to Read" << std::endl;
|
|
sharedRef->startRead();
|
|
}
|
|
});
|
|
}
|