blob: 7bb1042dec967150c06ee150c2b87630867e01d0 [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
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050051 // Check if CPU inventory exists already.
Vishwanatha Subbanna1ec291f2017-08-21 17:07:29 +053052 auto occs = open_power::occ::finder::get(bus);
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050053 if (occs.empty())
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053054 {
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050055 // Need to watch for CPU inventory creation.
56 for (auto id = 0; id < MAX_CPUS; ++id)
57 {
58 auto path = std::string(CPU_PATH) + std::to_string(id);
59 cpuMatches.emplace_back(
60 bus,
61 sdbusRule::interfacesAdded() +
62 sdbusRule::argNpath(0, path),
63 std::bind(std::mem_fn(&Manager::cpuCreated),
64 this, std::placeholders::_1));
65 }
66 }
67 else
68 {
69 for (const auto& occ : occs)
70 {
71 // CPU inventory exists already, OCC objects can be created.
72 createObjects(occ);
73 }
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053074 }
Lei YU0ab90ca2017-07-13 17:02:23 +080075#endif
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053076 }
77
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053078 private:
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053079 /** @brief Callback that responds to cpu creation in the inventory -
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053080 * by creating the needed objects.
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053081 *
82 * @param[in] msg - bus message
83 *
84 * @returns 0 to indicate success
85 */
86 int cpuCreated(sdbusplus::message::message& msg)
87 {
88 namespace fs = std::experimental::filesystem;
89
90 sdbusplus::message::object_path o;
91 msg.read(o);
92 fs::path cpuPath(std::string(std::move(o)));
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053093
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050094 auto name = cpuPath.filename().string();
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +053095 auto index = name.find(CPU_NAME);
96 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
97
Deepak Kodihalli5f031f32017-07-26 08:25:59 -050098 createObjects(name);
99
100 return 0;
101 }
102
Deepak Kodihalli5f031f32017-07-26 08:25:59 -0500103 /** @brief Create child OCC objects.
104 *
105 * @param[in] occ - the occ name, such as occ0.
106 */
107 void createObjects(const std::string& occ)
108 {
109 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
110
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +0530111 passThroughObjects.emplace_back(
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530112 std::make_unique<PassThrough>(
113 bus,
114 path.c_str()));
115
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +0530116 statusObjects.emplace_back(
117 std::make_unique<Status>(
118 bus,
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530119 event,
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +0530120 path.c_str(),
121 std::bind(std::mem_fn(&Manager::statusCallBack),
122 this, std::placeholders::_1)));
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500123
124 // Create the power cap monitor object for master occ (0)
Deepak Kodihalli5f031f32017-07-26 08:25:59 -0500125 if (!pcap)
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500126 {
127 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
128 bus,
Deepak Kodihalli5f031f32017-07-26 08:25:59 -0500129 *statusObjects.front());
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500130 }
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530131 }
132
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +0530133 /** @brief Callback handler invoked by Status object when the OccActive
134 * property is changed. This is needed to make sure that the
135 * error detection is started only after all the OCCs are bound.
136 * Similarly, when one of the OCC gets its OccActive property
137 * un-set, then the OCC error detection needs to be stopped on
138 * all the OCCs
139 *
140 * @param[in] status - OccActive status
141 */
142 void statusCallBack(bool status)
143 {
144 using namespace phosphor::logging;
145 using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
146 Error::InternalFailure;
147
148 // At this time, it won't happen but keeping it
149 // here just in case something changes in the future
150 if ((activeCount == 0) && (!status))
151 {
152 log<level::ERR>("Invalid update on OCCActive");
153 elog<InternalFailure>();
154 }
155
156 activeCount += status ? 1 : -1;
157
158 // If all the OCCs are bound, then start error detection
159 if (activeCount == statusObjects.size())
160 {
161 for (const auto& occ: statusObjects)
162 {
163 occ->addErrorWatch();
164 }
165 }
166 else if (!status)
167 {
168 // If some OCCs are not bound yet, those will be a NO-OP
169 for (const auto& occ: statusObjects)
170 {
171 occ->removeErrorWatch();
172 }
173 }
174 }
175
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530176 /** @brief reference to the bus */
177 sdbusplus::bus::bus& bus;
178
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530179 /** @brief reference to sd_event wrapped in unique_ptr */
180 EventPtr& event;
181
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530182 /** @brief OCC pass-through objects */
Vishwanatha Subbanna307d80b2017-06-28 15:56:09 +0530183 std::vector<std::unique_ptr<PassThrough>> passThroughObjects;
184
185 /** @brief OCC Status objects */
186 std::vector<std::unique_ptr<Status>> statusObjects;
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530187
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500188 /** @brief Power cap monitor and occ notification object */
189 std::unique_ptr<open_power::occ::powercap::PowerCap> pcap;
190
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530191 /** @brief sbdbusplus match objects */
192 std::vector<sdbusplus::bus::match_t> cpuMatches;
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +0530193
194 /** @brief Number of OCCs that are bound */
195 uint8_t activeCount = 0;
Lei YU0ab90ca2017-07-13 17:02:23 +0800196
197#ifdef I2C_OCC
198 /** @brief Init Status objects for I2C OCC devices
199 *
200 * It iterates in /sys/bus/i2c/devices, finds all occ hwmon devices
201 * and creates status objects.
202 */
203 void initStatusObjects()
204 {
205 // Make sure we have a valid path string
206 static_assert(sizeof(DEV_PATH) != 0);
207
208 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
209 for (auto& name : deviceNames)
210 {
211 i2c_occ::i2cToDbus(name);
212 auto path = fs::path(OCC_CONTROL_ROOT) / name;
213 statusObjects.emplace_back(
214 std::make_unique<Status>(
215 bus,
216 event,
217 path.c_str()));
218 }
219 }
220#endif
Vishwanatha Subbanna2180b2d2017-06-28 14:05:57 +0530221};
222
223} // namespace occ
224} // namespace open_power