Prep CPU sensor for no-overlays Get data from comparing bus and address from sysfs Change-Id: Ibef93f6921ab26602ff970b0ee1e32a64d5c5717 Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
diff --git a/include/CPUSensor.hpp b/include/CPUSensor.hpp index 8f7d2f0..4229801 100644 --- a/include/CPUSensor.hpp +++ b/include/CPUSensor.hpp
@@ -6,12 +6,24 @@ class CPUSensor : public Sensor { + public: + std::string name; + std::string configuration; + CPUSensor(const std::string &path, const std::string &objectType, + sdbusplus::asio::object_server &object_server, + std::shared_ptr<sdbusplus::asio::connection> &conn, + boost::asio::io_service &io, const std::string &fan_name, + std::vector<thresholds::Threshold> &&thresholds, + const std::string &configuration); + ~CPUSensor(); + constexpr static unsigned int SENSOR_SCALE_FACTOR = 1000; + constexpr static unsigned int SENSOR_POLL_MS = 1000; + private: std::string path; std::string objectType; sdbusplus::asio::object_server &objServer; std::shared_ptr<sdbusplus::asio::connection> dbusConnection; - std::string name; boost::asio::posix::stream_descriptor input_dev; boost::asio::deadline_timer wait_timer; boost::asio::streambuf read_buf; @@ -25,16 +37,4 @@ void set_initial_properties( std::shared_ptr<sdbusplus::asio::connection> &conn); - - public: - std::string configuration; - CPUSensor(const std::string &path, const std::string &objectType, - sdbusplus::asio::object_server &object_server, - std::shared_ptr<sdbusplus::asio::connection> &conn, - boost::asio::io_service &io, const std::string &fan_name, - std::vector<thresholds::Threshold> &&thresholds, - const std::string &configuration); - ~CPUSensor(); - constexpr static unsigned int SENSOR_SCALE_FACTOR = 1000; - constexpr static unsigned int SENSOR_POLL_MS = 1000; };
diff --git a/src/CPUSensorMain.cpp b/src/CPUSensorMain.cpp index cc9fb91..fb0ede4 100644 --- a/src/CPUSensorMain.cpp +++ b/src/CPUSensorMain.cpp
@@ -42,24 +42,23 @@ struct CPUConfig { - CPUConfig(const int& address, const std::string& overlayName, - const State& st) : - addr(address), - ovName(overlayName), state(st) + CPUConfig(const uint64_t& bus, const uint64_t& addr, + const std::string& name, const State& state) : + bus(bus), + addr(addr), name(name), state(state) { } + int bus; int addr; - std::string ovName; + std::string name; State state; bool operator<(const CPUConfig& rhs) const { - return (ovName < rhs.ovName); + return (name < rhs.name); } }; -static constexpr const char* DT_OVERLAY = "/usr/bin/dtoverlay"; -static constexpr const char* OVERLAY_DIR = "/tmp/overlays"; static constexpr const char* PECI_DEV = "/dev/peci-0"; static constexpr const unsigned int RANK_NUM_MAX = 8; @@ -107,86 +106,140 @@ useCache = true; } - std::vector<fs::path> oemNamePaths; + std::vector<fs::path> hwmonNamePaths; if (!find_files(fs::path(R"(/sys/bus/peci/devices)"), - R"(peci-\d+/\d+-.+/of_node/oemname1$)", oemNamePaths, 2)) + R"(peci-\d+/\d+-.+/peci-.+/hwmon/hwmon\d+/name$)", + hwmonNamePaths, 1)) { std::cerr << "No CPU sensors in system\n"; return true; } - for (fs::path& oemNamePath : oemNamePaths) + boost::container::flat_set<std::string> scannedDirectories; + boost::container::flat_set<std::string> createdSensors; + + for (fs::path& hwmonNamePath : hwmonNamePaths) { - std::ifstream nameFile(oemNamePath); - if (!nameFile.good()) + const std::string& pathStr = hwmonNamePath.string(); + auto hwmonDirectory = hwmonNamePath.parent_path(); + + auto ret = scannedDirectories.insert(hwmonDirectory.string()); + if (!ret.second) { - std::cerr << "Failure reading " << oemNamePath << "\n"; + continue; // already searched this path + } + + fs::path::iterator it = hwmonNamePath.begin(); + std::advance(it, 6); // pick the 6th part for a PECI client device name + std::string deviceName = *it; + auto findHyphen = deviceName.find("-"); + if (findHyphen == std::string::npos) + { + std::cerr << "found bad device " << deviceName << "\n"; continue; } - std::string oemName; - std::getline(nameFile, oemName); + std::string busStr = deviceName.substr(0, findHyphen); + std::string addrStr = deviceName.substr(findHyphen + 1); + + size_t bus = 0; + size_t addr = 0; + try + { + bus = std::stoi(busStr); + addr = std::stoi(addrStr, 0, 16); + } + catch (std::invalid_argument) + { + continue; + } + + std::ifstream nameFile(hwmonNamePath); + if (!nameFile.good()) + { + std::cerr << "Failure reading " << hwmonNamePath << "\n"; + continue; + } + std::string hwmonName; + std::getline(nameFile, hwmonName); nameFile.close(); - if (!oemName.size()) + if (!hwmonName.size()) { // shouldn't have an empty name file continue; } - oemName.pop_back(); // remove trailing null if (DEBUG) - std::cout << "Checking: " << oemNamePath << ": " << oemName << "\n"; + { + std::cout << "Checking: " << hwmonNamePath << ": " << hwmonName + << "\n"; + } + std::string sensorType; const SensorData* sensorData = nullptr; const std::string* interfacePath = nullptr; - for (const std::pair<sdbusplus::message::object_path, SensorData>& - sensor : sensorConfigurations) - { - if (!boost::ends_with(sensor.first.str, oemName)) - { - continue; - } - sensorData = &(sensor.second); - interfacePath = &(sensor.first.str); - break; - } - if (sensorData == nullptr) - { - std::cerr << "failed to find match for " << oemName << "\n"; - continue; - } const std::pair<std::string, boost::container::flat_map< std::string, BasicVariantType>>* baseConfiguration = nullptr; - std::string sensorObjectType; - for (const char* type : SENSOR_TYPES) - { - sensorObjectType = CONFIG_PREFIX + std::string(type); - auto sensorBase = sensorData->find(sensorObjectType); - if (sensorBase != sensorData->end()) - { - baseConfiguration = &(*sensorBase); - break; - } - } - if (baseConfiguration == nullptr) + for (const std::pair<sdbusplus::message::object_path, SensorData>& + sensor : sensorConfigurations) { - std::cerr << "error finding base configuration for" << oemName - << "\n"; + sensorData = &(sensor.second); + for (const char* type : SENSOR_TYPES) + { + sensorType = CONFIG_PREFIX + std::string(type); + auto sensorBase = sensorData->find(sensorType); + if (sensorBase != sensorData->end()) + { + baseConfiguration = &(*sensorBase); + break; + } + } + if (baseConfiguration == nullptr) + { + std::cerr << "error finding base configuration for" << hwmonName + << "\n"; + continue; + } + auto configurationBus = baseConfiguration->second.find("Bus"); + auto configurationAddress = + baseConfiguration->second.find("Address"); + + if (configurationBus == baseConfiguration->second.end() || + configurationAddress == baseConfiguration->second.end()) + { + std::cerr << "error finding bus or address in configuration"; + continue; + } + + if (sdbusplus::message::variant_ns::get<uint64_t>( + configurationBus->second) != bus || + sdbusplus::message::variant_ns::get<uint64_t>( + configurationAddress->second) != addr) + { + continue; + } + + interfacePath = &(sensor.first.str); + break; + } + if (interfacePath == nullptr) + { + std::cerr << "failed to find match for " << hwmonName << "\n"; continue; } auto findCpuId = baseConfiguration->second.find("CpuID"); if (findCpuId == baseConfiguration->second.end()) { - std::cerr << "could not determine CPU ID for " << oemName << "\n"; + std::cerr << "could not determine CPU ID for " << hwmonName << "\n"; continue; } - int cpuId = variant_ns::visit(VariantToIntVisitor(), findCpuId->second); + int cpuId = + variant_ns::visit(VariantToUnsignedIntVisitor(), findCpuId->second); - auto directory = oemNamePath.parent_path().parent_path(); + auto directory = hwmonNamePath.parent_path(); std::vector<fs::path> inputPaths; - if (!find_files(fs::path(directory), - R"(peci-.+/hwmon/hwmon\d+/temp\d+_input$)", inputPaths, + if (!find_files(fs::path(directory), R"(temp\d+_input$)", inputPaths, 0)) { std::cerr << "No temperature sensors in system\n"; @@ -209,6 +262,18 @@ std::getline(labelFile, label); labelFile.close(); std::string sensorName = label + " CPU" + std::to_string(cpuId); + + auto findSensor = sensors.find(sensorName); + if (findSensor != sensors.end()) + { + if (DEBUG) + { + std::cout << "Skipped: " << inputPath << ": " << sensorName + << " is already created\n"; + } + continue; + } + std::vector<thresholds::Threshold> sensorThresholds; std::string labelHead = label.substr(0, label.find(" ")); ParseThresholdsFromConfig(*sensorData, sensorThresholds, @@ -223,42 +288,69 @@ } } sensors[sensorName] = std::make_unique<CPUSensor>( - inputPathStr, sensorObjectType, objectServer, dbusConnection, - io, sensorName, std::move(sensorThresholds), *interfacePath); + inputPathStr, sensorType, objectServer, dbusConnection, io, + sensorName, std::move(sensorThresholds), *interfacePath); + createdSensors.insert(sensorName); if (DEBUG) + { std::cout << "Mapped: " << inputPath << " to " << sensorName << "\n"; + } } } - std::cout << "Sensor creation completed\n"; + if (createdSensors.size()) + { + std::cout << "Sensor" << (createdSensors.size() == 1 ? " is" : "s are") + << " created\n"; + } return true; } -void reloadOverlay(const std::string& overlay) +void exportDevice(const CPUConfig& config) { - boost::process::child c1(DT_OVERLAY, "-d", OVERLAY_DIR, "-r", overlay); - c1.wait(); - if (c1.exit_code()) + std::ostringstream hex; + hex << std::hex << config.addr; + const std::string& addrHexStr = hex.str(); + std::string busStr = std::to_string(config.bus); + + std::string parameters = "peci-client 0x" + addrHexStr; + std::string device = "/sys/bus/peci/devices/peci-" + busStr + "/new_device"; + + std::experimental::filesystem::path devicePath(device); + const std::string& dir = devicePath.parent_path().string(); + for (const auto& path : + std::experimental::filesystem::directory_iterator(dir)) { - if (DEBUG) + if (!std::experimental::filesystem::is_directory(path)) { - std::cout << "DTOverlay unload error with file " << overlay - << ". error: " << c1.exit_code() << "\n"; + continue; } - /* fall through anyway */ + const std::string& directoryName = path.path().filename(); + if (boost::starts_with(directoryName, busStr) && + boost::ends_with(directoryName, addrHexStr)) + { + if (DEBUG) + { + std::cout << parameters << " on bus " << busStr + << " is already exported\n"; + } + return; + } } - boost::process::child c2(DT_OVERLAY, "-d", OVERLAY_DIR, overlay); - c2.wait(); - if (c2.exit_code()) + std::ofstream deviceFile(device); + if (!deviceFile.good()) { - std::cerr << "DTOverlay load error with file " << overlay - << ". error: " << c2.exit_code() << "\n"; + std::cerr << "Error writing " << device << "\n"; return; } + deviceFile << parameters; + deviceFile.close(); + + std::cout << parameters << " on bus " << busStr << " is exported\n"; } void detectCpu(boost::asio::deadline_timer& timer, boost::asio::io_service& io, @@ -325,12 +417,12 @@ { if (config.state == State::OFF) { - std::cout << config.ovName << " is detected\n"; - reloadOverlay(config.ovName); + std::cout << config.name << " is detected\n"; + exportDevice(config); } if (state == State::READY) { - std::cout << "DIMM(s) on " << config.ovName + std::cout << "DIMM(s) on " << config.name << " is/are detected\n"; } config.state = state; @@ -354,7 +446,9 @@ } if (DEBUG) - std::cout << config.ovName << ", state: " << config.state << "\n"; + { + std::cout << config.name << ", state: " << config.state << "\n"; + } } close(file); @@ -388,7 +482,7 @@ } } -void getCpuConfig(const std::shared_ptr<sdbusplus::asio::connection>& systemBus, +bool getCpuConfig(const std::shared_ptr<sdbusplus::asio::connection>& systemBus, boost::container::flat_set<CPUConfig>& configs) { ManagedObjectType sensorConfigurations; @@ -399,7 +493,7 @@ if (!getSensorConfiguration(CONFIG_PREFIX + std::string(type), systemBus, sensorConfigurations, useCache)) { - return; + return false; } useCache = true; } @@ -421,14 +515,6 @@ continue; } - auto findAddress = config.second.find("Address"); - if (findAddress == config.second.end()) - { - continue; - } - int addr = variant_ns::visit(VariantToIntVisitor(), - findAddress->second); - auto findName = config.second.find("Name"); if (findName == config.second.end()) { @@ -438,22 +524,47 @@ VariantToStringVisitor(), findName->second); std::string name = std::regex_replace(nameRaw, ILLEGAL_NAME_REGEX, "_"); - std::string overlayName = name + "_" + type; + + auto findBus = config.second.find("Bus"); + if (findBus == config.second.end()) + { + std::cerr << "Can't find 'Bus' setting in " << name << "\n"; + continue; + } + uint64_t bus = variant_ns::visit(VariantToUnsignedIntVisitor(), + findBus->second); + + auto findAddress = config.second.find("Address"); + if (findAddress == config.second.end()) + { + std::cerr << "Can't find 'Address' setting in " << name + << "\n"; + continue; + } + uint64_t addr = variant_ns::visit(VariantToUnsignedIntVisitor(), + findAddress->second); if (DEBUG) { + std::cout << "bus: " << bus << "\n"; std::cout << "addr: " << addr << "\n"; std::cout << "name: " << name << "\n"; std::cout << "type: " << type << "\n"; - std::cout << "overlayName: " << overlayName << "\n"; } - configs.emplace(addr, overlayName, State::OFF); + configs.emplace(bus, addr, name, State::OFF); } } } - std::cout << "CPU configs parsed\n"; + if (configs.size()) + { + std::cout << "CPU config" << (configs.size() == 1 ? " is" : "s are") + << " parsed\n"; + return true; + } + + return false; } int main(int argc, char** argv) @@ -467,13 +578,27 @@ boost::container::flat_map<std::string, std::unique_ptr<CPUSensor>> sensors; std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches; boost::asio::deadline_timer pingTimer(io); - getCpuConfig(systemBus, configs); - if (configs.size()) - { - detectCpu(pingTimer, io, objectServer, sensors, configs, systemBus); - } - boost::asio::deadline_timer filterTimer(io); + + filterTimer.expires_from_now(boost::posix_time::seconds(1)); + filterTimer.async_wait([&](const boost::system::error_code& ec) { + if (ec == boost::asio::error::operation_aborted) + { + /* we were canceled*/ + return; + } + else if (ec) + { + std::cerr << "timer error\n"; + return; + } + + if (getCpuConfig(systemBus, configs)) + { + detectCpu(pingTimer, io, objectServer, sensors, configs, systemBus); + } + }); + std::function<void(sdbusplus::message::message&)> eventHandler = [&](sdbusplus::message::message& message) { if (message.is_method_error()) @@ -481,9 +606,14 @@ std::cerr << "callback method error\n"; return; } + + if (DEBUG) + { + std::cout << message.get_path() << " is changed\n"; + } + // this implicitly cancels the timer filterTimer.expires_from_now(boost::posix_time::seconds(1)); - filterTimer.async_wait([&](const boost::system::error_code& ec) { if (ec == boost::asio::error::operation_aborted) { @@ -496,9 +626,7 @@ return; } - getCpuConfig(systemBus, configs); - - if (configs.size()) + if (getCpuConfig(systemBus, configs)) { detectCpu(pingTimer, io, objectServer, sensors, configs, systemBus);