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 void Manager::findAndCreateObjects()
20 {
21     for (auto id = 0; id < MAX_CPUS; ++id)
22     {
23         // Create one occ per cpu
24         auto occ = std::string(OCC_NAME) + std::to_string(id);
25         createObjects(occ);
26     }
27 }
28 
29 int Manager::cpuCreated(sdbusplus::message::message& msg)
30 {
31     namespace fs = std::experimental::filesystem;
32 
33     sdbusplus::message::object_path o;
34     msg.read(o);
35     fs::path cpuPath(std::string(std::move(o)));
36 
37     auto name = cpuPath.filename().string();
38     auto index = name.find(CPU_NAME);
39     name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
40 
41     createObjects(name);
42 
43     return 0;
44 }
45 
46 void Manager::createObjects(const std::string& occ)
47 {
48     auto path = fs::path(OCC_CONTROL_ROOT) / occ;
49 
50     passThroughObjects.emplace_back(
51         std::make_unique<PassThrough>(bus, path.c_str()));
52 
53     statusObjects.emplace_back(std::make_unique<Status>(
54         bus, event, path.c_str(), *this,
55         std::bind(std::mem_fn(&Manager::statusCallBack), this,
56                   std::placeholders::_1)));
57 
58     // Create the power cap monitor object for master occ (0)
59     if (!pcap)
60     {
61         pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
62             bus, *statusObjects.front());
63     }
64 }
65 
66 void Manager::statusCallBack(bool status)
67 {
68     using namespace phosphor::logging;
69     using InternalFailure =
70         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
71 
72     // At this time, it won't happen but keeping it
73     // here just in case something changes in the future
74     if ((activeCount == 0) && (!status))
75     {
76         log<level::ERR>("Invalid update on OCCActive");
77         elog<InternalFailure>();
78     }
79 
80     activeCount += status ? 1 : -1;
81 
82     // Only start presence detection if all the OCCs are bound
83     if (activeCount == statusObjects.size())
84     {
85         for (auto& obj : statusObjects)
86         {
87             obj->addPresenceWatchMaster();
88         }
89     }
90 }
91 
92 #ifdef I2C_OCC
93 void Manager::initStatusObjects()
94 {
95     // Make sure we have a valid path string
96     static_assert(sizeof(DEV_PATH) != 0);
97 
98     auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
99     auto occMasterName = deviceNames.front();
100     for (auto& name : deviceNames)
101     {
102         i2c_occ::i2cToDbus(name);
103         name = std::string(OCC_NAME) + '_' + name;
104         auto path = fs::path(OCC_CONTROL_ROOT) / name;
105         statusObjects.emplace_back(
106             std::make_unique<Status>(bus, event, path.c_str(), *this));
107     }
108     // The first device is master occ
109     pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
110         bus, *statusObjects.front(), occMasterName);
111 }
112 #endif
113 
114 } // namespace occ
115 } // namespace open_power
116