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