1 #include <experimental/filesystem> 2 #include <phosphor-logging/log.hpp> 3 #include <phosphor-logging/elog-errors.hpp> 4 #include <xyz/openbmc_project/Common/error.hpp> 5 #include "occ_finder.hpp" 6 #include "occ_manager.hpp" 7 #include "i2c_occ.hpp" 8 #include "utils.hpp" 9 #include "config.h" 10 11 namespace open_power 12 { 13 namespace occ 14 { 15 16 void Manager::findAndCreateObjects() 17 { 18 for (auto id = 0; id < MAX_CPUS; ++id) 19 { 20 // Create one occ per cpu 21 auto occ = std::string(OCC_NAME) + std::to_string(id); 22 createObjects(occ); 23 } 24 } 25 26 int Manager::cpuCreated(sdbusplus::message::message& msg) 27 { 28 namespace fs = std::experimental::filesystem; 29 30 sdbusplus::message::object_path o; 31 msg.read(o); 32 fs::path cpuPath(std::string(std::move(o))); 33 34 auto name = cpuPath.filename().string(); 35 auto index = name.find(CPU_NAME); 36 name.replace(index, std::strlen(CPU_NAME), OCC_NAME); 37 38 createObjects(name); 39 40 return 0; 41 } 42 43 void Manager::createObjects(const std::string& occ) 44 { 45 auto path = fs::path(OCC_CONTROL_ROOT) / occ; 46 47 passThroughObjects.emplace_back( 48 std::make_unique<PassThrough>( 49 bus, 50 path.c_str())); 51 52 statusObjects.emplace_back( 53 std::make_unique<Status>( 54 bus, 55 event, 56 path.c_str(), 57 *this, 58 std::bind(std::mem_fn(&Manager::statusCallBack), 59 this, std::placeholders::_1))); 60 61 // Create the power cap monitor object for master occ (0) 62 if (!pcap) 63 { 64 pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 65 bus, 66 *statusObjects.front()); 67 } 68 } 69 70 void Manager::statusCallBack(bool status) 71 { 72 using namespace phosphor::logging; 73 using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 74 Error::InternalFailure; 75 76 // At this time, it won't happen but keeping it 77 // here just in case something changes in the future 78 if ((activeCount == 0) && (!status)) 79 { 80 log<level::ERR>("Invalid update on OCCActive"); 81 elog<InternalFailure>(); 82 } 83 84 activeCount += status ? 1 : -1; 85 86 // If all the OCCs are bound, then start error detection 87 if (activeCount == statusObjects.size()) 88 { 89 for (const auto& occ: statusObjects) 90 { 91 occ->addErrorWatch(); 92 } 93 } 94 else if (!status) 95 { 96 // If some OCCs are not bound yet, those will be a NO-OP 97 for (const auto& occ: statusObjects) 98 { 99 occ->removeErrorWatch(); 100 } 101 } 102 } 103 104 #ifdef I2C_OCC 105 void Manager::initStatusObjects() 106 { 107 // Make sure we have a valid path string 108 static_assert(sizeof(DEV_PATH) != 0); 109 110 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH); 111 auto occMasterName = deviceNames.front(); 112 for (auto& name : deviceNames) 113 { 114 i2c_occ::i2cToDbus(name); 115 name = std::string(OCC_NAME) + '_' + name; 116 auto path = fs::path(OCC_CONTROL_ROOT) / name; 117 statusObjects.emplace_back( 118 std::make_unique<Status>( 119 bus, 120 event, 121 path.c_str(), 122 *this)); 123 } 124 // The first device is master occ 125 pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 126 bus, 127 *statusObjects.front(), 128 occMasterName); 129 } 130 #endif 131 132 } // namespace occ 133 } // namespace open_power 134