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::INFO>(
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         log<level::ERR>(
101             fmt::format(
102                 "PassThrough::send(): OCC command failed with status {}",
103                 uint32_t(status))
104                 .c_str());
105     }
106 
107     return response;
108 }
109 
110 bool PassThrough::setMode(const uint8_t mode, const uint16_t modeData)
111 {
112 #ifdef POWER10
113     SysPwrMode newMode = SysPwrMode(mode);
114 
115     if ((!VALID_POWER_MODE_SETTING(newMode)) &&
116         (!VALID_OEM_POWER_MODE_SETTING(newMode)))
117     {
118         log<level::ERR>(
119             fmt::format(
120                 "PassThrough::setMode() Unsupported mode {} requested (0x{:04X})",
121                 newMode, modeData)
122                 .c_str());
123         return false;
124     }
125 
126     if (((newMode == SysPwrMode::FFO) || (newMode == SysPwrMode::SFP)) &&
127         (modeData == 0))
128     {
129         log<level::ERR>(
130             fmt::format(
131                 "PassThrough::setMode() Mode {} requires non-zero frequency point.",
132                 newMode)
133                 .c_str());
134         return false;
135     }
136 
137     if (!pmode)
138     {
139         log<level::ERR>("PassThrough::setMode: PowerMode is not defined!");
140         return false;
141     }
142 
143     log<level::INFO>(
144         fmt::format("PassThrough::setMode() Setting Power Mode {} (data: {})",
145                     newMode, modeData)
146             .c_str());
147     return pmode->setMode(newMode, modeData);
148 #else
149     log<level::DEBUG>(
150         fmt::format(
151             "PassThrough::setMode() No support to setting Power Mode {} (data: {})",
152             mode, modeData)
153             .c_str());
154     return false;
155 #endif
156 }
157 
158 // Called at OCC Status change signal
159 void PassThrough::activeStatusEvent(sdbusplus::message::message& msg)
160 {
161     std::string statusInterface;
162     std::map<std::string, std::variant<bool>> msgData;
163     msg.read(statusInterface, msgData);
164 
165     auto propertyMap = msgData.find("OccActive");
166     if (propertyMap != msgData.end())
167     {
168         // Extract the OccActive property
169         if (std::get<bool>(propertyMap->second))
170         {
171             occActive = true;
172         }
173         else
174         {
175             occActive = false;
176         }
177     }
178     return;
179 }
180 
181 } // namespace occ
182 } // namespace open_power
183