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