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