Add calls to the SBE FIFO device driver to perform the SBE
chip operations.
Change-Id: I2f1204efc8196e9d331789e7910f90537834ddde
Signed-off-by: Murulidhar Nataraju <murulidhar@in.ibm.com>
diff --git a/sbe_chipOp_handler.cpp b/sbe_chipOp_handler.cpp
index f662690..05d506f 100644
--- a/sbe_chipOp_handler.cpp
+++ b/sbe_chipOp_handler.cpp
@@ -1,49 +1,120 @@
-#include <stdexcept>
#include <array>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <poll.h>
+#include <endian.h>
#include <sbe_chipOp_handler.hpp>
+#include <file.hpp>
namespace openpower
{
namespace sbe
{
namespace internal
{
-/*! \union sbeRespHeader_t
- * Defines the breakup of the SBE FIFO chip operation response header.
- */
-union sbeRespHeader_t
-{
- uint32_t commandWord; /**<Entire 32 bit command word */
- struct
- {
- uint8_t command: 8; /**<command value for which response is obtained */
- uint8_t commandClass: 8; /**< Class of the command */
- uint16_t magic: 16; /**< Magic code obtained in the response */
- };
-} __attribute__((packed));
-
constexpr uint16_t MAGIC_CODE = 0xC0DE;
constexpr auto SBE_OPERATION_SUCCESSFUL = 0;
constexpr auto LENGTH_OF_DISTANCE_HEADER_IN_WORDS = 0x1;
constexpr auto LENGTH_OF_RESP_HEADER_IN_WORDS = 0x2;
-constexpr auto SBEI_SBE_RESPONSE_SIZE_IN_WORDS = ((sizeof(sbeRespHeader_t) + \
- sizeof(sbe_word_t)) / 4);
constexpr auto DISTANCE_TO_RESP_CODE = 0x1;
-
-std::vector<sbe_word_t> write(const char* devPath,
- const sbe_word_t* cmdBuffer,
- size_t cmdBufLen,
- size_t respBufLen)
+constexpr auto MAX_FFDC_LEN_IN_WORDS = 5120;
+constexpr auto WORD_SIZE = 4;
+constexpr auto MAGIC_CODE_BITS = 16;
+std::vector<sbe_word_t> writeToFifo(const char* devPath,
+ const sbe_word_t* cmdBuffer,
+ size_t cmdBufLen,
+ size_t respBufLen)
{
- //TODO: Add support for reading and writing from the FIFO device
- std::vector<sbe_word_t> response(respBufLen);
+ size_t len = 0;
+ std::vector<sbe_word_t> response;
+ std::ostringstream errMsg;
+
+ //Open the device and obtain the file descriptor associated with it.
+ FileDescriptor fileFd(devPath, (O_RDWR | O_NONBLOCK));
+
+ //Wait for FIFO device and perform write operation
+ struct pollfd poll_fd = {};
+ poll_fd.fd = fileFd();
+ poll_fd.events = POLLOUT | POLLERR;
+
+ int rc = 0;
+ if ((rc = poll(&poll_fd, 1, -1)) < 0)
+ {
+ //TODO:use elog infrastructure
+ errMsg << "Waiting for FIFO device:" << devPath << "to write failed"
+ << "rc=" << rc << "errno=" << errno;
+ throw std::runtime_error(errMsg.str().c_str());
+ }
+ if (poll_fd.revents & POLLERR)
+ {
+ //TODO:use elog infrastructure
+ errMsg << "POLLERR while waiting for writeable FIFO,errno:" << errno;
+ throw std::runtime_error(errMsg.str().c_str());
+ }
+ auto bytesToWrite = (cmdBufLen * WORD_SIZE);
+ //Perform the write operation
+ len = write(fileFd(), cmdBuffer, bytesToWrite);
+ if (len < 0)
+ {
+ //TODO:use elog infrastructure
+ errMsg << "Failed to write to FIFO device:" << devPath << " Length "
+ "returned= " << len << " errno=" << errno;
+ throw std::runtime_error(errMsg.str().c_str());
+ }
+ //Wait for FIFO device and perform read operation
+ poll_fd.fd = fileFd();
+ poll_fd.events = POLLIN | POLLERR;
+ if ((rc = poll(&poll_fd, 1, -1) < 0))
+ {
+ //TODO:use elog infrastructure
+ errMsg << "Waiting for FIFO device:" << devPath << "to read failed"
+ << " rc=" << rc << " and errno=" << errno;
+ throw std::runtime_error(errMsg.str().c_str());
+ }
+ if (poll_fd.revents & POLLERR)
+ {
+ //TODO:use elog infrastructure
+ errMsg << "POLLERR while waiting for readable FIFO,errno:" << errno;
+ throw std::runtime_error(errMsg.str().c_str());
+ }
+ //Derive the total read length which should include the FFDC, which SBE
+ //returns in case of failure.
+ size_t totalReadLen = respBufLen + MAX_FFDC_LEN_IN_WORDS;
+ //Create a temporary buffer
+ std::vector<sbe_word_t> buffer(totalReadLen);
+
+ auto bytesToRead = (totalReadLen * WORD_SIZE);
+ len = read(fileFd(), buffer.data(), bytesToRead);
+ if (len < 0)
+ {
+ //TODO:use elog infrastructure
+ errMsg << "Failed to read the FIFO device:" << devPath << "bytes read ="
+ << len << " errno=" << errno;
+ throw std::runtime_error(errMsg.str().c_str());
+ }
+ else if (len != bytesToRead)
+ {
+ //TODO:use elog infrastructure
+ errMsg << "Exepcted " << bytesToRead << " bytes to be read from FIFO"
+ " device:" << devPath << ", but bytes read are " << len <<
+ " errno= " << errno;
+ throw std::runtime_error(errMsg.str().c_str());
+ }
+
+ //Extract the valid number of words read.
+ for (auto i = 0; i < (rc / WORD_SIZE); ++i)
+ {
+ response.push_back(be32toh(buffer[i]));
+ }
+
+ //Closing of the file descriptor will be handled when the FileDescriptor
+ //object will go out of scope.
return response;
}
-std::vector<sbe_word_t> parseResponse(
- const std::vector<sbe_word_t>& sbeDataBuf)
+void parseResponse(std::vector<sbe_word_t>& sbeDataBuf)
{
-
//Number of 32-bit words obtained from the SBE
size_t lengthObtained = sbeDataBuf.size();
@@ -62,22 +133,25 @@
}
//Fetch the response header contents
- sbeRespHeader_t l_respHeader{};
auto iter = sbeDataBuf.begin();
std::advance(iter, (lengthObtained - distanceToStatusHeader));
- l_respHeader.commandWord = *iter;
+
+ //First header word will have 2 bytes of MAGIC CODE followed by
+ //Command class and command type
+ //| MAGIC BYTES:0xCODE | COMMAND-CLASS | COMMAND-TYPE|
+ sbe_word_t l_magicCode = (*iter >> MAGIC_CODE_BITS);
//Fetch the primary and secondary response code
std::advance(iter, DISTANCE_TO_RESP_CODE);
auto l_priSecResp = *iter;
//Validate the magic code obtained in the response
- if (l_respHeader.magic != MAGIC_CODE)
+ if (l_magicCode != MAGIC_CODE)
{
//TODO:use elog infrastructure
std::ostringstream errMsg;
errMsg << "Invalid MAGIC keyword in the response header (" <<
- l_respHeader.magic << "),expected keyword " << MAGIC_CODE;
+ l_magicCode << "),expected keyword " << MAGIC_CODE;
throw std::runtime_error(errMsg.str().c_str());
}
@@ -86,7 +160,7 @@
{
//Extract the SBE FFDC and throw it to the caller
size_t ffdcLen = (distanceToStatusHeader -
- SBEI_SBE_RESPONSE_SIZE_IN_WORDS -
+ LENGTH_OF_RESP_HEADER_IN_WORDS -
LENGTH_OF_DISTANCE_HEADER_IN_WORDS);
if (ffdcLen)
{
@@ -105,12 +179,15 @@
<< ".Length of FFDC data of obtained:" << ffdcLen;
throw std::runtime_error(errMsg.str().c_str());
}
- return sbeDataBuf;
+ //In case of success, remove the response header content and send only the
+ //data.Response header will be towards the end of the buffer.
+ auto respLen = (lengthObtained - distanceToStatusHeader);
+ iter = sbeDataBuf.begin();
+ std::advance(iter,respLen);
+ sbeDataBuf.erase(iter, sbeDataBuf.end());
}
}
}
}
-
-