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 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 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 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 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 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