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