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