summaryrefslogtreecommitdiffstats
path: root/src/occ_gpe0/firdata/sbe_fifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/occ_gpe0/firdata/sbe_fifo.c')
-rw-r--r--src/occ_gpe0/firdata/sbe_fifo.c444
1 files changed, 444 insertions, 0 deletions
diff --git a/src/occ_gpe0/firdata/sbe_fifo.c b/src/occ_gpe0/firdata/sbe_fifo.c
new file mode 100644
index 0000000..9a2099a
--- /dev/null
+++ b/src/occ_gpe0/firdata/sbe_fifo.c
@@ -0,0 +1,444 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/firdata/sbe_fifo.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "sbe_fifo.h"
+#include <trac.h>
+#include <fsi.h>
+#include <native.h>
+
+/** @brief Waits for FIFO to be ready to be written to
+ * @param i_target The SCOM target.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+uint32_t waitUpFifoReady(SCOM_Trgt_t* i_target)
+{
+ uint32_t l_rc = SUCCESS;
+
+ uint64_t l_elapsed_time_ns = 0;
+ uint32_t l_addr = SBE_FIFO_UPFIFO_STATUS;
+ uint32_t l_data = 0;
+
+ do
+ {
+ //Read upstream status to see if there is room for more data
+ l_rc = getfsi(*i_target, l_addr, &l_data);
+ if(l_rc != SUCCESS)
+ {
+ TRAC_ERR("waitUpFifoReady: failed to getfsi from addr 0x%08x",
+ l_addr);
+ break;
+ }
+
+ if(!(l_data & UPFIFO_STATUS_FIFO_FULL))
+ {
+ break;
+ }
+
+ //Check for timeout
+ if(l_elapsed_time_ns >= MAX_UP_FIFO_TIMEOUT_NS)
+ {
+ l_rc = FAIL;
+ TRAC_ERR("waitUpFifoReady: timeout occurred while waiting for"
+ " FIFO to clear");
+ break;
+ }
+
+ sleep(10000); //sleep for 10,000 ns
+ l_elapsed_time_ns += 10000;
+ }while(TRUE);
+
+ return l_rc;
+}
+
+/** @brief Waits for information to show up in FIFO
+ * @param i_target The SCOM target.
+ * @param o_status the status of the FIFO
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+uint32_t waitDnFifoReady(SCOM_Trgt_t* i_target, uint32_t* o_status)
+{
+ uint32_t l_rc = SUCCESS;
+
+ uint64_t l_elapsed_time_ns = 0;
+ uint32_t l_addr = SBE_FIFO_DNFIFO_STATUS;
+
+ do
+ {
+ // read dnstream status to see if data ready to be read
+ // or if has hit the EOT
+ l_rc = getfsi(*i_target, l_addr, o_status);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ if(!(*o_status & DNFIFO_STATUS_FIFO_EMPTY) ||
+ (*o_status & DNFIFO_STATUS_DEQUEUED_EOT_FLAG))
+ {
+ break;
+ }
+ else
+ {
+ TRAC_IMP("SBE status reg returned fifo empty or dequeued eot flag 0x%.8X",
+ *o_status);
+ }
+
+ // Check for timeout
+ if(l_elapsed_time_ns >= MAX_UP_FIFO_TIMEOUT_NS)
+ {
+ TRAC_ERR("waitDnFifoReady: timeout waiting for downstream FIFO"
+ " to be empty.");
+ l_rc = FAIL;
+ break;
+ }
+
+ sleep(10000); // wait for 10,000 ns
+ l_elapsed_time_ns += 10000;
+
+ }while(TRUE);
+
+ return l_rc;
+}
+
+/** @brief Writes a request to FIFO
+ * @param i_target The SCOM target.
+ * @param i_fifoRequest the request to execute.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+uint32_t writeRequest(SCOM_Trgt_t* i_target, uint32_t* i_fifoRequest)
+{
+ uint32_t l_rc = SUCCESS;
+
+ TRAC_IMP("Enter writeRequest");
+
+ // Ensure Downstream Max Transfer Counter is 0 non-0 can cause
+ // protocol issues)
+ uint32_t l_addr = SBE_FIFO_DNFIFO_MAX_TSFR;
+ uint32_t l_data = 0;
+ l_rc = putfsi(*i_target, l_addr, l_data);
+ if(l_rc != SUCCESS)
+ {
+ TRAC_ERR("writeRequest: failed to putfsi to addr 0x%08x",
+ l_addr);
+ return l_rc;
+ }
+
+ //The first uint32_t has the number of uint32_t words in the request
+ l_addr = SBE_FIFO_UPFIFO_DATA_IN;
+ uint32_t* l_sent = i_fifoRequest; //This pointer will advance as words are sent
+ uint32_t l_count = *l_sent;
+ uint32_t i;
+
+ for(i = 0; i < l_count; ++i)
+ {
+ //Wait for room to write into fifo
+ l_rc = waitUpFifoReady(i_target);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ //Send data into fifo
+ l_rc = putfsi(*i_target, l_addr, *l_sent);
+ if(l_rc != SUCCESS)
+ {
+ TRAC_ERR("writeRequest: failed to putfsi to addr 0x%08x",
+ l_addr);
+ return l_rc;
+ }
+
+ l_sent++;
+ }
+
+ //Notify SBE that last word has been sent
+ l_rc = waitUpFifoReady(i_target);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ l_addr = SBE_FIFO_UPFIFO_SIG_EOT;
+ l_data = FSB_UPFIFO_SIG_EOT;
+ l_rc = putfsi(*i_target, l_addr, l_data);
+ if(l_rc != SUCCESS)
+ {
+ TRAC_ERR("writeRequest: failed to putfsi to addr 0x%08x", l_addr);
+ }
+
+ TRAC_IMP("Exit writeRequest");
+
+ return l_rc;
+}
+
+/** @brief Reads and processes the FIFO response
+ * @param i_target The SCOM target.
+ * @param i_fifoRequest the original FIFO request.
+ * @param o_fifoResponse the FIFO response.
+ * @param i_responseSize the expected size of the response.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+uint32_t readResponse(SCOM_Trgt_t* i_target,
+ uint32_t* i_fifoRequest,
+ uint32_t* o_fifoResponse,
+ uint32_t i_responseSize)
+{
+ uint32_t l_rc = SUCCESS;
+ uint32_t l_readBuffer[READ_BUFFER_SIZE];
+
+ TRAC_IMP("Enter readResponse");
+
+ // EOT is expected before the response buffer is full. Room for
+ // the PCBPIB status or FFDC is included, but is only returned
+ // if there is an error. The last received word has the distance
+ // to the status, which is placed at the end of the returned data
+ // in order to reflect errors during transfer.
+
+ uint32_t* l_received = o_fifoResponse; // advance as words are received
+ uint32_t l_maxWords = i_responseSize / sizeof(uint32_t);
+ uint32_t l_wordsReceived = 0; // Used to validata the "distance" to status
+ bool l_eotReceived = FALSE;
+ uint32_t l_lastWord = 0; // Last word received. Final read is the "distance"
+ // in words to the status header.
+ bool l_overRun = FALSE;
+
+ do
+ {
+ // Wait for data to be ready to receive (download) or if the EOT
+ // has been sent. If not EOT, then data ready to receive.
+ uint32_t l_status = 0;
+ l_rc = waitDnFifoReady(i_target, &l_status);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ if(l_status & DNFIFO_STATUS_DEQUEUED_EOT_FLAG)
+ {
+ l_eotReceived = TRUE;
+ // Ignore EOT dummy word
+ if(l_wordsReceived >= (sizeof(struct statusHeader) / sizeof(uint32_t)))
+ {
+ if(l_overRun == FALSE)
+ {
+ l_received--;
+ l_wordsReceived--;
+ l_lastWord = o_fifoResponse[l_wordsReceived-1];
+ }
+ else
+ {
+ l_lastWord = l_readBuffer[l_wordsReceived-2];
+ }
+ }
+ break;
+ }
+
+ // When error occurs, SBE will write more than l_maxWords
+ // we have to keep reading 1 word at a time until we get EOT
+ // or more than READ_BUFFER_SIZE. Save what we read in the buffer
+ if(l_wordsReceived >= l_maxWords)
+ {
+ l_overRun = TRUE;
+ }
+
+ // Read next word
+ l_rc = getfsi(*i_target, SBE_FIFO_DNFIFO_DATA_OUT, &l_lastWord);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ l_readBuffer[l_wordsReceived] = l_lastWord;
+
+ if(l_overRun == FALSE)
+ {
+ *l_received = l_lastWord; // Copy to returned output buffer
+ l_received++; // Advance to the next position
+ }
+ l_wordsReceived++;
+
+ if(l_wordsReceived > READ_BUFFER_SIZE)
+ {
+ TRAC_ERR("readResponse: data overflow without EOT");
+ l_rc = FAIL;
+ return l_rc;
+ }
+
+ }while(TRUE);
+
+ // At this point, l_wordsReceived of words received.
+ // l_received points to 1 word past last word received.
+ // l_lastWord has last word received, which is "distance" to status
+ // EOT is expected before running out of response buffer
+ if(!l_eotReceived)
+ {
+ l_rc = FAIL;
+ TRAC_ERR("readResponse: no EOT cmd = 0x%08x size = %d",
+ i_fifoRequest[1], i_responseSize);
+ return l_rc;
+ }
+
+ // Notify SBE that EOT has been received
+ uint32_t l_eotSig = FSB_UPFIFO_SIG_EOT;
+ l_rc = putfsi(*i_target, SBE_FIFO_DNFIFO_ACK_EOT, l_eotSig);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ // Determine if transmission is successful.
+ // Last word received has the distance to status in words including itself.
+ // l_wordsReceived has number of words received.
+ // Need to have received at least status header and distance word.
+ if((l_lastWord < (sizeof(struct statusHeader)/sizeof(uint32_t) + 1)) ||
+ (l_wordsReceived < (sizeof(struct statusHeader)/sizeof(uint32_t) + 1)) ||
+ (l_lastWord > l_wordsReceived))
+ {
+ TRAC_ERR("readResponse: invalid status distance. Cmd = 0x%08x distance"
+ " = %d allocated response size = %d received word size = %d",
+ i_fifoRequest[1], l_lastWord, i_responseSize, l_wordsReceived);
+ l_rc = FAIL;
+ return l_rc;
+ }
+
+ // Check status for success.
+ // l_received points one word past last word received.
+ // l_lastWord has number of words to status header including self.
+ uint32_t* l_statusTmp = (l_overRun == FALSE) ? (l_received - l_lastWord) :
+ &l_readBuffer[l_wordsReceived - 1];
+ struct statusHeader* l_statusHeader = (struct statusHeader*)l_statusTmp;
+ if((FIFO_STATUS_MAGIC != l_statusHeader->magic) ||
+ (SBE_PRI_OPERATION_SUCCESSFUL != l_statusHeader->primaryStatus) ||
+ (SBE_SEC_OPERATION_SUCCESSFUL != l_statusHeader->secondaryStatus))
+ {
+ TRAC_ERR("readResponse: failing downstream status cmd = 0x%08x magic = "
+ "0x%08x primary status = 0x%08x secondary status = 0x%08x",
+ i_fifoRequest[1],
+ l_statusHeader->magic,
+ l_statusHeader->primaryStatus,
+ l_statusHeader->secondaryStatus);
+
+ l_rc = FAIL;
+ }
+
+ TRAC_IMP("Exit readResponse");
+ return l_rc;
+}
+
+/** @brief Performs a FIFO operation (read or write)
+ * @param i_target The SCOM target.
+ * @param i_fifoRequest the FIFO request data structure
+ * @param i_fifoResponse the response from SBE
+ * @param i_responseSize the size of the response
+ * @return Non-SUCCESS if the operation fails. SUCCESS otherwise.
+ */
+uint32_t performFifoChipOp(SCOM_Trgt_t* i_target,
+ uint32_t* i_fifoRequest,
+ uint32_t* i_fifoResponse,
+ uint32_t i_responseSize)
+{
+ uint32_t l_rc = SUCCESS;
+
+ TRAC_IMP("Enter performFifoChipOp");
+
+ l_rc = writeRequest(i_target, i_fifoRequest);
+ if(l_rc != SUCCESS)
+ {
+ return l_rc;
+ }
+
+ l_rc = readResponse(i_target,
+ i_fifoRequest,
+ i_fifoResponse,
+ i_responseSize);
+
+ TRAC_IMP("Exit performFifoChioOp");
+
+ return l_rc;
+}
+
+/** @brief Performs a write SCOM operation using SBE FIFO
+ * @param i_target The SCOM target.
+ * @param i_addr 64-bit SCOM address.
+ * @param i_data 64-bit data to write.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t putFifoScom(SCOM_Trgt_t* i_target, uint64_t i_addr, uint64_t i_data)
+{
+ uint32_t l_rc = SUCCESS;
+
+ TRAC_IMP("Enter putFifoScom");
+
+ struct fifoPutScomRequest l_fifoRequest;
+ struct fifoPutScomResponse l_fifoResponse;
+
+ l_fifoRequest.wordCnt = PUT_SCOM_REQUEST_WORD_CNT;
+ l_fifoRequest.reserved = 0;
+ l_fifoRequest.commandClass = SBE_FIFO_CLASS_SCOM_ACCESS;
+ l_fifoRequest.command = SBE_FIFO_CMD_PUT_SCOM;
+ l_fifoRequest.address = i_addr;
+ l_fifoRequest.data = i_data;
+
+ l_rc = performFifoChipOp(i_target,
+ (uint32_t*)&l_fifoRequest,
+ (uint32_t*)&l_fifoResponse,
+ sizeof(struct fifoPutScomResponse));
+
+ TRAC_IMP("Exit putFifoScom");
+
+ return l_rc;
+}
+
+/** @brief Performs a read SCOM operation using SBE FIFO
+ * @param i_target The SCOM target.
+ * @param i_addr 64-bit SCOM address.
+ * @param o_data 64-bit returned value.
+ * @return Non-SUCCESS if the SCOM fails. SUCCESS otherwise.
+ */
+int32_t getFifoScom(SCOM_Trgt_t* i_target, uint64_t i_addr, uint64_t* o_data)
+{
+ uint32_t l_rc = SUCCESS;
+
+ TRAC_IMP("Enter getFifoScom");
+
+ struct fifoGetScomRequest l_fifoRequest;
+ struct fifoGetScomResponse l_fifoResponse;
+
+ l_fifoRequest.wordCnt = GET_SCOM_REQUEST_WORD_CNT;
+ l_fifoRequest.reserved = 0;
+ l_fifoRequest.commandClass = SBE_FIFO_CLASS_SCOM_ACCESS;
+ l_fifoRequest.command = SBE_FIFO_CMD_GET_SCOM;
+ l_fifoRequest.address = i_addr;
+
+ l_rc = performFifoChipOp(i_target,
+ (uint32_t*)&l_fifoRequest,
+ (uint32_t*)&l_fifoResponse,
+ sizeof(struct fifoGetScomResponse));
+
+ //Always return data even if there is an error
+ *o_data = l_fifoResponse.data;
+
+ TRAC_IMP("Exit getFifoScom");
+
+ return l_rc;
+}
OpenPOWER on IntegriCloud