1 #include "config.h" 2 3 #include "occ_manager.hpp" 4 5 #include "i2c_occ.hpp" 6 #include "utils.hpp" 7 8 #include <experimental/filesystem> 9 #include <phosphor-logging/elog-errors.hpp> 10 #include <phosphor-logging/log.hpp> 11 #include <xyz/openbmc_project/Common/error.hpp> 12 13 namespace open_power 14 { 15 namespace occ 16 { 17 18 using namespace phosphor::logging; 19 20 void Manager::findAndCreateObjects() 21 { 22 for (auto id = 0; id < MAX_CPUS; ++id) 23 { 24 // Create one occ per cpu 25 auto occ = std::string(OCC_NAME) + std::to_string(id); 26 createObjects(occ); 27 } 28 } 29 30 int Manager::cpuCreated(sdbusplus::message::message& msg) 31 { 32 namespace fs = std::experimental::filesystem; 33 34 sdbusplus::message::object_path o; 35 msg.read(o); 36 fs::path cpuPath(std::string(std::move(o))); 37 38 auto name = cpuPath.filename().string(); 39 auto index = name.find(CPU_NAME); 40 name.replace(index, std::strlen(CPU_NAME), OCC_NAME); 41 42 createObjects(name); 43 44 return 0; 45 } 46 47 void Manager::createObjects(const std::string& occ) 48 { 49 auto path = fs::path(OCC_CONTROL_ROOT) / occ; 50 51 passThroughObjects.emplace_back( 52 std::make_unique<PassThrough>(path.c_str())); 53 54 statusObjects.emplace_back(std::make_unique<Status>( 55 event, path.c_str(), *this, 56 std::bind(std::mem_fn(&Manager::statusCallBack), this, 57 std::placeholders::_1) 58 #ifdef PLDM 59 , 60 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(), 61 std::placeholders::_1) 62 #endif 63 )); 64 65 // Create the power cap monitor object for master occ (0) 66 if (!pcap) 67 { 68 pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 69 *statusObjects.front()); 70 } 71 } 72 73 void Manager::statusCallBack(bool status) 74 { 75 using InternalFailure = 76 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 77 78 // At this time, it won't happen but keeping it 79 // here just in case something changes in the future 80 if ((activeCount == 0) && (!status)) 81 { 82 log<level::ERR>("Invalid update on OCCActive"); 83 elog<InternalFailure>(); 84 } 85 86 activeCount += status ? 1 : -1; 87 88 // Only start presence detection if all the OCCs are bound 89 if (activeCount == statusObjects.size()) 90 { 91 for (auto& obj : statusObjects) 92 { 93 obj->addPresenceWatchMaster(); 94 } 95 } 96 97 if ((!_pollTimer->isEnabled()) && (activeCount > 0)) 98 { 99 log<level::INFO>(fmt::format("Manager::statusCallBack(): {} OCCs will " 100 "be polled every {} seconds", 101 activeCount, pollInterval) 102 .c_str()); 103 104 // Send poll and start OCC poll timer 105 pollerTimerExpired(); 106 } 107 else if ((_pollTimer->isEnabled()) && (activeCount == 0)) 108 { 109 // Stop OCC poll timer 110 log<level::INFO>("Manager::statusCallBack(): OCCs are not running, " 111 "stopping poll timer"); 112 _pollTimer->setEnabled(false); 113 } 114 } 115 116 #ifdef I2C_OCC 117 void Manager::initStatusObjects() 118 { 119 // Make sure we have a valid path string 120 static_assert(sizeof(DEV_PATH) != 0); 121 122 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH); 123 auto occMasterName = deviceNames.front(); 124 for (auto& name : deviceNames) 125 { 126 i2c_occ::i2cToDbus(name); 127 name = std::string(OCC_NAME) + '_' + name; 128 auto path = fs::path(OCC_CONTROL_ROOT) / name; 129 statusObjects.emplace_back( 130 std::make_unique<Status>(event, path.c_str(), *this)); 131 } 132 // The first device is master occ 133 pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 134 *statusObjects.front(), occMasterName); 135 } 136 #endif 137 138 #ifdef PLDM 139 bool Manager::updateOCCActive(instanceID instance, bool status) 140 { 141 return (statusObjects[instance])->occActive(status); 142 } 143 #endif 144 145 void Manager::pollerTimerExpired() 146 { 147 if (activeCount == 0) 148 { 149 // No OCCs running, so poll timer will not be restarted 150 log<level::INFO>("Manager::pollerTimerExpire(): No OCCs running, poll " 151 "timer not restarted"); 152 } 153 154 if (!_pollTimer) 155 { 156 log<level::ERR>( 157 "Manager::pollerTimerExpired() ERROR: Timer not defined"); 158 return; 159 } 160 161 for (auto& obj : statusObjects) 162 { 163 // Read sysfs to force kernel to poll OCC 164 obj->readOccState(); 165 } 166 167 // Restart OCC poll timer 168 _pollTimer->restartOnce(std::chrono::seconds(pollInterval)); 169 } 170 171 } // namespace occ 172 } // namespace open_power 173