1 #include "config.h"
2
3 #include "occ_pass_through.hpp"
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8
9 #include <org/open_power/OCC/Device/error.hpp>
10 #include <phosphor-logging/lg2.hpp>
11
12 #include <algorithm>
13 #include <memory>
14 #include <string>
15
16 namespace open_power
17 {
18 namespace occ
19 {
20
21 using namespace phosphor::logging;
22 using namespace sdbusplus::org::open_power::OCC::Device::Error;
23
PassThrough(const char * path,std::unique_ptr<open_power::occ::powermode::PowerMode> & powerModeRef)24 PassThrough::PassThrough(
25 const char* path
26 #ifdef POWER10
27 ,
28 std::unique_ptr<open_power::occ::powermode::PowerMode>& powerModeRef
29 #endif
30 ) :
31 Iface(utils::getBus(), path), path(path),
32 #ifdef POWER10
33 pmode(powerModeRef),
34 #endif
35 devicePath(OCC_DEV_PATH + std::to_string((this->path.back() - '0') + 1)),
36 occInstance(this->path.back() - '0'),
37 activeStatusSignal(
38 utils::getBus(),
39 sdbusRule::propertiesChanged(path, "org.open_power.OCC.Status"),
40 std::bind(std::mem_fn(&PassThrough::activeStatusEvent), this,
41 std::placeholders::_1)),
42 occCmd(occInstance, path)
43 {
44 // Nothing to do.
45 }
46
send(std::vector<int32_t> command)47 std::vector<int32_t> PassThrough::send(std::vector<int32_t> command)
48 {
49 std::vector<int32_t> response{};
50
51 // OCC only understands [bytes] so need array of bytes. Doing this
52 // because rest-server currently treats all int* as 32 bit integer.
53 std::vector<uint8_t> cmdInBytes, rsp;
54 cmdInBytes.resize(command.size());
55
56 // Populate uint8_t version of vector.
57 std::transform(command.begin(), command.end(), cmdInBytes.begin(),
58 [](decltype(cmdInBytes)::value_type x) { return x; });
59
60 rsp = send(cmdInBytes);
61
62 response.resize(rsp.size());
63 std::transform(rsp.begin(), rsp.end(), response.begin(),
64 [](decltype(response)::value_type x) { return x; });
65
66 return response;
67 }
68
send(std::vector<uint8_t> command)69 std::vector<uint8_t> PassThrough::send(std::vector<uint8_t> command)
70 {
71 std::vector<uint8_t> response{};
72
73 if (!occActive)
74 {
75 lg2::error(
76 "PassThrough::send() - OCC{INST} not active, command not sent",
77 "INST", occInstance);
78 return response;
79 }
80
81 if (command.size() >= 3)
82 {
83 const uint16_t dataLen = command[1] << 8 | command[2];
84 std::string dataString = "";
85 if (command.size() > 3)
86 {
87 // Trace first 4 bytes of command data
88 size_t index = 3;
89 dataString = "0x";
90 for (; (index < 7) && (index < command.size()); ++index)
91 {
92 dataString += std::format("{:02X}", command[index]);
93 }
94 if (index < command.size())
95 {
96 dataString += "...";
97 }
98 }
99 lg2::info(
100 "PassThrough::send() Sending {CMD} command to OCC{INST} (data len={LEN}, data={DATA})",
101 "CMD", lg2::hex, command.front(), "INST", occInstance, "LEN",
102 dataLen, "DATA", dataString);
103 }
104 else
105 {
106 lg2::info("PassThrough::send() Sending {CMD} command to OCC{INST}",
107 "CMD", command.front(), "INST", occInstance);
108 }
109 CmdStatus status = occCmd.send(command, response);
110 if (status == CmdStatus::SUCCESS)
111 {
112 if (response.size() >= 5)
113 {
114 lg2::debug("PassThrough::send() response had {LEN} bytes", "LEN",
115 response.size());
116 }
117 else
118 {
119 lg2::error("PassThrough::send() Invalid OCC response");
120 dump_hex(response);
121 }
122 }
123 else
124 {
125 lg2::error(
126 "PassThrough::send(): OCC command failed with status {STATUS}",
127 "STATUS", status);
128 }
129
130 return response;
131 }
132
setMode(const uint8_t mode,const uint16_t modeData)133 bool PassThrough::setMode(const uint8_t mode, const uint16_t modeData)
134 {
135 #ifdef POWER10
136 SysPwrMode newMode = SysPwrMode(mode);
137
138 if (!pmode)
139 {
140 lg2::error("PassThrough::setMode: PowerMode is not defined!");
141 return false;
142 }
143
144 if (!pmode->isValidMode(SysPwrMode(mode)))
145 {
146 lg2::error(
147 "PassThrough::setMode() Unsupported mode {MODE} requested ({DATA})",
148 "MODE", newMode, "DATA", modeData);
149 return false;
150 }
151
152 if (((newMode == SysPwrMode::FFO) || (newMode == SysPwrMode::SFP)) &&
153 (modeData == 0))
154 {
155 lg2::error(
156 "PassThrough::setMode() Mode {MODE} requires non-zero frequency point.",
157 "MODE", newMode);
158 return false;
159 }
160
161 lg2::info("PassThrough::setMode() Setting Power Mode {MODE} (data: {DATA})",
162 "MODE", uint8_t(newMode), "DATA", modeData);
163 return pmode->setMode(newMode, modeData);
164 #else
165 lg2::debug(
166 "PassThrough::setMode() No support to setting Power Mode {MODE} (data: {DATA})",
167 "MODE", mode, "DATA", modeData);
168 return false;
169 #endif
170 }
171
172 // Called at OCC Status change signal
activeStatusEvent(sdbusplus::message_t & msg)173 void PassThrough::activeStatusEvent(sdbusplus::message_t& msg)
174 {
175 std::string statusInterface;
176 std::map<std::string, std::variant<bool>> msgData;
177 msg.read(statusInterface, msgData);
178
179 auto propertyMap = msgData.find("OccActive");
180 if (propertyMap != msgData.end())
181 {
182 // Extract the OccActive property
183 if (std::get<bool>(propertyMap->second))
184 {
185 occActive = true;
186 }
187 else
188 {
189 occActive = false;
190 }
191 }
192 return;
193 }
194
195 } // namespace occ
196 } // namespace open_power
197