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 std::bind(std::mem_fn(&Manager::statusCallBack), 74 this, std::placeholders::_1))); 75 76 // Create the power cap monitor object for master occ (0) 77 if (!pcap) 78 { 79 pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 80 bus, 81 *statusObjects.front()); 82 } 83 } 84 85 void Manager::statusCallBack(bool status) 86 { 87 using namespace phosphor::logging; 88 using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 89 Error::InternalFailure; 90 91 // At this time, it won't happen but keeping it 92 // here just in case something changes in the future 93 if ((activeCount == 0) && (!status)) 94 { 95 log<level::ERR>("Invalid update on OCCActive"); 96 elog<InternalFailure>(); 97 } 98 99 activeCount += status ? 1 : -1; 100 101 // If all the OCCs are bound, then start error detection 102 if (activeCount == statusObjects.size()) 103 { 104 for (const auto& occ: statusObjects) 105 { 106 occ->addErrorWatch(); 107 } 108 } 109 else if (!status) 110 { 111 // If some OCCs are not bound yet, those will be a NO-OP 112 for (const auto& occ: statusObjects) 113 { 114 occ->removeErrorWatch(); 115 } 116 } 117 } 118 119 #ifdef I2C_OCC 120 void Manager::initStatusObjects() 121 { 122 // Make sure we have a valid path string 123 static_assert(sizeof(DEV_PATH) != 0); 124 125 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH); 126 for (auto& name : deviceNames) 127 { 128 i2c_occ::i2cToDbus(name); 129 name = std::string(OCC_NAME) + '_' + name; 130 auto path = fs::path(OCC_CONTROL_ROOT) / name; 131 statusObjects.emplace_back( 132 std::make_unique<Status>( 133 bus, 134 event, 135 path.c_str())); 136 } 137 } 138 #endif 139 140 } // namespace occ 141 } // namespace open_power 142