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