blob: 0d3224121313c227b5138c930a28cc15d9ba90c3 [file] [log] [blame]
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +05301#pragma once
2
3#include <cstring>
4#include <vector>
5#include <experimental/filesystem>
6#include <functional>
7#include <sdbusplus/bus.hpp>
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +05308#include <phosphor-logging/log.hpp>
9#include <phosphor-logging/elog.hpp>
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050010#include <powercap.hpp>
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053011#include "occ_pass_through.hpp"
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +053012#include "occ_status.hpp"
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050013#include "occ_finder.hpp"
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053014#include "config.h"
Lei YU0ab90ca2017-07-13 17:02:23 +080015#include "i2c_occ.hpp"
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053016
17namespace sdbusRule = sdbusplus::bus::match::rules;
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053018namespace open_power
19{
20namespace occ
21{
22
23/** @class Manager
24 * @brief Builds and manages OCC objects
25 */
26struct Manager
27{
28 public:
29 Manager() = delete;
30 Manager(const Manager&) = delete;
31 Manager& operator=(const Manager&) = delete;
32 Manager(Manager&&) = default;
33 Manager& operator=(Manager&&) = default;
34 ~Manager() = default;
35
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +053036 /** @brief Adds OCC pass-through and status objects on the bus
37 * when corresponding CPU inventory is created.
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053038 *
39 * @param[in] bus - handle to the bus
40 * @param[in] event - Unique ptr reference to sd_event
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053041 */
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053042 Manager(sdbusplus::bus::bus& bus,
43 EventPtr& event) :
44 bus(bus),
45 event(event)
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053046 {
Lei YU0ab90ca2017-07-13 17:02:23 +080047#ifdef I2C_OCC
48 // I2C OCC status objects are initialized directly
49 initStatusObjects();
50#else
Vishwanatha Subbannab57f1512017-09-04 15:06:20 +053051
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050052 // Check if CPU inventory exists already.
Vishwanatha Subbanna1ec291f2017-08-21 17:07:29 +053053 auto occs = open_power::occ::finder::get(bus);
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050054 if (occs.empty())
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053055 {
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050056 // Need to watch for CPU inventory creation.
57 for (auto id = 0; id < MAX_CPUS; ++id)
58 {
59 auto path = std::string(CPU_PATH) + std::to_string(id);
60 cpuMatches.emplace_back(
61 bus,
62 sdbusRule::interfacesAdded() +
63 sdbusRule::argNpath(0, path),
64 std::bind(std::mem_fn(&Manager::cpuCreated),
65 this, std::placeholders::_1));
66 }
67 }
68 else
69 {
70 for (const auto& occ : occs)
71 {
72 // CPU inventory exists already, OCC objects can be created.
73 createObjects(occ);
74 }
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053075 }
Lei YU0ab90ca2017-07-13 17:02:23 +080076#endif
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053077 }
78
Vishwanatha Subbannab57f1512017-09-04 15:06:20 +053079
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053080 private:
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053081 /** @brief Callback that responds to cpu creation in the inventory -
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053082 * by creating the needed objects.
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053083 *
84 * @param[in] msg - bus message
85 *
86 * @returns 0 to indicate success
87 */
88 int cpuCreated(sdbusplus::message::message& msg)
89 {
90 namespace fs = std::experimental::filesystem;
91
92 sdbusplus::message::object_path o;
93 msg.read(o);
94 fs::path cpuPath(std::string(std::move(o)));
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053095
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050096 auto name = cpuPath.filename().string();
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053097 auto index = name.find(CPU_NAME);
98 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
99
Deepak Kodihalli5f031f32017-07-26 08:25:59 -0500100 createObjects(name);
101
102 return 0;
103 }
104
Deepak Kodihalli5f031f32017-07-26 08:25:59 -0500105 /** @brief Create child OCC objects.
106 *
107 * @param[in] occ - the occ name, such as occ0.
108 */
109 void createObjects(const std::string& occ)
110 {
111 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
112
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +0530113 passThroughObjects.emplace_back(
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530114 std::make_unique<PassThrough>(
115 bus,
116 path.c_str()));
117
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +0530118 statusObjects.emplace_back(
119 std::make_unique<Status>(
120 bus,
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530121 event,
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +0530122 path.c_str(),
123 std::bind(std::mem_fn(&Manager::statusCallBack),
124 this, std::placeholders::_1)));
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500125
126 // Create the power cap monitor object for master occ (0)
Deepak Kodihalli5f031f32017-07-26 08:25:59 -0500127 if (!pcap)
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500128 {
129 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
130 bus,
Deepak Kodihalli5f031f32017-07-26 08:25:59 -0500131 *statusObjects.front());
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500132 }
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530133 }
134
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +0530135 /** @brief Callback handler invoked by Status object when the OccActive
136 * property is changed. This is needed to make sure that the
137 * error detection is started only after all the OCCs are bound.
138 * Similarly, when one of the OCC gets its OccActive property
139 * un-set, then the OCC error detection needs to be stopped on
140 * all the OCCs
141 *
142 * @param[in] status - OccActive status
143 */
144 void statusCallBack(bool status)
145 {
146 using namespace phosphor::logging;
147 using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
148 Error::InternalFailure;
149
150 // At this time, it won't happen but keeping it
151 // here just in case something changes in the future
152 if ((activeCount == 0) && (!status))
153 {
154 log<level::ERR>("Invalid update on OCCActive");
155 elog<InternalFailure>();
156 }
157
158 activeCount += status ? 1 : -1;
159
160 // If all the OCCs are bound, then start error detection
161 if (activeCount == statusObjects.size())
162 {
163 for (const auto& occ: statusObjects)
164 {
165 occ->addErrorWatch();
166 }
167 }
168 else if (!status)
169 {
170 // If some OCCs are not bound yet, those will be a NO-OP
171 for (const auto& occ: statusObjects)
172 {
173 occ->removeErrorWatch();
174 }
175 }
176 }
177
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530178 /** @brief reference to the bus */
179 sdbusplus::bus::bus& bus;
180
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530181 /** @brief reference to sd_event wrapped in unique_ptr */
182 EventPtr& event;
183
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530184 /** @brief OCC pass-through objects */
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +0530185 std::vector<std::unique_ptr<PassThrough>> passThroughObjects;
186
187 /** @brief OCC Status objects */
188 std::vector<std::unique_ptr<Status>> statusObjects;
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530189
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500190 /** @brief Power cap monitor and occ notification object */
191 std::unique_ptr<open_power::occ::powercap::PowerCap> pcap;
192
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530193 /** @brief sbdbusplus match objects */
194 std::vector<sdbusplus::bus::match_t> cpuMatches;
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +0530195
196 /** @brief Number of OCCs that are bound */
197 uint8_t activeCount = 0;
Lei YU0ab90ca2017-07-13 17:02:23 +0800198
199#ifdef I2C_OCC
200 /** @brief Init Status objects for I2C OCC devices
201 *
202 * It iterates in /sys/bus/i2c/devices, finds all occ hwmon devices
203 * and creates status objects.
204 */
205 void initStatusObjects()
206 {
207 // Make sure we have a valid path string
208 static_assert(sizeof(DEV_PATH) != 0);
209
210 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
211 for (auto& name : deviceNames)
212 {
213 i2c_occ::i2cToDbus(name);
214 auto path = fs::path(OCC_CONTROL_ROOT) / name;
215 statusObjects.emplace_back(
216 std::make_unique<Status>(
217 bus,
218 event,
219 path.c_str()));
220 }
221 }
222#endif
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530223};
224
225} // namespace occ
226} // namespace open_power