xref: /openbmc/openpower-occ-control/occ_manager.cpp (revision 636577f44fe3fc951538c1119ed0da8ac9a40932)
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