Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 1 | #include <endian.h> |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 2 | #include <errno.h> |
| 3 | #include <fcntl.h> |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 4 | #include <poll.h> |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 5 | #include <unistd.h> |
| 6 | |
| 7 | #include <array> |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 8 | #include <file.hpp> |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 9 | #include <sbe_chipOp_handler.hpp> |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 10 | namespace openpower |
| 11 | { |
| 12 | namespace sbe |
| 13 | { |
| 14 | namespace internal |
| 15 | { |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 16 | |
| 17 | constexpr uint16_t MAGIC_CODE = 0xC0DE; |
| 18 | constexpr auto SBE_OPERATION_SUCCESSFUL = 0; |
| 19 | constexpr auto LENGTH_OF_DISTANCE_HEADER_IN_WORDS = 0x1; |
| 20 | constexpr auto LENGTH_OF_RESP_HEADER_IN_WORDS = 0x2; |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 21 | constexpr auto DISTANCE_TO_RESP_CODE = 0x1; |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 22 | constexpr auto MAX_FFDC_LEN_IN_WORDS = 5120; |
| 23 | constexpr auto WORD_SIZE = 4; |
| 24 | constexpr auto MAGIC_CODE_BITS = 16; |
| 25 | std::vector<sbe_word_t> writeToFifo(const char* devPath, |
| 26 | const sbe_word_t* cmdBuffer, |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 27 | size_t cmdBufLen, size_t respBufLen) |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 28 | { |
Benjamin Herrenschmidt | 0dc2932 | 2018-05-17 15:25:47 +1000 | [diff] [blame] | 29 | ssize_t len = 0; |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 30 | std::vector<sbe_word_t> response; |
| 31 | std::ostringstream errMsg; |
| 32 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 33 | // Open the device and obtain the file descriptor associated with it. |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 34 | FileDescriptor fileFd(devPath, (O_RDWR | O_NONBLOCK)); |
| 35 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 36 | // Wait for FIFO device and perform write operation |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 37 | struct pollfd poll_fd = {}; |
| 38 | poll_fd.fd = fileFd(); |
| 39 | poll_fd.events = POLLOUT | POLLERR; |
| 40 | |
| 41 | int rc = 0; |
| 42 | if ((rc = poll(&poll_fd, 1, -1)) < 0) |
| 43 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 44 | // TODO:use elog infrastructure |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 45 | errMsg << "Waiting for FIFO device:" << devPath << "to write failed" |
| 46 | << "rc=" << rc << "errno=" << errno; |
| 47 | throw std::runtime_error(errMsg.str().c_str()); |
| 48 | } |
| 49 | if (poll_fd.revents & POLLERR) |
| 50 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 51 | // TODO:use elog infrastructure |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 52 | errMsg << "POLLERR while waiting for writeable FIFO,errno:" << errno; |
| 53 | throw std::runtime_error(errMsg.str().c_str()); |
| 54 | } |
| 55 | auto bytesToWrite = (cmdBufLen * WORD_SIZE); |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 56 | // Perform the write operation |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 57 | len = write(fileFd(), cmdBuffer, bytesToWrite); |
| 58 | if (len < 0) |
| 59 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 60 | // TODO:use elog infrastructure |
| 61 | errMsg << "Failed to write to FIFO device:" << devPath |
| 62 | << " Length " |
| 63 | "returned= " |
| 64 | << len << " errno=" << errno; |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 65 | throw std::runtime_error(errMsg.str().c_str()); |
| 66 | } |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 67 | // Wait for FIFO device and perform read operation |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 68 | poll_fd.fd = fileFd(); |
| 69 | poll_fd.events = POLLIN | POLLERR; |
| 70 | if ((rc = poll(&poll_fd, 1, -1) < 0)) |
| 71 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 72 | // TODO:use elog infrastructure |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 73 | errMsg << "Waiting for FIFO device:" << devPath << "to read failed" |
| 74 | << " rc=" << rc << " and errno=" << errno; |
| 75 | throw std::runtime_error(errMsg.str().c_str()); |
| 76 | } |
| 77 | if (poll_fd.revents & POLLERR) |
| 78 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 79 | // TODO:use elog infrastructure |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 80 | errMsg << "POLLERR while waiting for readable FIFO,errno:" << errno; |
| 81 | throw std::runtime_error(errMsg.str().c_str()); |
| 82 | } |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 83 | // Derive the total read length which should include the FFDC, which SBE |
| 84 | // returns in case of failure. |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 85 | size_t totalReadLen = respBufLen + MAX_FFDC_LEN_IN_WORDS; |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 86 | // Create a temporary buffer |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 87 | std::vector<sbe_word_t> buffer(totalReadLen); |
| 88 | |
Benjamin Herrenschmidt | 0dc2932 | 2018-05-17 15:25:47 +1000 | [diff] [blame] | 89 | ssize_t bytesToRead = (totalReadLen * WORD_SIZE); |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 90 | len = read(fileFd(), buffer.data(), bytesToRead); |
| 91 | if (len < 0) |
| 92 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 93 | // TODO:use elog infrastructure |
| 94 | errMsg << "Failed to read the FIFO device:" << devPath |
| 95 | << "bytes read =" << len << " errno=" << errno; |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 96 | throw std::runtime_error(errMsg.str().c_str()); |
| 97 | } |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 98 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 99 | // Extract the valid number of words read. |
Benjamin Herrenschmidt | f241156 | 2018-05-17 15:27:04 +1000 | [diff] [blame] | 100 | for (auto i = 0; i < (len / WORD_SIZE); ++i) |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 101 | { |
| 102 | response.push_back(be32toh(buffer[i])); |
| 103 | } |
| 104 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 105 | // Closing of the file descriptor will be handled when the FileDescriptor |
| 106 | // object will go out of scope. |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 107 | return response; |
| 108 | } |
| 109 | |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 110 | void parseResponse(std::vector<sbe_word_t>& sbeDataBuf) |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 111 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 112 | // Number of 32-bit words obtained from the SBE |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 113 | size_t lengthObtained = sbeDataBuf.size(); |
| 114 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 115 | // Fetch the SBE header and SBE chiop primary and secondary status |
| 116 | // Last value in the buffer will have the offset for the SBE header |
| 117 | size_t distanceToStatusHeader = sbeDataBuf[sbeDataBuf.size() - 1]; |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 118 | |
| 119 | if (lengthObtained < distanceToStatusHeader) |
| 120 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 121 | // TODO:use elog infrastructure |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 122 | std::ostringstream errMsg; |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 123 | errMsg << "Distance to SBE status header value " |
| 124 | << distanceToStatusHeader |
| 125 | << " is greater then total length of " |
| 126 | "response buffer " |
| 127 | << lengthObtained; |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 128 | throw std::runtime_error(errMsg.str().c_str()); |
| 129 | } |
| 130 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 131 | // Fetch the response header contents |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 132 | auto iter = sbeDataBuf.begin(); |
| 133 | std::advance(iter, (lengthObtained - distanceToStatusHeader)); |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 134 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 135 | // First header word will have 2 bytes of MAGIC CODE followed by |
| 136 | // Command class and command type |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 137 | //| MAGIC BYTES:0xCODE | COMMAND-CLASS | COMMAND-TYPE| |
| 138 | sbe_word_t l_magicCode = (*iter >> MAGIC_CODE_BITS); |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 139 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 140 | // Fetch the primary and secondary response code |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 141 | std::advance(iter, DISTANCE_TO_RESP_CODE); |
| 142 | auto l_priSecResp = *iter; |
| 143 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 144 | // Validate the magic code obtained in the response |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 145 | if (l_magicCode != MAGIC_CODE) |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 146 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 147 | // TODO:use elog infrastructure |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 148 | std::ostringstream errMsg; |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 149 | errMsg << "Invalid MAGIC keyword in the response header (" |
| 150 | << l_magicCode << "),expected keyword " << MAGIC_CODE; |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 151 | throw std::runtime_error(errMsg.str().c_str()); |
| 152 | } |
| 153 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 154 | // Validate the Primary and Secondary response value |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 155 | if (l_priSecResp != SBE_OPERATION_SUCCESSFUL) |
| 156 | { |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 157 | // Extract the SBE FFDC and throw it to the caller |
| 158 | size_t ffdcLen = |
| 159 | (distanceToStatusHeader - LENGTH_OF_RESP_HEADER_IN_WORDS - |
| 160 | LENGTH_OF_DISTANCE_HEADER_IN_WORDS); |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 161 | if (ffdcLen) |
| 162 | { |
| 163 | std::vector<sbe_word_t> ffdcData(ffdcLen); |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 164 | // Fetch the offset of FFDC data |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 165 | auto ffdcOffset = (lengthObtained - distanceToStatusHeader) + |
| 166 | LENGTH_OF_RESP_HEADER_IN_WORDS; |
| 167 | std::copy_n((sbeDataBuf.begin() + ffdcOffset), ffdcLen, |
| 168 | ffdcData.begin()); |
| 169 | } |
| 170 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 171 | // TODO:use elog infrastructure to return the SBE and Hardware procedure |
| 172 | // FFDC container back to the caller. |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 173 | std::ostringstream errMsg; |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 174 | errMsg << "Chip operation failed with SBE response code:" |
| 175 | << l_priSecResp |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 176 | << ".Length of FFDC data of obtained:" << ffdcLen; |
| 177 | throw std::runtime_error(errMsg.str().c_str()); |
| 178 | } |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 179 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 180 | // In case of success, remove the response header content and send only the |
| 181 | // data.Response header will be towards the end of the buffer. |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 182 | auto respLen = (lengthObtained - distanceToStatusHeader); |
| 183 | iter = sbeDataBuf.begin(); |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 184 | std::advance(iter, respLen); |
Murulidhar Nataraju | 06a0c2c | 2017-07-11 08:55:33 -0500 | [diff] [blame] | 185 | sbeDataBuf.erase(iter, sbeDataBuf.end()); |
Murulidhar Nataraju | 1adec02 | 2017-04-20 12:05:51 -0500 | [diff] [blame] | 186 | } |
| 187 | |
Patrick Venture | da79c9c | 2018-11-01 15:35:52 -0700 | [diff] [blame] | 188 | } // namespace internal |
| 189 | } // namespace sbe |
| 190 | } // namespace openpower |