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