xref: /openbmc/openpower-occ-control/occ_pass_through.cpp (revision 37abe9be91df2bb173c9642a2740a425904d7921)
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