summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c')
-rw-r--r--sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c2701
1 files changed, 2701 insertions, 0 deletions
diff --git a/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c b/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c
new file mode 100644
index 0000000..0211394
--- /dev/null
+++ b/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c
@@ -0,0 +1,2701 @@
+/******************************************************************************
+
+ © 1995-2003, 2004, 2005-2011 Freescale Semiconductor, Inc.
+ All rights reserved.
+
+ This is proprietary source code of Freescale Semiconductor Inc.,
+ and its use is subject to the NetComm Device Drivers EULA.
+ The copyright notice above does not evidence any actual or intended
+ publication of such source code.
+
+ ALTERNATIVELY, redistribution and use in source and binary forms, with
+ or without modification, are permitted provided that the following
+ conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Freescale Semiconductor nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+
+ **************************************************************************/
+/******************************************************************************
+ @File qm.c
+
+ @Description QM & Portal implementation
+*//***************************************************************************/
+#include "error_ext.h"
+#include "std_ext.h"
+#include "string_ext.h"
+#include "mm_ext.h"
+#include "qm.h"
+#include "qman_low.h"
+
+
+/****************************************/
+/* static functions */
+/****************************************/
+
+#define SLOW_POLL_IDLE 1000
+#define SLOW_POLL_BUSY 10
+
+
+static t_Error qman_volatile_dequeue(t_QmPortal *p_QmPortal,
+ struct qman_fq *p_Fq,
+ uint32_t vdqcr)
+{
+ ASSERT_COND((p_Fq->state == qman_fq_state_parked) ||
+ (p_Fq->state == qman_fq_state_retired));
+ ASSERT_COND(!(vdqcr & QM_VDQCR_FQID_MASK));
+ ASSERT_COND(!(p_Fq->flags & QMAN_FQ_STATE_VDQCR));
+
+ vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | p_Fq->fqid;
+ NCSW_PLOCK(p_QmPortal);
+ FQLOCK(p_Fq);
+ p_Fq->flags |= QMAN_FQ_STATE_VDQCR;
+ qm_dqrr_vdqcr_set(p_QmPortal->p_LowQmPortal, vdqcr);
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+
+ return E_OK;
+}
+
+static const char *mcr_result_str(uint8_t result)
+{
+ switch (result) {
+ case QM_MCR_RESULT_NULL:
+ return "QM_MCR_RESULT_NULL";
+ case QM_MCR_RESULT_OK:
+ return "QM_MCR_RESULT_OK";
+ case QM_MCR_RESULT_ERR_FQID:
+ return "QM_MCR_RESULT_ERR_FQID";
+ case QM_MCR_RESULT_ERR_FQSTATE:
+ return "QM_MCR_RESULT_ERR_FQSTATE";
+ case QM_MCR_RESULT_ERR_NOTEMPTY:
+ return "QM_MCR_RESULT_ERR_NOTEMPTY";
+ case QM_MCR_RESULT_PENDING:
+ return "QM_MCR_RESULT_PENDING";
+ }
+ return "<unknown MCR result>";
+}
+
+static t_Error qman_create_fq(t_QmPortal *p_QmPortal,
+ uint32_t fqid,
+ uint32_t flags,
+ struct qman_fq *p_Fq)
+{
+ struct qm_fqd fqd;
+ struct qm_mcr_queryfq_np np;
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+
+ p_Fq->fqid = fqid;
+ p_Fq->flags = flags;
+ p_Fq->state = qman_fq_state_oos;
+ p_Fq->cgr_groupid = 0;
+ if (!(flags & QMAN_FQ_FLAG_RECOVER) ||
+ (flags & QMAN_FQ_FLAG_NO_MODIFY))
+ return E_OK;
+ /* Everything else is RECOVER support */
+ NCSW_PLOCK(p_QmPortal);
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->queryfq.fqid = fqid;
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYFQ);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ);
+ if (p_Mcr->result != QM_MCR_RESULT_OK) {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("QUERYFQ failed: %s", mcr_result_str(p_Mcr->result)));
+ }
+ fqd = p_Mcr->queryfq.fqd;
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->queryfq_np.fqid = fqid;
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYFQ_NP);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ_NP);
+ if (p_Mcr->result != QM_MCR_RESULT_OK) {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("UERYFQ_NP failed: %s", mcr_result_str(p_Mcr->result)));
+ }
+ np = p_Mcr->queryfq_np;
+ /* Phew, have queryfq and queryfq_np results, stitch together
+ * the FQ object from those. */
+ p_Fq->cgr_groupid = fqd.cgid;
+ switch (np.state & QM_MCR_NP_STATE_MASK) {
+ case QM_MCR_NP_STATE_OOS:
+ break;
+ case QM_MCR_NP_STATE_RETIRED:
+ p_Fq->state = qman_fq_state_retired;
+ if (np.frm_cnt)
+ p_Fq->flags |= QMAN_FQ_STATE_NE;
+ break;
+ case QM_MCR_NP_STATE_TEN_SCHED:
+ case QM_MCR_NP_STATE_TRU_SCHED:
+ case QM_MCR_NP_STATE_ACTIVE:
+ p_Fq->state = qman_fq_state_sched;
+ if (np.state & QM_MCR_NP_STATE_R)
+ p_Fq->flags |= QMAN_FQ_STATE_CHANGING;
+ break;
+ case QM_MCR_NP_STATE_PARKED:
+ p_Fq->state = qman_fq_state_parked;
+ break;
+ default:
+ ASSERT_COND(FALSE);
+ }
+ if (fqd.fq_ctrl & QM_FQCTRL_CGE)
+ p_Fq->state |= QMAN_FQ_STATE_CGR_EN;
+ PUNLOCK(p_QmPortal);
+
+ return E_OK;
+}
+
+static void qman_destroy_fq(struct qman_fq *p_Fq, uint32_t flags)
+{
+ /* We don't need to lock the FQ as it is a pre-condition that the FQ be
+ * quiesced. Instead, run some checks. */
+ UNUSED(flags);
+ switch (p_Fq->state) {
+ case qman_fq_state_parked:
+ ASSERT_COND(flags & QMAN_FQ_DESTROY_PARKED);
+ case qman_fq_state_oos:
+ return;
+ default:
+ break;
+ }
+ ASSERT_COND(FALSE);
+}
+
+static t_Error qman_init_fq(t_QmPortal *p_QmPortal,
+ struct qman_fq *p_Fq,
+ uint32_t flags,
+ struct qm_mcc_initfq *p_Opts)
+{
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+ uint8_t res, myverb = (uint8_t)((flags & QMAN_INITFQ_FLAG_SCHED) ?
+ QM_MCC_VERB_INITFQ_SCHED : QM_MCC_VERB_INITFQ_PARKED);
+
+ SANITY_CHECK_RETURN_ERROR((p_Fq->state == qman_fq_state_oos) ||
+ (p_Fq->state == qman_fq_state_parked),
+ E_INVALID_STATE);
+
+ if (p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)
+ return ERROR_CODE(E_INVALID_VALUE);
+ /* Issue an INITFQ_[PARKED|SCHED] management command */
+ NCSW_PLOCK(p_QmPortal);
+ FQLOCK(p_Fq);
+ if ((p_Fq->flags & QMAN_FQ_STATE_CHANGING) ||
+ ((p_Fq->state != qman_fq_state_oos) &&
+ (p_Fq->state != qman_fq_state_parked))) {
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ return ERROR_CODE(E_BUSY);
+ }
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ Mem2IOCpy32((void*)&p_Mcc->initfq, p_Opts, sizeof(struct qm_mcc_initfq));
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, myverb);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == myverb);
+ res = p_Mcr->result;
+ if (res != QM_MCR_RESULT_OK) {
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE,("INITFQ failed: %s", mcr_result_str(res)));
+ }
+
+ if (p_Mcc->initfq.we_mask & QM_INITFQ_WE_FQCTRL) {
+ if (p_Mcc->initfq.fqd.fq_ctrl & QM_FQCTRL_CGE)
+ p_Fq->flags |= QMAN_FQ_STATE_CGR_EN;
+ else
+ p_Fq->flags &= ~QMAN_FQ_STATE_CGR_EN;
+ }
+ if (p_Mcc->initfq.we_mask & QM_INITFQ_WE_CGID)
+ p_Fq->cgr_groupid = p_Mcc->initfq.fqd.cgid;
+ p_Fq->state = (flags & QMAN_INITFQ_FLAG_SCHED) ?
+ qman_fq_state_sched : qman_fq_state_parked;
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ return E_OK;
+}
+
+static t_Error qman_retire_fq(t_QmPortal *p_QmPortal,
+ struct qman_fq *p_Fq,
+ uint32_t *p_Flags,
+ bool drain)
+{
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+ t_Error err = E_OK;
+ uint8_t res;
+
+ SANITY_CHECK_RETURN_ERROR((p_Fq->state == qman_fq_state_parked) ||
+ (p_Fq->state == qman_fq_state_sched),
+ E_INVALID_STATE);
+
+ if (p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)
+ return E_INVALID_VALUE;
+ NCSW_PLOCK(p_QmPortal);
+ FQLOCK(p_Fq);
+ if ((p_Fq->flags & QMAN_FQ_STATE_CHANGING) ||
+ (p_Fq->state == qman_fq_state_retired) ||
+ (p_Fq->state == qman_fq_state_oos)) {
+ err = E_BUSY;
+ goto out;
+ }
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->alterfq.fqid = p_Fq->fqid;
+ if (drain)
+ p_Mcc->alterfq.context_b = (uint32_t)PTR_TO_UINT(p_Fq);
+ qm_mc_commit(p_QmPortal->p_LowQmPortal,
+ (uint8_t)((drain)?QM_MCC_VERB_ALTER_RETIRE_CTXB:QM_MCC_VERB_ALTER_RETIRE));
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) ==
+ (drain)?QM_MCR_VERB_ALTER_RETIRE_CTXB:QM_MCR_VERB_ALTER_RETIRE);
+ res = p_Mcr->result;
+ if (res == QM_MCR_RESULT_OK)
+ {
+ /* Process 'fq' right away, we'll ignore FQRNI */
+ if (p_Mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY)
+ p_Fq->flags |= QMAN_FQ_STATE_NE;
+ if (p_Mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT)
+ p_Fq->flags |= QMAN_FQ_STATE_ORL;
+ p_Fq->state = qman_fq_state_retired;
+ }
+ else if (res == QM_MCR_RESULT_PENDING)
+ p_Fq->flags |= QMAN_FQ_STATE_CHANGING;
+ else {
+ XX_Print("ALTER_RETIRE failed: %s\n",
+ mcr_result_str(res));
+ err = E_INVALID_STATE;
+ }
+ if (p_Flags)
+ *p_Flags = p_Fq->flags;
+out:
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ return err;
+}
+
+static t_Error qman_oos_fq(t_QmPortal *p_QmPortal, struct qman_fq *p_Fq)
+{
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+ uint8_t res;
+
+ ASSERT_COND(p_Fq->state == qman_fq_state_retired);
+ if (p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)
+ return ERROR_CODE(E_INVALID_VALUE);
+ NCSW_PLOCK(p_QmPortal);
+ FQLOCK(p_Fq);
+ if ((p_Fq->flags & QMAN_FQ_STATE_BLOCKOOS) ||
+ (p_Fq->state != qman_fq_state_retired)) {
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ return ERROR_CODE(E_BUSY);
+ }
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->alterfq.fqid = p_Fq->fqid;
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_ALTER_OOS);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_OOS);
+ res = p_Mcr->result;
+ if (res != QM_MCR_RESULT_OK) {
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("ALTER_OOS failed: %s\n", mcr_result_str(res)));
+ }
+ p_Fq->state = qman_fq_state_oos;
+
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ return E_OK;
+}
+
+static t_Error qman_schedule_fq(t_QmPortal *p_QmPortal, struct qman_fq *p_Fq)
+{
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+ uint8_t res;
+
+ ASSERT_COND(p_Fq->state == qman_fq_state_parked);
+ if (p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)
+ return ERROR_CODE(E_INVALID_VALUE);
+ /* Issue a ALTERFQ_SCHED management command */
+ NCSW_PLOCK(p_QmPortal);
+ FQLOCK(p_Fq);
+ if ((p_Fq->flags & QMAN_FQ_STATE_CHANGING) ||
+ (p_Fq->state != qman_fq_state_parked)) {
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ return ERROR_CODE(E_BUSY);
+ }
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->alterfq.fqid = p_Fq->fqid;
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_ALTER_SCHED);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_SCHED);
+ res = p_Mcr->result;
+ if (res != QM_MCR_RESULT_OK) {
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("ALTER_SCHED failed: %s\n", mcr_result_str(res)));
+ }
+ p_Fq->state = qman_fq_state_sched;
+
+ FQUNLOCK(p_Fq);
+ PUNLOCK(p_QmPortal);
+ return E_OK;
+}
+
+/* Inline helper to reduce nesting in LoopMessageRing() */
+static __inline__ void fq_state_change(struct qman_fq *p_Fq,
+ struct qm_mr_entry *p_Msg,
+ uint8_t verb)
+{
+ FQLOCK(p_Fq);
+ switch(verb) {
+ case QM_MR_VERB_FQRL:
+ ASSERT_COND(p_Fq->flags & QMAN_FQ_STATE_ORL);
+ p_Fq->flags &= ~QMAN_FQ_STATE_ORL;
+ break;
+ case QM_MR_VERB_FQRN:
+ ASSERT_COND((p_Fq->state == qman_fq_state_parked) ||
+ (p_Fq->state == qman_fq_state_sched));
+ ASSERT_COND(p_Fq->flags & QMAN_FQ_STATE_CHANGING);
+ p_Fq->flags &= ~QMAN_FQ_STATE_CHANGING;
+ if (p_Msg->fq.fqs & QM_MR_FQS_NOTEMPTY)
+ p_Fq->flags |= QMAN_FQ_STATE_NE;
+ if (p_Msg->fq.fqs & QM_MR_FQS_ORLPRESENT)
+ p_Fq->flags |= QMAN_FQ_STATE_ORL;
+ p_Fq->state = qman_fq_state_retired;
+ break;
+ case QM_MR_VERB_FQPN:
+ ASSERT_COND(p_Fq->state == qman_fq_state_sched);
+ ASSERT_COND(p_Fq->flags & QMAN_FQ_STATE_CHANGING);
+ p_Fq->state = qman_fq_state_parked;
+ }
+ FQUNLOCK(p_Fq);
+}
+
+static t_Error freeDrainedFq(struct qman_fq *p_Fq)
+{
+ t_QmFqr *p_QmFqr;
+ uint32_t i;
+
+ ASSERT_COND(p_Fq);
+ p_QmFqr = (t_QmFqr *)p_Fq->h_QmFqr;
+ ASSERT_COND(p_QmFqr);
+
+ ASSERT_COND(!p_QmFqr->p_DrainedFqs[p_Fq->fqidOffset]);
+ p_QmFqr->p_DrainedFqs[p_Fq->fqidOffset] = TRUE;
+ p_QmFqr->numOfDrainedFqids++;
+ if (p_QmFqr->numOfDrainedFqids == p_QmFqr->numOfFqids)
+ {
+ for (i=0;i<p_QmFqr->numOfFqids;i++)
+ {
+ if ((p_QmFqr->p_Fqs[i]->state == qman_fq_state_retired) &&
+ (qman_oos_fq(p_QmFqr->h_QmPortal, p_QmFqr->p_Fqs[i]) != E_OK))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_oos_fq() failed!"));
+ qman_destroy_fq(p_QmFqr->p_Fqs[i], 0);
+ XX_FreeSmart(p_QmFqr->p_Fqs[i]);
+ }
+ XX_Free(p_QmFqr->p_DrainedFqs);
+ p_QmFqr->p_DrainedFqs = NULL;
+
+ if (p_QmFqr->f_CompletionCB)
+ {
+ p_QmFqr->f_CompletionCB(p_QmFqr->h_App, p_QmFqr);
+ XX_Free(p_QmFqr->p_Fqs);
+ if (p_QmFqr->fqidBase)
+ QmFqidPut(p_QmFqr->h_Qm, p_QmFqr->fqidBase);
+ XX_Free(p_QmFqr);
+ }
+ }
+
+ return E_OK;
+}
+
+static t_Error drainRetiredFq(struct qman_fq *p_Fq)
+{
+ t_QmFqr *p_QmFqr;
+
+ ASSERT_COND(p_Fq);
+ p_QmFqr = (t_QmFqr *)p_Fq->h_QmFqr;
+ ASSERT_COND(p_QmFqr);
+
+ if (p_Fq->flags & QMAN_FQ_STATE_NE)
+ {
+ if (qman_volatile_dequeue(p_QmFqr->h_QmPortal, p_Fq,
+ (QM_VDQCR_PRECEDENCE_VDQCR | QM_VDQCR_NUMFRAMES_TILLEMPTY)) != E_OK)
+
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("drain with volatile failed"));
+ return E_OK;
+ }
+ else
+ return freeDrainedFq(p_Fq);
+}
+
+static e_RxStoreResponse drainCB(t_Handle h_App,
+ t_Handle h_QmFqr,
+ t_Handle h_QmPortal,
+ uint32_t fqidOffset,
+ t_DpaaFD *p_Frame)
+{
+ UNUSED(h_App);
+ UNUSED(h_QmFqr);
+ UNUSED(h_QmPortal);
+ UNUSED(fqidOffset);
+ UNUSED(p_Frame);
+
+ DBG(TRACE,("got fd for fqid %d", ((t_QmFqr *)h_QmFqr)->fqidBase + fqidOffset));
+ return e_RX_STORE_RESPONSE_CONTINUE;
+}
+
+static void cb_ern_dcErn(t_Handle h_App,
+ t_Handle h_QmPortal,
+ struct qman_fq *p_Fq,
+ const struct qm_mr_entry *p_Msg)
+{
+ static int cnt = 0;
+ UNUSED(p_Fq);
+ UNUSED(p_Msg);
+ UNUSED(h_App);
+ UNUSED(h_QmPortal);
+
+ XX_Print("cb_ern_dcErn_fqs() unimplemented %d\n", ++cnt);
+}
+
+static void cb_fqs(t_Handle h_App,
+ t_Handle h_QmPortal,
+ struct qman_fq *p_Fq,
+ const struct qm_mr_entry *p_Msg)
+{
+ UNUSED(p_Msg);
+ UNUSED(h_App);
+ UNUSED(h_QmPortal);
+
+ if (p_Fq->state == qman_fq_state_retired &&
+ !(p_Fq->flags & QMAN_FQ_STATE_ORL))
+ drainRetiredFq(p_Fq);
+}
+
+static void null_cb_mr(t_Handle h_App,
+ t_Handle h_QmPortal,
+ struct qman_fq *p_Fq,
+ const struct qm_mr_entry *p_Msg)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ UNUSED(p_Fq);UNUSED(h_App);
+
+ if ((p_Msg->verb & QM_MR_VERB_DC_ERN) == QM_MR_VERB_DC_ERN)
+ XX_Print("Ignoring unowned MR frame on cpu %d, dc-portal 0x%02x.\n",
+ p_QmPortal->p_LowQmPortal->config.cpu,p_Msg->dcern.portal);
+ else
+ XX_Print("Ignoring unowned MR frame on cpu %d, verb 0x%02x.\n",
+ p_QmPortal->p_LowQmPortal->config.cpu,p_Msg->verb);
+}
+
+static uint32_t LoopMessageRing(t_QmPortal *p_QmPortal, uint32_t is)
+{
+ struct qm_mr_entry *p_Msg;
+
+ if (is & QM_PIRQ_CSCI) {
+ struct qm_mc_result *p_Mcr;
+ struct qman_cgrs tmp;
+ uint32_t mask;
+ unsigned int i, j;
+
+ NCSW_PLOCK(p_QmPortal);
+ qm_mc_start(p_QmPortal->p_LowQmPortal);
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYCONGESTION);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+
+ /* cgrs[0] is the portal mask for its cg's, cgrs[1] is the
+ previous state of cg's */
+ for (i = 0; i < QM_MAX_NUM_OF_CGS/32; i++)
+ {
+ /* get curent state */
+ tmp.q.__state[i] = p_Mcr->querycongestion.state.__state[i];
+ /* keep only cg's that are registered for this portal */
+ tmp.q.__state[i] &= p_QmPortal->cgrs[0].q.__state[i];
+ /* handle only cg's that changed their state from previous exception */
+ tmp.q.__state[i] ^= p_QmPortal->cgrs[1].q.__state[i];
+ /* update previous */
+ p_QmPortal->cgrs[1].q.__state[i] = p_Mcr->querycongestion.state.__state[i];
+ }
+ PUNLOCK(p_QmPortal);
+
+ /* if in interrupt */
+ /* call the callback routines for any CG with a changed state */
+ for (i = 0; i < QM_MAX_NUM_OF_CGS/32; i++)
+ for(j=0, mask = 0x80000000; j<32 ; j++, mask>>=1)
+ {
+ if(tmp.q.__state[i] & mask)
+ {
+ t_QmCg *p_QmCg = (t_QmCg *)(p_QmPortal->cgsHandles[i*32 + j]);
+ if(p_QmCg->f_Exception)
+ p_QmCg->f_Exception(p_QmCg->h_App, e_QM_EX_CG_STATE_CHANGE);
+ }
+ }
+
+ }
+
+
+ if (is & QM_PIRQ_EQRI) {
+ NCSW_PLOCK(p_QmPortal);
+ qmPortalEqcrCceUpdate(p_QmPortal->p_LowQmPortal);
+ qm_eqcr_set_ithresh(p_QmPortal->p_LowQmPortal, 0);
+ PUNLOCK(p_QmPortal);
+ }
+
+ if (is & QM_PIRQ_MRI) {
+mr_loop:
+ qmPortalMrPvbUpdate(p_QmPortal->p_LowQmPortal);
+ p_Msg = qm_mr_current(p_QmPortal->p_LowQmPortal);
+ if (p_Msg) {
+ struct qman_fq *p_FqFqs = (void *)p_Msg->fq.contextB;
+ struct qman_fq *p_FqErn = (void *)p_Msg->ern.tag;
+ uint8_t verb =(uint8_t)(p_Msg->verb & QM_MR_VERB_TYPE_MASK);
+ t_QmRejectedFrameInfo rejectedFrameInfo;
+
+ memset(&rejectedFrameInfo, 0, sizeof(t_QmRejectedFrameInfo));
+ if (!(verb & QM_MR_VERB_DC_ERN))
+ {
+ switch(p_Msg->ern.rc)
+ {
+ case(QM_MR_RC_CGR_TAILDROP):
+ rejectedFrameInfo.rejectionCode = e_QM_RC_CG_TAILDROP;
+ rejectedFrameInfo.cg.cgId = (uint8_t)p_FqErn->cgr_groupid;
+ break;
+ case(QM_MR_RC_WRED):
+ rejectedFrameInfo.rejectionCode = e_QM_RC_CG_WRED;
+ rejectedFrameInfo.cg.cgId = (uint8_t)p_FqErn->cgr_groupid;
+ break;
+ case(QM_MR_RC_FQ_TAILDROP):
+ rejectedFrameInfo.rejectionCode = e_QM_RC_FQ_TAILDROP;
+ rejectedFrameInfo.cg.cgId = (uint8_t)p_FqErn->cgr_groupid;
+ break;
+ case(QM_MR_RC_ERROR):
+ break;
+ default:
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("Unknown rejection code"));
+ }
+ if (!p_FqErn)
+ p_QmPortal->p_NullCB->ern(p_QmPortal->h_App, NULL, p_QmPortal, 0, (t_DpaaFD*)&p_Msg->ern.fd, &rejectedFrameInfo);
+ else
+ p_FqErn->cb.ern(p_FqErn->h_App, p_FqErn->h_QmFqr, p_QmPortal, p_FqErn->fqidOffset, (t_DpaaFD*)&p_Msg->ern.fd, &rejectedFrameInfo);
+ } else if (verb == QM_MR_VERB_DC_ERN)
+ {
+ if (!p_FqErn)
+ p_QmPortal->p_NullCB->dc_ern(NULL, p_QmPortal, NULL, p_Msg);
+ else
+ p_FqErn->cb.dc_ern(p_FqErn->h_App, p_QmPortal, p_FqErn, p_Msg);
+ } else
+ {
+ if (verb == QM_MR_VERB_FQRNI)
+ ; /* we drop FQRNIs on the floor */
+ else if (!p_FqFqs)
+ p_QmPortal->p_NullCB->fqs(NULL, p_QmPortal, NULL, p_Msg);
+ else if ((verb == QM_MR_VERB_FQRN) ||
+ (verb == QM_MR_VERB_FQRL) ||
+ (verb == QM_MR_VERB_FQPN))
+ {
+ fq_state_change(p_FqFqs, p_Msg, verb);
+ p_FqFqs->cb.fqs(p_FqFqs->h_App, p_QmPortal, p_FqFqs, p_Msg);
+ }
+ }
+ qm_mr_next(p_QmPortal->p_LowQmPortal);
+ qmPortalMrCciConsume(p_QmPortal->p_LowQmPortal, 1);
+
+ goto mr_loop;
+ }
+ }
+
+ return is & (QM_PIRQ_CSCI | QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI);
+}
+
+static void LoopDequeueRing(t_Handle h_QmPortal)
+{
+ struct qm_dqrr_entry *p_Dq;
+ struct qman_fq *p_Fq;
+ enum qman_cb_dqrr_result res = qman_cb_dqrr_consume;
+ e_RxStoreResponse tmpRes;
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+ int prefetch = !(p_QmPortal->options & QMAN_PORTAL_FLAG_RSTASH);
+
+ while (res != qman_cb_dqrr_pause)
+ {
+ if (prefetch)
+ qmPortalDqrrPvbPrefetch(p_QmPortal->p_LowQmPortal);
+ qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
+ p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
+ if (!p_Dq)
+ break;
+ p_Fq = (void *)p_Dq->contextB;
+ if (p_Dq->stat & QM_DQRR_STAT_UNSCHEDULED) {
+ /* We only set QMAN_FQ_STATE_NE when retiring, so we only need
+ * to check for clearing it when doing volatile dequeues. It's
+ * one less thing to check in the critical path (SDQCR). */
+ tmpRes = p_Fq->cb.dqrr(p_Fq->h_App, p_Fq->h_QmFqr, p_QmPortal, p_Fq->fqidOffset, (t_DpaaFD*)&p_Dq->fd);
+ if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
+ res = qman_cb_dqrr_pause;
+ /* Check for VDQCR completion */
+ if (p_Dq->stat & QM_DQRR_STAT_DQCR_EXPIRED)
+ p_Fq->flags &= ~QMAN_FQ_STATE_VDQCR;
+ if (p_Dq->stat & QM_DQRR_STAT_FQ_EMPTY)
+ {
+ p_Fq->flags &= ~QMAN_FQ_STATE_NE;
+ freeDrainedFq(p_Fq);
+ }
+ }
+ else
+ {
+ /* Interpret 'dq' from the owner's perspective. */
+ /* use portal default handlers */
+ ASSERT_COND(p_Dq->fqid);
+ if (p_Fq)
+ {
+ tmpRes = p_Fq->cb.dqrr(p_Fq->h_App,
+ p_Fq->h_QmFqr,
+ p_QmPortal,
+ p_Fq->fqidOffset,
+ (t_DpaaFD*)&p_Dq->fd);
+ if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
+ res = qman_cb_dqrr_pause;
+ else if (p_Fq->state == qman_fq_state_waiting_parked)
+ res = qman_cb_dqrr_park;
+ }
+ else
+ {
+ tmpRes = p_QmPortal->p_NullCB->dqrr(p_QmPortal->h_App,
+ NULL,
+ p_QmPortal,
+ p_Dq->fqid,
+ (t_DpaaFD*)&p_Dq->fd);
+ if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
+ res = qman_cb_dqrr_pause;
+ }
+ }
+
+ /* Parking isn't possible unless HELDACTIVE was set. NB,
+ * FORCEELIGIBLE implies HELDACTIVE, so we only need to
+ * check for HELDACTIVE to cover both. */
+ ASSERT_COND((p_Dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) ||
+ (res != qman_cb_dqrr_park));
+ if (p_QmPortal->options & QMAN_PORTAL_FLAG_DCA) {
+ /* Defer just means "skip it, I'll consume it myself later on" */
+ if (res != qman_cb_dqrr_defer)
+ qmPortalDqrrDcaConsume1ptr(p_QmPortal->p_LowQmPortal,
+ p_Dq,
+ (res == qman_cb_dqrr_park));
+ qm_dqrr_next(p_QmPortal->p_LowQmPortal);
+ } else {
+ if (res == qman_cb_dqrr_park)
+ /* The only thing to do for non-DCA is the park-request */
+ qm_dqrr_park_ci(p_QmPortal->p_LowQmPortal);
+ qm_dqrr_next(p_QmPortal->p_LowQmPortal);
+ qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
+ }
+ }
+}
+
+static void LoopDequeueRingDcaOptimized(t_Handle h_QmPortal)
+{
+ struct qm_dqrr_entry *p_Dq;
+ struct qman_fq *p_Fq;
+ enum qman_cb_dqrr_result res = qman_cb_dqrr_consume;
+ e_RxStoreResponse tmpRes;
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ while (res != qman_cb_dqrr_pause)
+ {
+ qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
+ p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
+ if (!p_Dq)
+ break;
+ p_Fq = (void *)p_Dq->contextB;
+ if (p_Dq->stat & QM_DQRR_STAT_UNSCHEDULED) {
+ /* We only set QMAN_FQ_STATE_NE when retiring, so we only need
+ * to check for clearing it when doing volatile dequeues. It's
+ * one less thing to check in the critical path (SDQCR). */
+ tmpRes = p_Fq->cb.dqrr(p_Fq->h_App, p_Fq->h_QmFqr, p_QmPortal, p_Fq->fqidOffset, (t_DpaaFD*)&p_Dq->fd);
+ if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
+ res = qman_cb_dqrr_pause;
+ /* Check for VDQCR completion */
+ if (p_Dq->stat & QM_DQRR_STAT_DQCR_EXPIRED)
+ p_Fq->flags &= ~QMAN_FQ_STATE_VDQCR;
+ if (p_Dq->stat & QM_DQRR_STAT_FQ_EMPTY)
+ {
+ p_Fq->flags &= ~QMAN_FQ_STATE_NE;
+ freeDrainedFq(p_Fq);
+ }
+ }
+ else
+ {
+ /* Interpret 'dq' from the owner's perspective. */
+ /* use portal default handlers */
+ ASSERT_COND(p_Dq->fqid);
+ if (p_Fq)
+ {
+ tmpRes = p_Fq->cb.dqrr(p_Fq->h_App,
+ p_Fq->h_QmFqr,
+ p_QmPortal,
+ p_Fq->fqidOffset,
+ (t_DpaaFD*)&p_Dq->fd);
+ if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
+ res = qman_cb_dqrr_pause;
+ else if (p_Fq->state == qman_fq_state_waiting_parked)
+ res = qman_cb_dqrr_park;
+ }
+ else
+ {
+ tmpRes = p_QmPortal->p_NullCB->dqrr(p_QmPortal->h_App,
+ NULL,
+ p_QmPortal,
+ p_Dq->fqid,
+ (t_DpaaFD*)&p_Dq->fd);
+ if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
+ res = qman_cb_dqrr_pause;
+ }
+ }
+
+ /* Parking isn't possible unless HELDACTIVE was set. NB,
+ * FORCEELIGIBLE implies HELDACTIVE, so we only need to
+ * check for HELDACTIVE to cover both. */
+ ASSERT_COND((p_Dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) ||
+ (res != qman_cb_dqrr_park));
+ /* Defer just means "skip it, I'll consume it myself later on" */
+ if (res != qman_cb_dqrr_defer)
+ qmPortalDqrrDcaConsume1ptr(p_QmPortal->p_LowQmPortal,
+ p_Dq,
+ (res == qman_cb_dqrr_park));
+ qm_dqrr_next(p_QmPortal->p_LowQmPortal);
+ }
+}
+
+static void LoopDequeueRingOptimized(t_Handle h_QmPortal)
+{
+ struct qm_dqrr_entry *p_Dq;
+ struct qman_fq *p_Fq;
+ enum qman_cb_dqrr_result res = qman_cb_dqrr_consume;
+ e_RxStoreResponse tmpRes;
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ while (res != qman_cb_dqrr_pause)
+ {
+ qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
+ p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
+ if (!p_Dq)
+ break;
+ p_Fq = (void *)p_Dq->contextB;
+ if (p_Dq->stat & QM_DQRR_STAT_UNSCHEDULED) {
+ /* We only set QMAN_FQ_STATE_NE when retiring, so we only need
+ * to check for clearing it when doing volatile dequeues. It's
+ * one less thing to check in the critical path (SDQCR). */
+ tmpRes = p_Fq->cb.dqrr(p_Fq->h_App, p_Fq->h_QmFqr, p_QmPortal, p_Fq->fqidOffset, (t_DpaaFD*)&p_Dq->fd);
+ if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
+ res = qman_cb_dqrr_pause;
+ /* Check for VDQCR completion */
+ if (p_Dq->stat & QM_DQRR_STAT_DQCR_EXPIRED)
+ p_Fq->flags &= ~QMAN_FQ_STATE_VDQCR;
+ if (p_Dq->stat & QM_DQRR_STAT_FQ_EMPTY)
+ {
+ p_Fq->flags &= ~QMAN_FQ_STATE_NE;
+ freeDrainedFq(p_Fq);
+ }
+ }
+ else
+ {
+ /* Interpret 'dq' from the owner's perspective. */
+ /* use portal default handlers */
+ ASSERT_COND(p_Dq->fqid);
+ if (p_Fq)
+ {
+ tmpRes = p_Fq->cb.dqrr(p_Fq->h_App,
+ p_Fq->h_QmFqr,
+ p_QmPortal,
+ p_Fq->fqidOffset,
+ (t_DpaaFD*)&p_Dq->fd);
+ if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
+ res = qman_cb_dqrr_pause;
+ else if (p_Fq->state == qman_fq_state_waiting_parked)
+ res = qman_cb_dqrr_park;
+ }
+ else
+ {
+ tmpRes = p_QmPortal->p_NullCB->dqrr(p_QmPortal->h_App,
+ NULL,
+ p_QmPortal,
+ p_Dq->fqid,
+ (t_DpaaFD*)&p_Dq->fd);
+ if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
+ res = qman_cb_dqrr_pause;
+ }
+ }
+
+ /* Parking isn't possible unless HELDACTIVE was set. NB,
+ * FORCEELIGIBLE implies HELDACTIVE, so we only need to
+ * check for HELDACTIVE to cover both. */
+ ASSERT_COND((p_Dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) ||
+ (res != qman_cb_dqrr_park));
+ if (res == qman_cb_dqrr_park)
+ /* The only thing to do for non-DCA is the park-request */
+ qm_dqrr_park_ci(p_QmPortal->p_LowQmPortal);
+ qm_dqrr_next(p_QmPortal->p_LowQmPortal);
+ qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
+ }
+}
+
+/* Portal interrupt handler */
+static void portal_isr(void *ptr)
+{
+ t_QmPortal *p_QmPortal = ptr;
+ uint32_t event = 0;
+ uint32_t enableEvents = qm_isr_enable_read(p_QmPortal->p_LowQmPortal);
+
+ DBG(TRACE, ("software-portal %d got interrupt", p_QmPortal->p_LowQmPortal->config.cpu));
+
+ event |= (qm_isr_status_read(p_QmPortal->p_LowQmPortal) &
+ enableEvents);
+
+ qm_isr_status_clear(p_QmPortal->p_LowQmPortal, event);
+ /* Only do fast-path handling if it's required */
+ if (/*(event & QM_PIRQ_DQRI) &&*/
+ (p_QmPortal->options & QMAN_PORTAL_FLAG_IRQ_FAST))
+ p_QmPortal->f_LoopDequeueRingCB(p_QmPortal);
+ if (p_QmPortal->options & QMAN_PORTAL_FLAG_IRQ_SLOW)
+ LoopMessageRing(p_QmPortal, event);
+}
+
+
+static t_Error qman_query_fq_np(t_QmPortal *p_QmPortal, struct qman_fq *p_Fq, struct qm_mcr_queryfq_np *p_Np)
+{
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+ uint8_t res;
+
+ NCSW_PLOCK(p_QmPortal);
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->queryfq_np.fqid = p_Fq->fqid;
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYFQ_NP);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP);
+ res = p_Mcr->result;
+ if (res == QM_MCR_RESULT_OK)
+ *p_Np = p_Mcr->queryfq_np;
+ PUNLOCK(p_QmPortal);
+ if (res != QM_MCR_RESULT_OK)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("QUERYFQ_NP failed: %s\n", mcr_result_str(res)));
+ return E_OK;
+}
+
+static uint8_t QmCgGetCgId(t_Handle h_QmCg)
+{
+ t_QmCg *p_QmCg = (t_QmCg *)h_QmCg;
+
+ return p_QmCg->id;
+
+}
+
+static t_Error qm_new_fq(t_QmPortal *p_QmPortal,
+ uint32_t fqid,
+ uint32_t fqidOffset,
+ uint32_t channel,
+ uint32_t wqid,
+ uint16_t count,
+ uint32_t flags,
+ t_QmFqrCongestionAvoidanceParams *p_CgParams,
+ t_QmContextA *p_ContextA,
+ t_QmContextB *p_ContextB,
+ bool initParked,
+ t_Handle h_QmFqr,
+ struct qman_fq **p_Fqs)
+{
+ struct qman_fq *p_Fq = NULL;
+ struct qm_mcc_initfq fq_opts;
+ uint32_t i;
+ t_Error err = E_OK;
+ int gap, tmp;
+ uint32_t tmpA, tmpN, ta=0, tn=0, initFqFlag;
+
+ ASSERT_COND(p_QmPortal);
+ ASSERT_COND(count);
+
+ for(i=0;i<count;i++)
+ {
+ p_Fq = (struct qman_fq *)XX_MallocSmart(sizeof(struct qman_fq), 0, 64);
+ if (!p_Fq)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!"));
+ memset(p_Fq, 0, sizeof(struct qman_fq));
+ p_Fq->cb.dqrr = p_QmPortal->f_DfltFrame;
+ p_Fq->cb.ern = p_QmPortal->f_RejectedFrame;
+ p_Fq->cb.dc_ern = cb_ern_dcErn;
+ p_Fq->cb.fqs = cb_fqs;
+ p_Fq->h_App = p_QmPortal->h_App;
+ p_Fq->h_QmFqr = h_QmFqr;
+ p_Fq->fqidOffset = fqidOffset;
+ p_Fqs[i] = p_Fq;
+ if ((err = qman_create_fq(p_QmPortal,(uint32_t)(fqid + i), 0, p_Fqs[i])) != E_OK)
+ break;
+ }
+
+ if (err != E_OK)
+ {
+ for(i=0;i<count;i++)
+ if (p_Fqs[i])
+ {
+ XX_FreeSmart(p_Fqs[i]);
+ p_Fqs[i] = NULL;
+ }
+ RETURN_ERROR(MINOR, err, ("Failed to create Fqs"));
+ }
+
+ memset(&fq_opts,0,sizeof(fq_opts));
+ fq_opts.fqid = fqid;
+ fq_opts.count = (uint16_t)(count-1);
+ fq_opts.we_mask |= QM_INITFQ_WE_DESTWQ;
+ fq_opts.fqd.dest.channel = channel;
+ fq_opts.fqd.dest.wq = wqid;
+ fq_opts.we_mask |= QM_INITFQ_WE_FQCTRL;
+ fq_opts.fqd.fq_ctrl = (uint16_t)flags;
+
+ if ((flags & QM_FQCTRL_CGE) || (flags & QM_FQCTRL_TDE))
+ ASSERT_COND(p_CgParams);
+
+ if(flags & QM_FQCTRL_CGE)
+ {
+ ASSERT_COND(p_CgParams->h_QmCg);
+
+ /* CG OAC and FQ TD may not be configured at the same time. if both are required,
+ than we configure CG first, and the FQ TD later - see below. */
+ fq_opts.fqd.cgid = QmCgGetCgId(p_CgParams->h_QmCg);
+ fq_opts.we_mask |= QM_INITFQ_WE_CGID;
+ if(p_CgParams->overheadAccountingLength)
+ {
+ fq_opts.we_mask |= QM_INITFQ_WE_OAC;
+ fq_opts.we_mask &= ~QM_INITFQ_WE_TDTHRESH;
+ fq_opts.fqd.td_thresh = (uint16_t)(QM_FQD_TD_THRESH_OAC_EN | p_CgParams->overheadAccountingLength);
+ }
+ }
+ if((flags & QM_FQCTRL_TDE) && (!p_CgParams->overheadAccountingLength))
+ {
+ ASSERT_COND(p_CgParams->fqTailDropThreshold);
+
+ fq_opts.we_mask |= QM_INITFQ_WE_TDTHRESH;
+
+ /* express thresh as ta*2^tn */
+ gap = (int)p_CgParams->fqTailDropThreshold;
+ for (tmpA=0 ; tmpA<256; tmpA++ )
+ for (tmpN=0 ; tmpN<32; tmpN++ )
+ {
+ tmp = ABS((int)(p_CgParams->fqTailDropThreshold - tmpA*(1<<tmpN)));
+ if (tmp < gap)
+ {
+ ta = tmpA;
+ tn = tmpN;
+ gap = tmp;
+ }
+ }
+ fq_opts.fqd.td.exp = tn;
+ fq_opts.fqd.td.mant = ta;
+ }
+
+ if (p_ContextA)
+ {
+ fq_opts.we_mask |= QM_INITFQ_WE_CONTEXTA;
+ memcpy((void*)&fq_opts.fqd.context_a, p_ContextA, sizeof(t_QmContextA));
+ }
+ /* If this FQ will not be used for tx, we can use contextB field */
+ if (fq_opts.fqd.dest.channel < e_QM_FQ_CHANNEL_FMAN0_SP0)
+ {
+ if (sizeof(p_Fqs[0]) <= sizeof(fq_opts.fqd.context_b))
+ {
+ fq_opts.we_mask |= QM_INITFQ_WE_CONTEXTB;
+ fq_opts.fqd.context_b = (uint32_t)PTR_TO_UINT(p_Fqs[0]);
+ }
+ else
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("64 bit pointer (virtual) not supported yet!!!"));
+ }
+ else if (p_ContextB) /* Tx-Queue */
+ {
+ fq_opts.we_mask |= QM_INITFQ_WE_CONTEXTB;
+ memcpy((void*)&fq_opts.fqd.context_b, p_ContextB, sizeof(t_QmContextB));
+ }
+
+ if((flags & QM_FQCTRL_TDE) && (p_CgParams->overheadAccountingLength))
+ initFqFlag = 0;
+ else
+ initFqFlag = (uint32_t)(initParked?0:QMAN_INITFQ_FLAG_SCHED);
+
+ if ((err = qman_init_fq(p_QmPortal, p_Fqs[0], initFqFlag, &fq_opts)) != E_OK)
+ {
+ for(i=0;i<count;i++)
+ if (p_Fqs[i])
+ {
+ XX_FreeSmart(p_Fqs[i]);
+ p_Fqs[i] = NULL;
+ }
+ RETURN_ERROR(MINOR, err, ("Failed to init Fqs [%d-%d]", fqid, fqid+count-1));
+ }
+
+ /* if both CG OAC and FQ TD are needed, we call qman_init_fq again, this time for the FQ TD only */
+ if((flags & QM_FQCTRL_TDE) && (p_CgParams->overheadAccountingLength))
+ {
+ ASSERT_COND(p_CgParams->fqTailDropThreshold);
+
+ fq_opts.we_mask = QM_INITFQ_WE_TDTHRESH;
+
+ /* express thresh as ta*2^tn */
+ gap = (int)p_CgParams->fqTailDropThreshold;
+ for (tmpA=0 ; tmpA<256; tmpA++ )
+ for (tmpN=0 ; tmpN<32; tmpN++ )
+ {
+ tmp = ABS((int)(p_CgParams->fqTailDropThreshold - tmpA*(1<<tmpN)));
+ if (tmp < gap)
+ {
+ ta = tmpA;
+ tn = tmpN;
+ gap = tmp;
+ }
+ }
+ fq_opts.fqd.td.exp = tn;
+ fq_opts.fqd.td.mant = ta;
+ if ((err = qman_init_fq(p_QmPortal, p_Fqs[0], (uint32_t)(initParked?0:QMAN_INITFQ_FLAG_SCHED), &fq_opts)) != E_OK)
+ {
+ for(i=0;i<count;i++)
+ if (p_Fqs[i])
+ {
+ XX_FreeSmart(p_Fqs[i]);
+ p_Fqs[i] = NULL;
+ }
+ RETURN_ERROR(MINOR, err, ("Failed to init Fqs"));
+ }
+ }
+
+
+ for(i=1;i<count;i++)
+ {
+ memcpy(p_Fqs[i], p_Fqs[0], sizeof(struct qman_fq));
+ p_Fqs[i]->fqid += i;
+ }
+
+ return err;
+}
+
+
+static t_Error qm_free_fq(t_QmPortal *p_QmPortal, struct qman_fq *p_Fq)
+{
+ uint32_t flags=0;
+
+ if (qman_retire_fq(p_QmPortal, p_Fq, &flags, FALSE) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_retire_fq() failed!"));
+
+ if (flags & QMAN_FQ_STATE_CHANGING)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("fq %d currently in use, will be retired", p_Fq->fqid));
+
+ if (flags & QMAN_FQ_STATE_NE)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_retire_fq() failed;" \
+ "Frame Queue Not Empty, Need to dequeue"));
+
+ if (qman_oos_fq(p_QmPortal, p_Fq) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_oos_fq() failed!"));
+
+ qman_destroy_fq(p_Fq,0);
+
+ return E_OK;
+}
+
+static void qman_disable_portal(t_QmPortal *p_QmPortal)
+{
+ NCSW_PLOCK(p_QmPortal);
+ if (!(p_QmPortal->disable_count++))
+ qm_dqrr_set_maxfill(p_QmPortal->p_LowQmPortal, 0);
+ PUNLOCK(p_QmPortal);
+}
+
+
+/* quiesce SDQCR/VDQCR, then drain till h/w wraps up anything it
+ * was doing (5ms is more than enough to ensure it's done). */
+static void clean_dqrr_mr(t_QmPortal *p_QmPortal)
+{
+ struct qm_dqrr_entry *p_Dq;
+ struct qm_mr_entry *p_Msg;
+ int idle = 0;
+
+ qm_dqrr_sdqcr_set(p_QmPortal->p_LowQmPortal, 0);
+ qm_dqrr_vdqcr_set(p_QmPortal->p_LowQmPortal, 0);
+drain_loop:
+ qmPortalDqrrPvbPrefetch(p_QmPortal->p_LowQmPortal);
+ qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
+ qmPortalMrPvbUpdate(p_QmPortal->p_LowQmPortal);
+ p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
+ p_Msg = qm_mr_current(p_QmPortal->p_LowQmPortal);
+ if (p_Dq) {
+ qm_dqrr_next(p_QmPortal->p_LowQmPortal);
+ qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
+ }
+ if (p_Msg) {
+ qm_mr_next(p_QmPortal->p_LowQmPortal);
+ qmPortalMrCciConsume(p_QmPortal->p_LowQmPortal, 1);
+ }
+ if (!p_Dq && !p_Msg) {
+ if (++idle < 5) {
+ XX_UDelay(1000);
+ goto drain_loop;
+ }
+ } else {
+ idle = 0;
+ goto drain_loop;
+ }
+}
+
+static t_Error qman_create_portal(t_QmPortal *p_QmPortal,
+ uint32_t flags,
+ uint32_t sdqcrFlags,
+ uint8_t dqrrSize)
+{
+ const struct qm_portal_config *p_Config = &(p_QmPortal->p_LowQmPortal->config);
+ int ret = 0;
+ t_Error err;
+ uint32_t isdr;
+
+ if ((err = qm_eqcr_init(p_QmPortal->p_LowQmPortal, e_QmPortalPVB, e_QmPortalEqcrCCE)) != E_OK)
+ RETURN_ERROR(MINOR, err, ("Qman EQCR initialization failed\n"));
+
+ if (qm_dqrr_init(p_QmPortal->p_LowQmPortal,
+ sdqcrFlags ? e_QmPortalDequeuePushMode : e_QmPortalDequeuePullMode,
+ e_QmPortalPVB,
+ (flags & QMAN_PORTAL_FLAG_DCA) ? e_QmPortalDqrrDCA : e_QmPortalDqrrCCI,
+ dqrrSize,
+ (flags & QMAN_PORTAL_FLAG_RSTASH) ? 1 : 0,
+ (flags & QMAN_PORTAL_FLAG_DSTASH) ? 1 : 0)) {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("DQRR initialization failed"));
+ goto fail_dqrr;
+ }
+
+ if (qm_mr_init(p_QmPortal->p_LowQmPortal, e_QmPortalPVB, e_QmPortalMrCCI)) {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("MR initialization failed"));
+ goto fail_mr;
+ }
+ if (qm_mc_init(p_QmPortal->p_LowQmPortal)) {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("MC initialization failed"));
+ goto fail_mc;
+ }
+ if (qm_isr_init(p_QmPortal->p_LowQmPortal)) {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("ISR initialization failed"));
+ goto fail_isr;
+ }
+ /* static interrupt-gating controls */
+ qm_dqrr_set_ithresh(p_QmPortal->p_LowQmPortal, 12);
+ qm_mr_set_ithresh(p_QmPortal->p_LowQmPortal, 4);
+ qm_isr_set_iperiod(p_QmPortal->p_LowQmPortal, 100);
+ p_QmPortal->options = flags;
+ isdr = 0xffffffff;
+ qm_isr_status_clear(p_QmPortal->p_LowQmPortal, 0xffffffff);
+ qm_isr_enable_write(p_QmPortal->p_LowQmPortal, DEFAULT_portalExceptions);
+ qm_isr_disable_write(p_QmPortal->p_LowQmPortal, isdr);
+ if (flags & QMAN_PORTAL_FLAG_IRQ)
+ {
+ XX_SetIntr(p_Config->irq, portal_isr, p_QmPortal);
+ XX_EnableIntr(p_Config->irq);
+ qm_isr_uninhibit(p_QmPortal->p_LowQmPortal);
+ } else
+ /* without IRQ, we can't block */
+ flags &= ~QMAN_PORTAL_FLAG_WAIT;
+ /* Need EQCR to be empty before continuing */
+ isdr ^= QM_PIRQ_EQCI;
+ qm_isr_disable_write(p_QmPortal->p_LowQmPortal, isdr);
+ ret = qm_eqcr_get_fill(p_QmPortal->p_LowQmPortal);
+ if (ret) {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("EQCR unclean"));
+ goto fail_eqcr_empty;
+ }
+ isdr ^= (QM_PIRQ_DQRI | QM_PIRQ_MRI);
+ qm_isr_disable_write(p_QmPortal->p_LowQmPortal, isdr);
+ if (qm_dqrr_current(p_QmPortal->p_LowQmPortal) != NULL)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("DQRR unclean"));
+goto fail_dqrr_mr_empty;
+ }
+ if (qm_mr_current(p_QmPortal->p_LowQmPortal) != NULL)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("MR unclean"));
+goto fail_dqrr_mr_empty;
+ }
+ qm_isr_disable_write(p_QmPortal->p_LowQmPortal, 0);
+ qm_dqrr_sdqcr_set(p_QmPortal->p_LowQmPortal, sdqcrFlags);
+ return E_OK;
+fail_dqrr_mr_empty:
+fail_eqcr_empty:
+ qm_isr_finish(p_QmPortal->p_LowQmPortal);
+fail_isr:
+ qm_mc_finish(p_QmPortal->p_LowQmPortal);
+fail_mc:
+ qm_mr_finish(p_QmPortal->p_LowQmPortal);
+fail_mr:
+ qm_dqrr_finish(p_QmPortal->p_LowQmPortal);
+fail_dqrr:
+ qm_eqcr_finish(p_QmPortal->p_LowQmPortal);
+ return ERROR_CODE(E_INVALID_STATE);
+}
+
+static void qman_destroy_portal(t_QmPortal *p_QmPortal)
+{
+ /* NB we do this to "quiesce" EQCR. If we add enqueue-completions or
+ * something related to QM_PIRQ_EQCI, this may need fixing. */
+ qmPortalEqcrCceUpdate(p_QmPortal->p_LowQmPortal);
+ if (p_QmPortal->options & QMAN_PORTAL_FLAG_IRQ)
+ {
+ XX_DisableIntr(p_QmPortal->p_LowQmPortal->config.irq);
+ XX_FreeIntr(p_QmPortal->p_LowQmPortal->config.irq);
+ }
+ qm_isr_finish(p_QmPortal->p_LowQmPortal);
+ qm_mc_finish(p_QmPortal->p_LowQmPortal);
+ qm_mr_finish(p_QmPortal->p_LowQmPortal);
+ qm_dqrr_finish(p_QmPortal->p_LowQmPortal);
+ qm_eqcr_finish(p_QmPortal->p_LowQmPortal);
+}
+
+static inline struct qm_eqcr_entry *try_eq_start(t_QmPortal *p_QmPortal)
+{
+ struct qm_eqcr_entry *p_Eq;
+ uint8_t avail;
+
+ avail = qm_eqcr_get_avail(p_QmPortal->p_LowQmPortal);
+ if (avail == EQCR_THRESH)
+ qmPortalEqcrCcePrefetch(p_QmPortal->p_LowQmPortal);
+ else if (avail < EQCR_THRESH)
+ qmPortalEqcrCceUpdate(p_QmPortal->p_LowQmPortal);
+ p_Eq = qm_eqcr_start(p_QmPortal->p_LowQmPortal);
+
+ return p_Eq;
+}
+
+
+static t_Error qman_orp_update(t_QmPortal *p_QmPortal,
+ uint32_t orpId,
+ uint16_t orpSeqnum,
+ uint32_t flags)
+{
+ struct qm_eqcr_entry *p_Eq;
+
+ NCSW_PLOCK(p_QmPortal);
+ p_Eq = try_eq_start(p_QmPortal);
+ if (!p_Eq)
+ {
+ PUNLOCK(p_QmPortal);
+ return ERROR_CODE(E_BUSY);
+ }
+
+ if (flags & QMAN_ENQUEUE_FLAG_NESN)
+ orpSeqnum |= QM_EQCR_SEQNUM_NESN;
+ else
+ /* No need to check 4 QMAN_ENQUEUE_FLAG_HOLE */
+ orpSeqnum &= ~QM_EQCR_SEQNUM_NESN;
+ p_Eq->seqnum = orpSeqnum;
+ p_Eq->orp = orpId;
+qmPortalEqcrPvbCommit(p_QmPortal->p_LowQmPortal, (uint8_t)QM_EQCR_VERB_ORP);
+
+ PUNLOCK(p_QmPortal);
+ return E_OK;
+}
+
+static __inline__ t_Error CheckStashParams(t_QmFqrParams *p_QmFqrParams)
+{
+ ASSERT_COND(p_QmFqrParams);
+
+ if (p_QmFqrParams->stashingParams.frameAnnotationSize > QM_CONTEXTA_MAX_STASH_SIZE)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Frame Annotation Size Exceeded Max Stash Size(%d)", QM_CONTEXTA_MAX_STASH_SIZE));
+ if (p_QmFqrParams->stashingParams.frameDataSize > QM_CONTEXTA_MAX_STASH_SIZE)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Frame Data Size Exceeded Max Stash Size(%d)", QM_CONTEXTA_MAX_STASH_SIZE));
+ if (p_QmFqrParams->stashingParams.fqContextSize > QM_CONTEXTA_MAX_STASH_SIZE)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Frame Context Size Exceeded Max Stash Size(%d)", QM_CONTEXTA_MAX_STASH_SIZE));
+ if (p_QmFqrParams->stashingParams.fqContextSize)
+ {
+ if (!p_QmFqrParams->stashingParams.fqContextAddr)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FQ Context Address Must be givven"));
+ if (!IS_ALIGNED(p_QmFqrParams->stashingParams.fqContextAddr, CACHELINE_SIZE))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FQ Context Address Must be aligned to %d", CACHELINE_SIZE));
+ if (p_QmFqrParams->stashingParams.fqContextAddr & 0xffffff0000000000LL)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FQ Context Address May be up to 40 bit"));
+ }
+
+ return E_OK;
+}
+
+static t_Error QmPortalRegisterCg(t_Handle h_QmPortal, t_Handle h_QmCg, uint8_t cgId)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ /* cgrs[0] is the mask of registered CG's*/
+ if(p_QmPortal->cgrs[0].q.__state[cgId/32] & (0x80000000 >> (cgId % 32)))
+ RETURN_ERROR(MINOR, E_BUSY, ("CG already used"));
+
+ p_QmPortal->cgrs[0].q.__state[cgId/32] |= 0x80000000 >> (cgId % 32);
+ p_QmPortal->cgsHandles[cgId] = h_QmCg;
+
+ return E_OK;
+}
+
+static t_Error QmPortalUnregisterCg(t_Handle h_QmPortal, uint8_t cgId)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ /* cgrs[0] is the mask of registered CG's*/
+ if(!(p_QmPortal->cgrs[0].q.__state[cgId/32] & (0x80000000 >> (cgId % 32))))
+ RETURN_ERROR(MINOR, E_BUSY, ("CG is not in use"));
+
+ p_QmPortal->cgrs[0].q.__state[cgId/32] &= ~0x80000000 >> (cgId % 32);
+ p_QmPortal->cgsHandles[cgId] = NULL;
+
+ return E_OK;
+}
+
+static e_DpaaSwPortal QmPortalGetSwPortalId(t_Handle h_QmPortal)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ return (e_DpaaSwPortal)p_QmPortal->p_LowQmPortal->config.cpu;
+}
+
+static t_Error CalcWredCurve(t_QmCgWredCurve *p_WredCurve, uint32_t *p_CurveWord)
+{
+ uint32_t maxP, roundDown, roundUp, tmpA, tmpN;
+ uint32_t ma=0, mn=0, slope, sa=0, sn=0, pn;
+ int pres = 1000;
+ int gap, tmp;
+
+/* TODO - change maxTh to uint64_t?
+ if(p_WredCurve->maxTh > (1<<39))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("maxTh is not in range"));*/
+
+ /* express maxTh as ma*2^mn */
+ gap = (int)p_WredCurve->maxTh;
+ for (tmpA=0 ; tmpA<256; tmpA++ )
+ for (tmpN=0 ; tmpN<32; tmpN++ )
+ {
+ tmp = ABS((int)(p_WredCurve->maxTh - tmpA*(1<<tmpN)));
+ if (tmp < gap)
+ {
+ ma = tmpA;
+ mn = tmpN;
+ gap = tmp;
+ }
+ }
+ ASSERT_COND(ma <256);
+ ASSERT_COND(mn <32);
+ p_WredCurve->maxTh = ma*(1<<mn);
+
+ if(p_WredCurve->maxTh <= p_WredCurve->minTh)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("maxTh must be larger than minTh"));
+ if(p_WredCurve->probabilityDenominator > 64)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("probabilityDenominator mustn't be 1-64"));
+
+ /* first we translate from Cisco probabilityDenominator
+ to 256 fixed denominator, result must be divisible by 4. */
+ /* we multiply by a fixed value to get better accuracy (without
+ using floating point) */
+ maxP = (uint32_t)(256*1000/p_WredCurve->probabilityDenominator);
+ if (maxP % 4*pres)
+ {
+ roundDown = maxP + (maxP % (4*pres));
+ roundUp = roundDown + 4*pres;
+ if((roundUp - maxP) > (maxP - roundDown))
+ maxP = roundDown;
+ else
+ maxP = roundUp;
+ }
+ maxP = maxP/pres;
+ ASSERT_COND(maxP <= 256);
+ pn = (uint8_t)(maxP/4 - 1);
+
+ if(maxP >= (p_WredCurve->maxTh - p_WredCurve->minTh))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Due to probabilityDenominator selected, maxTh-minTh must be larger than %d", maxP));
+
+ pres = 1000000;
+ slope = maxP*pres/(p_WredCurve->maxTh - p_WredCurve->minTh);
+ /* express slope as sa/2^sn */
+ gap = (int)slope;
+ for (tmpA=(uint32_t)(64*pres) ; tmpA<128*pres; tmpA += pres )
+ for (tmpN=7 ; tmpN<64; tmpN++ )
+ {
+ tmp = ABS((int)(slope - tmpA/(1<<tmpN)));
+ if (tmp < gap)
+ {
+ sa = tmpA;
+ sn = tmpN;
+ gap = tmp;
+ }
+ }
+ sa = sa/pres;
+ ASSERT_COND(sa<128 && sa>=64);
+ sn = sn;
+ ASSERT_COND(sn<64 && sn>=7);
+
+ *p_CurveWord = ((ma << 24) |
+ (mn << 19) |
+ (sa << 12) |
+ (sn << 6) |
+ pn);
+
+ return E_OK;
+}
+
+static t_Error QmPortalPullFrame(t_Handle h_QmPortal, uint32_t pdqcr, t_DpaaFD *p_Frame)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+ struct qm_dqrr_entry *p_Dq;
+ struct qman_fq *p_Fq;
+ int prefetch;
+ uint32_t *p_Dst, *p_Src;
+
+ ASSERT_COND(p_QmPortal);
+ ASSERT_COND(p_Frame);
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal->pullMode, E_INVALID_STATE);
+
+ NCSW_PLOCK(p_QmPortal);
+
+ qm_dqrr_pdqcr_set(p_QmPortal->p_LowQmPortal, pdqcr);
+ CORE_MemoryBarrier();
+ while (qm_dqrr_pdqcr_get(p_QmPortal->p_LowQmPortal)) ;
+
+ prefetch = !(p_QmPortal->options & QMAN_PORTAL_FLAG_RSTASH);
+ while(TRUE)
+ {
+ if (prefetch)
+ qmPortalDqrrPvbPrefetch(p_QmPortal->p_LowQmPortal);
+ qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
+ p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
+ if (!p_Dq)
+ continue;
+ p_Fq = (void *)p_Dq->contextB;
+ ASSERT_COND(p_Dq->fqid);
+ p_Dst = (uint32_t *)p_Frame;
+ p_Src = (uint32_t *)&p_Dq->fd;
+ p_Dst[0] = p_Src[0];
+ p_Dst[1] = p_Src[1];
+ p_Dst[2] = p_Src[2];
+ p_Dst[3] = p_Src[3];
+ if (p_QmPortal->options & QMAN_PORTAL_FLAG_DCA)
+ {
+ qmPortalDqrrDcaConsume1ptr(p_QmPortal->p_LowQmPortal,
+ p_Dq,
+ FALSE);
+ qm_dqrr_next(p_QmPortal->p_LowQmPortal);
+ }
+ else
+ {
+ qm_dqrr_next(p_QmPortal->p_LowQmPortal);
+ qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
+ }
+ break;
+ }
+
+ PUNLOCK(p_QmPortal);
+
+ if (!(p_Dq->stat & QM_DQRR_STAT_FD_VALID))
+ return ERROR_CODE(E_EMPTY);
+
+ return E_OK;
+}
+
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+t_Handle QM_PORTAL_Config(t_QmPortalParam *p_QmPortalParam)
+{
+ t_QmPortal *p_QmPortal;
+ uint32_t i;
+
+ SANITY_CHECK_RETURN_VALUE(p_QmPortalParam, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_QmPortalParam->swPortalId < DPAA_MAX_NUM_OF_SW_PORTALS, E_INVALID_VALUE, 0);
+
+ p_QmPortal = (t_QmPortal *)XX_Malloc(sizeof(t_QmPortal));
+ if (!p_QmPortal)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Qm Portal obj!!!"));
+ return NULL;
+ }
+ memset(p_QmPortal, 0, sizeof(t_QmPortal));
+
+ p_QmPortal->p_LowQmPortal = (struct qm_portal *)XX_Malloc(sizeof(struct qm_portal));
+ if (!p_QmPortal->p_LowQmPortal)
+ {
+ XX_Free(p_QmPortal);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Low qm p_QmPortal obj!!!"));
+ return NULL;
+ }
+ memset(p_QmPortal->p_LowQmPortal, 0, sizeof(struct qm_portal));
+
+ p_QmPortal->p_QmPortalDriverParams = (t_QmPortalDriverParams *)XX_Malloc(sizeof(t_QmPortalDriverParams));
+ if (!p_QmPortal->p_QmPortalDriverParams)
+ {
+ XX_Free(p_QmPortal->p_LowQmPortal);
+ XX_Free(p_QmPortal);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Qm Portal driver parameters"));
+ return NULL;
+ }
+ memset(p_QmPortal->p_QmPortalDriverParams, 0, sizeof(t_QmPortalDriverParams));
+
+ p_QmPortal->p_LowQmPortal->addr.addr_ce = UINT_TO_PTR(p_QmPortalParam->ceBaseAddress);
+ p_QmPortal->p_LowQmPortal->addr.addr_ci = UINT_TO_PTR(p_QmPortalParam->ciBaseAddress);
+ p_QmPortal->p_LowQmPortal->config.irq = p_QmPortalParam->irq;
+ p_QmPortal->p_LowQmPortal->config.bound = 0;
+ p_QmPortal->p_LowQmPortal->config.cpu = (int)p_QmPortalParam->swPortalId;
+ p_QmPortal->p_LowQmPortal->config.channel = (e_QmFQChannel)(e_QM_FQ_CHANNEL_SWPORTAL0 + p_QmPortalParam->swPortalId);
+ p_QmPortal->p_LowQmPortal->bind_lock = XX_InitSpinlock();
+
+ p_QmPortal->h_Qm = p_QmPortalParam->h_Qm;
+ p_QmPortal->f_DfltFrame = p_QmPortalParam->f_DfltFrame;
+ p_QmPortal->f_RejectedFrame = p_QmPortalParam->f_RejectedFrame;
+ p_QmPortal->h_App = p_QmPortalParam->h_App;
+
+ p_QmPortal->p_QmPortalDriverParams->fdLiodnOffset = p_QmPortalParam->fdLiodnOffset;
+ p_QmPortal->p_QmPortalDriverParams->dequeueDcaMode = DEFAULT_dequeueDcaMode;
+ p_QmPortal->p_QmPortalDriverParams->dequeueUpToThreeFrames = DEFAULT_dequeueUpToThreeFrames;
+ p_QmPortal->p_QmPortalDriverParams->commandType = DEFAULT_dequeueCommandType;
+ p_QmPortal->p_QmPortalDriverParams->userToken = DEFAULT_dequeueUserToken;
+ p_QmPortal->p_QmPortalDriverParams->specifiedWq = DEFAULT_dequeueSpecifiedWq;
+ p_QmPortal->p_QmPortalDriverParams->dedicatedChannel = DEFAULT_dequeueDedicatedChannel;
+ p_QmPortal->p_QmPortalDriverParams->dedicatedChannelHasPrecedenceOverPoolChannels =
+ DEFAULT_dequeueDedicatedChannelHasPrecedenceOverPoolChannels;
+ p_QmPortal->p_QmPortalDriverParams->poolChannelId = DEFAULT_dequeuePoolChannelId;
+ p_QmPortal->p_QmPortalDriverParams->wqId = DEFAULT_dequeueWqId;
+ for (i=0;i<QM_MAX_NUM_OF_POOL_CHANNELS;i++)
+ p_QmPortal->p_QmPortalDriverParams->poolChannels[i] = FALSE;
+ p_QmPortal->p_QmPortalDriverParams->dqrrSize = DEFAULT_dqrrSize;
+ p_QmPortal->p_QmPortalDriverParams->pullMode = DEFAULT_pullMode;
+
+ return p_QmPortal;
+}
+
+t_Error QM_PORTAL_Init(t_Handle h_QmPortal)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+ uint32_t i, flags=0, sdqcrFlags=0;
+ t_Error err;
+ t_QmInterModulePortalInitParams qmParams;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal->p_QmPortalDriverParams, E_INVALID_HANDLE);
+
+ memset(&qmParams, 0, sizeof(qmParams));
+ qmParams.portalId = (uint8_t)p_QmPortal->p_LowQmPortal->config.cpu;
+ qmParams.liodn = p_QmPortal->p_QmPortalDriverParams->fdLiodnOffset;
+ qmParams.dqrrLiodn = p_QmPortal->p_QmPortalDriverParams->dqrrLiodn;
+ qmParams.fdFqLiodn = p_QmPortal->p_QmPortalDriverParams->fdFqLiodn;
+ qmParams.stashDestQueue = p_QmPortal->p_QmPortalDriverParams->stashDestQueue;
+ if ((err = QmGetSetPortalParams(p_QmPortal->h_Qm, &qmParams)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ flags = (uint32_t)(((p_QmPortal->p_LowQmPortal->config.irq == NO_IRQ) ?
+ 0 :
+ (QMAN_PORTAL_FLAG_IRQ |
+ QMAN_PORTAL_FLAG_IRQ_FAST |
+ QMAN_PORTAL_FLAG_IRQ_SLOW)));
+ flags |= ((p_QmPortal->p_QmPortalDriverParams->dequeueDcaMode) ? QMAN_PORTAL_FLAG_DCA : 0);
+ flags |= (p_QmPortal->p_QmPortalDriverParams->dqrr)?QMAN_PORTAL_FLAG_RSTASH:0;
+ flags |= (p_QmPortal->p_QmPortalDriverParams->fdFq)?QMAN_PORTAL_FLAG_DSTASH:0;
+
+ p_QmPortal->pullMode = p_QmPortal->p_QmPortalDriverParams->pullMode;
+ if (!p_QmPortal->pullMode)
+ {
+ sdqcrFlags |= (p_QmPortal->p_QmPortalDriverParams->dequeueUpToThreeFrames) ? QM_SDQCR_COUNT_UPTO3 : QM_SDQCR_COUNT_EXACT1;
+ sdqcrFlags |= QM_SDQCR_TOKEN_SET(p_QmPortal->p_QmPortalDriverParams->userToken);
+ sdqcrFlags |= QM_SDQCR_TYPE_SET(p_QmPortal->p_QmPortalDriverParams->commandType);
+ if (!p_QmPortal->p_QmPortalDriverParams->specifiedWq)
+ {
+ /* sdqcrFlags |= QM_SDQCR_SOURCE_CHANNELS;*/ /* removed as the macro is '0' */
+ sdqcrFlags |= (p_QmPortal->p_QmPortalDriverParams->dedicatedChannelHasPrecedenceOverPoolChannels) ? QM_SDQCR_DEDICATED_PRECEDENCE : 0;
+ sdqcrFlags |= (p_QmPortal->p_QmPortalDriverParams->dedicatedChannel) ? QM_SDQCR_CHANNELS_DEDICATED : 0;
+ for (i=0;i<QM_MAX_NUM_OF_POOL_CHANNELS;i++)
+ sdqcrFlags |= ((p_QmPortal->p_QmPortalDriverParams->poolChannels[i]) ?
+ QM_SDQCR_CHANNELS_POOL(i+1) : 0);
+ }
+ else
+ {
+ sdqcrFlags |= QM_SDQCR_SOURCE_SPECIFICWQ;
+ sdqcrFlags |= (p_QmPortal->p_QmPortalDriverParams->dedicatedChannel) ?
+ QM_SDQCR_SPECIFICWQ_DEDICATED : QM_SDQCR_SPECIFICWQ_POOL(p_QmPortal->p_QmPortalDriverParams->poolChannelId);
+ sdqcrFlags |= QM_SDQCR_SPECIFICWQ_WQ(p_QmPortal->p_QmPortalDriverParams->wqId);
+ }
+ }
+ if ((flags & QMAN_PORTAL_FLAG_RSTASH) && (flags & QMAN_PORTAL_FLAG_DCA))
+ p_QmPortal->f_LoopDequeueRingCB = LoopDequeueRingDcaOptimized;
+ else if ((flags & QMAN_PORTAL_FLAG_RSTASH) && !(flags & QMAN_PORTAL_FLAG_DCA))
+ p_QmPortal->f_LoopDequeueRingCB = LoopDequeueRingOptimized;
+ else
+ p_QmPortal->f_LoopDequeueRingCB = LoopDequeueRing;
+
+ if ((!p_QmPortal->f_RejectedFrame) || (!p_QmPortal->f_DfltFrame))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_RejectedFrame or f_DfltFrame callback not provided"));
+
+ p_QmPortal->p_NullCB = (struct qman_fq_cb *)XX_Malloc(sizeof(struct qman_fq_cb));
+ if (!p_QmPortal->p_NullCB)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FQ Null CB obj!!!"));
+ memset(p_QmPortal->p_NullCB, 0, sizeof(struct qman_fq_cb));
+
+ p_QmPortal->p_NullCB->dqrr = p_QmPortal->f_DfltFrame;
+ p_QmPortal->p_NullCB->ern = p_QmPortal->f_RejectedFrame;
+ p_QmPortal->p_NullCB->dc_ern = p_QmPortal->p_NullCB->fqs = null_cb_mr;
+
+ if (qman_create_portal(p_QmPortal, flags, sdqcrFlags, p_QmPortal->p_QmPortalDriverParams->dqrrSize) != E_OK)
+ {
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("create portal failed"));
+ }
+
+ QmSetPortalHandle(p_QmPortal->h_Qm, (t_Handle)p_QmPortal, (e_DpaaSwPortal)p_QmPortal->p_LowQmPortal->config.cpu);
+ XX_Free(p_QmPortal->p_QmPortalDriverParams);
+ p_QmPortal->p_QmPortalDriverParams = NULL;
+
+ DBG(TRACE, ("Qman-Portal %d @ %p:%p",
+ p_QmPortal->p_LowQmPortal->config.cpu,
+ p_QmPortal->p_LowQmPortal->addr.addr_ce,
+ p_QmPortal->p_LowQmPortal->addr.addr_ci
+ ));
+
+ DBG(TRACE, ("Qman-Portal %d phys @ 0x%016llx:0x%016llx",
+ p_QmPortal->p_LowQmPortal->config.cpu,
+ (uint64_t)XX_VirtToPhys(p_QmPortal->p_LowQmPortal->addr.addr_ce),
+ (uint64_t)XX_VirtToPhys(p_QmPortal->p_LowQmPortal->addr.addr_ci)
+ ));
+
+ return E_OK;
+}
+
+t_Error QM_PORTAL_Free(t_Handle h_QmPortal)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ if (!p_QmPortal)
+ return ERROR_CODE(E_INVALID_HANDLE);
+
+ ASSERT_COND(p_QmPortal->p_LowQmPortal);
+ QmSetPortalHandle(p_QmPortal->h_Qm, NULL, (e_DpaaSwPortal)p_QmPortal->p_LowQmPortal->config.cpu);
+ qman_destroy_portal(p_QmPortal);
+ if (p_QmPortal->p_NullCB)
+ XX_Free(p_QmPortal->p_NullCB);
+
+ if (p_QmPortal->p_LowQmPortal->bind_lock)
+ XX_FreeSpinlock(p_QmPortal->p_LowQmPortal->bind_lock);
+ if(p_QmPortal->p_QmPortalDriverParams)
+ XX_Free(p_QmPortal->p_QmPortalDriverParams);
+ XX_Free(p_QmPortal->p_LowQmPortal);
+ XX_Free(p_QmPortal);
+
+ return E_OK;
+}
+
+t_Error QM_PORTAL_ConfigDcaMode(t_Handle h_QmPortal, bool enable)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal->p_QmPortalDriverParams, E_INVALID_HANDLE);
+
+ p_QmPortal->p_QmPortalDriverParams->dequeueDcaMode = enable;
+
+ return E_OK;
+}
+
+t_Error QM_PORTAL_ConfigStash(t_Handle h_QmPortal, t_QmPortalStashParam *p_StashParams)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal->p_QmPortalDriverParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_StashParams, E_NULL_POINTER);
+
+ p_QmPortal->p_QmPortalDriverParams->stashDestQueue = p_StashParams->stashDestQueue;
+ p_QmPortal->p_QmPortalDriverParams->dqrrLiodn = p_StashParams->dqrrLiodn;
+ p_QmPortal->p_QmPortalDriverParams->fdFqLiodn = p_StashParams->fdFqLiodn;
+ p_QmPortal->p_QmPortalDriverParams->eqcr = p_StashParams->eqcr;
+ p_QmPortal->p_QmPortalDriverParams->eqcrHighPri = p_StashParams->eqcrHighPri;
+ p_QmPortal->p_QmPortalDriverParams->dqrr = p_StashParams->dqrr;
+ p_QmPortal->p_QmPortalDriverParams->dqrrHighPri = p_StashParams->dqrrHighPri;
+ p_QmPortal->p_QmPortalDriverParams->fdFq = p_StashParams->fdFq;
+ p_QmPortal->p_QmPortalDriverParams->fdFqHighPri = p_StashParams->fdFqHighPri;
+ p_QmPortal->p_QmPortalDriverParams->fdFqDrop = p_StashParams->fdFqDrop;
+
+ return E_OK;
+}
+
+
+t_Error QM_PORTAL_ConfigPullMode(t_Handle h_QmPortal, bool pullMode)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal->p_QmPortalDriverParams, E_NULL_POINTER);
+
+ p_QmPortal->p_QmPortalDriverParams->pullMode = pullMode;
+
+ return E_OK;
+}
+
+t_Error QM_PORTAL_AddPoolChannel(t_Handle h_QmPortal, uint8_t poolChannelId)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+ uint32_t sdqcrFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((poolChannelId < QM_MAX_NUM_OF_POOL_CHANNELS), E_INVALID_VALUE);
+
+ sdqcrFlags = qm_dqrr_sdqcr_get(p_QmPortal->p_LowQmPortal);
+ sdqcrFlags |= QM_SDQCR_CHANNELS_POOL(poolChannelId+1);
+ qm_dqrr_sdqcr_set(p_QmPortal->p_LowQmPortal, sdqcrFlags);
+
+ return E_OK;
+}
+
+t_Error QM_PORTAL_Poll(t_Handle h_QmPortal, e_QmPortalPollSource source)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
+
+ NCSW_PLOCK(p_QmPortal);
+
+ if ((source == e_QM_PORTAL_POLL_SOURCE_CONTROL_FRAMES) ||
+ (source == e_QM_PORTAL_POLL_SOURCE_BOTH))
+ {
+ uint32_t is = qm_isr_status_read(p_QmPortal->p_LowQmPortal);
+ uint32_t active = LoopMessageRing(p_QmPortal, is);
+ if (active)
+ qm_isr_status_clear(p_QmPortal->p_LowQmPortal, active);
+ }
+ if ((source == e_QM_PORTAL_POLL_SOURCE_DATA_FRAMES) ||
+ (source == e_QM_PORTAL_POLL_SOURCE_BOTH))
+ p_QmPortal->f_LoopDequeueRingCB((t_Handle)p_QmPortal);
+
+ PUNLOCK(p_QmPortal);
+
+ return E_OK;
+}
+
+t_Error QM_PORTAL_PollFrame(t_Handle h_QmPortal, t_QmPortalFrameInfo *p_frameInfo)
+{
+ t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
+ struct qm_dqrr_entry *p_Dq;
+ struct qman_fq *p_Fq;
+ int prefetch;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_frameInfo, E_NULL_POINTER);
+
+ NCSW_PLOCK(p_QmPortal);
+
+ prefetch = !(p_QmPortal->options & QMAN_PORTAL_FLAG_RSTASH);
+ if (prefetch)
+ qmPortalDqrrPvbPrefetch(p_QmPortal->p_LowQmPortal);
+ qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
+ p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
+ if (!p_Dq)
+ {
+ PUNLOCK(p_QmPortal);
+ return ERROR_CODE(E_EMPTY);
+ }
+ p_Fq = (void *)p_Dq->contextB;
+ ASSERT_COND(p_Dq->fqid);
+ if (p_Fq)
+ {
+ p_frameInfo->h_App = p_Fq->h_App;
+ p_frameInfo->h_QmFqr = p_Fq->h_QmFqr;
+ p_frameInfo->fqidOffset = p_Fq->fqidOffset;
+ memcpy((void*)&p_frameInfo->frame, (void*)&p_Dq->fd, sizeof(t_DpaaFD));
+ }
+ else
+ {
+ p_frameInfo->h_App = p_QmPortal->h_App;
+ p_frameInfo->h_QmFqr = NULL;
+ p_frameInfo->fqidOffset = p_Dq->fqid;
+ memcpy((void*)&p_frameInfo->frame, (void*)&p_Dq->fd, sizeof(t_DpaaFD));
+ }
+ if (p_QmPortal->options & QMAN_PORTAL_FLAG_DCA) {
+ qmPortalDqrrDcaConsume1ptr(p_QmPortal->p_LowQmPortal,
+ p_Dq,
+ FALSE);
+ qm_dqrr_next(p_QmPortal->p_LowQmPortal);
+ } else {
+ qm_dqrr_next(p_QmPortal->p_LowQmPortal);
+ qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
+ }
+
+ PUNLOCK(p_QmPortal);
+
+ return E_OK;
+}
+
+
+t_Handle QM_FQR_Create(t_QmFqrParams *p_QmFqrParams)
+{
+ t_QmFqr *p_QmFqr;
+ uint32_t i, flags = 0;
+ u_QmFqdContextA cnxtA;
+
+ SANITY_CHECK_RETURN_VALUE(p_QmFqrParams, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_QmFqrParams->h_Qm, E_INVALID_HANDLE, NULL);
+
+ if (p_QmFqrParams->shadowMode &&
+ (!p_QmFqrParams->useForce || p_QmFqrParams->numOfFqids != 1))
+ {
+ REPORT_ERROR(MAJOR, E_CONFLICT, ("shadowMode must be use with useForce and numOfFqids==1!!!"));
+ return NULL;
+ }
+
+ p_QmFqr = (t_QmFqr *)XX_MallocSmart(sizeof(t_QmFqr), 0, 64);
+ if (!p_QmFqr)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("QM FQR obj!!!"));
+ return NULL;
+ }
+ memset(p_QmFqr, 0, sizeof(t_QmFqr));
+
+ p_QmFqr->h_Qm = p_QmFqrParams->h_Qm;
+ p_QmFqr->h_QmPortal = p_QmFqrParams->h_QmPortal;
+ p_QmFqr->shadowMode = p_QmFqrParams->shadowMode;
+ p_QmFqr->numOfFqids = (p_QmFqrParams->useForce && !p_QmFqrParams->numOfFqids) ?
+ 1 : p_QmFqrParams->numOfFqids;
+
+ if (!p_QmFqr->h_QmPortal)
+ {
+ p_QmFqr->h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
+ SANITY_CHECK_RETURN_VALUE(p_QmFqr->h_QmPortal, E_INVALID_HANDLE, NULL);
+ }
+
+ p_QmFqr->p_Fqs = (struct qman_fq **)XX_Malloc(sizeof(struct qman_fq *) * p_QmFqr->numOfFqids);
+ if (!p_QmFqr->p_Fqs)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("QM FQs obj!!!"));
+ QM_FQR_Free(p_QmFqr);
+ return NULL;
+ }
+ memset(p_QmFqr->p_Fqs, 0, sizeof(struct qman_fq *) * p_QmFqr->numOfFqids);
+
+ if (p_QmFqr->shadowMode)
+ {
+ struct qman_fq *p_Fq = NULL;
+
+ p_QmFqr->fqidBase = p_QmFqrParams->qs.frcQ.fqid;
+ p_Fq = (struct qman_fq *)XX_MallocSmart(sizeof(struct qman_fq), 0, 64);
+ if (!p_Fq)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!"));
+ QM_FQR_Free(p_QmFqr);
+ return NULL;
+ }
+ memset(p_Fq, 0, sizeof(struct qman_fq));
+ p_Fq->cb.dqrr = ((t_QmPortal*)p_QmFqr->h_QmPortal)->f_DfltFrame;
+ p_Fq->cb.ern = ((t_QmPortal*)p_QmFqr->h_QmPortal)->f_RejectedFrame;
+ p_Fq->cb.dc_ern = cb_ern_dcErn;
+ p_Fq->cb.fqs = cb_fqs;
+ p_Fq->h_App = ((t_QmPortal*)p_QmFqr->h_QmPortal)->h_App;
+ p_Fq->h_QmFqr = p_QmFqr;
+ p_Fq->state = qman_fq_state_sched;
+ p_Fq->fqid = p_QmFqr->fqidBase;
+ p_QmFqr->p_Fqs[0] = p_Fq;
+ }
+ else
+ {
+ p_QmFqr->channel = p_QmFqrParams->channel;
+ p_QmFqr->workQueue = p_QmFqrParams->wq;
+
+ p_QmFqr->fqidBase = QmFqidGet(p_QmFqr->h_Qm,
+ p_QmFqr->numOfFqids,
+ p_QmFqrParams->qs.nonFrcQs.align,
+ p_QmFqrParams->useForce,
+ p_QmFqrParams->qs.frcQ.fqid);
+ if (p_QmFqr->fqidBase == (uint32_t)ILLEGAL_BASE)
+ {
+ REPORT_ERROR(CRITICAL,E_INVALID_STATE,("can't allocate a fqid"));
+ QM_FQR_Free(p_QmFqr);
+ return NULL;
+ }
+
+ if(p_QmFqrParams->congestionAvoidanceEnable &&
+ (p_QmFqrParams->congestionAvoidanceParams.h_QmCg == NULL) &&
+ (p_QmFqrParams->congestionAvoidanceParams.fqTailDropThreshold == 0))
+ {
+ REPORT_ERROR(CRITICAL,E_INVALID_STATE,("NULL congestion group handle and no FQ Threshold"));
+ QM_FQR_Free(p_QmFqr);
+ return NULL;
+ }
+ if(p_QmFqrParams->congestionAvoidanceEnable)
+ {
+ if(p_QmFqrParams->congestionAvoidanceParams.h_QmCg)
+ flags |= QM_FQCTRL_CGE;
+ if(p_QmFqrParams->congestionAvoidanceParams.fqTailDropThreshold)
+ flags |= QM_FQCTRL_TDE;
+ }
+
+ /*
+ flags |= (p_QmFqrParams->holdActive) ? QM_FQCTRL_ORP : 0;
+ flags |= (p_QmFqrParams->holdActive) ? QM_FQCTRL_CPCSTASH : 0;
+ flags |= (p_QmFqrParams->holdActive) ? QM_FQCTRL_FORCESFDR : 0;
+ flags |= (p_QmFqrParams->holdActive) ? QM_FQCTRL_AVOIDBLOCK : 0;
+ */
+ flags |= (p_QmFqrParams->holdActive) ? QM_FQCTRL_HOLDACTIVE : 0;
+ flags |= (p_QmFqrParams->preferInCache) ? QM_FQCTRL_LOCKINCACHE : 0;
+
+ if (p_QmFqrParams->useContextAForStash)
+ {
+ if (CheckStashParams(p_QmFqrParams) != E_OK)
+ {
+ REPORT_ERROR(CRITICAL,E_INVALID_STATE,NO_MSG);
+ QM_FQR_Free(p_QmFqr);
+ return NULL;
+ }
+
+ memset(&cnxtA, 0, sizeof(cnxtA));
+ cnxtA.stashing.annotation_cl = DIV_CEIL(p_QmFqrParams->stashingParams.frameAnnotationSize, CACHELINE_SIZE);
+ cnxtA.stashing.data_cl = DIV_CEIL(p_QmFqrParams->stashingParams.frameDataSize, CACHELINE_SIZE);
+ cnxtA.stashing.context_cl = DIV_CEIL(p_QmFqrParams->stashingParams.fqContextSize, CACHELINE_SIZE);
+ cnxtA.context_hi = (uint8_t)((p_QmFqrParams->stashingParams.fqContextAddr >> 32) & 0xff);
+ cnxtA.context_lo = (uint32_t)(p_QmFqrParams->stashingParams.fqContextAddr);
+ flags |= QM_FQCTRL_CTXASTASHING;
+ }
+
+ for(i=0;i<p_QmFqr->numOfFqids;i++)
+ if (qm_new_fq(p_QmFqr->h_QmPortal,
+ p_QmFqr->fqidBase+i,
+ i,
+ p_QmFqr->channel,
+ p_QmFqr->workQueue,
+ 1/*p_QmFqr->numOfFqids*/,
+ flags,
+ (p_QmFqrParams->congestionAvoidanceEnable ?
+ &p_QmFqrParams->congestionAvoidanceParams : NULL),
+ p_QmFqrParams->useContextAForStash ?
+ (t_QmContextA *)&cnxtA : p_QmFqrParams->p_ContextA,
+ p_QmFqrParams->p_ContextB,
+ p_QmFqrParams->initParked,
+ p_QmFqr,
+ &p_QmFqr->p_Fqs[i]) != E_OK)
+ {
+ QM_FQR_Free(p_QmFqr);
+ return NULL;
+ }
+ }
+ return p_QmFqr;
+}
+
+t_Error QM_FQR_Free(t_Handle h_QmFqr)
+{
+ t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
+ uint32_t i;
+
+ if (!p_QmFqr)
+ return ERROR_CODE(E_INVALID_HANDLE);
+
+ if (p_QmFqr->p_Fqs)
+ {
+ for (i=0;i<p_QmFqr->numOfFqids;i++)
+ if (p_QmFqr->p_Fqs[i])
+ {
+ if (!p_QmFqr->shadowMode)
+ qm_free_fq(p_QmFqr->h_QmPortal, p_QmFqr->p_Fqs[i]);
+ XX_FreeSmart(p_QmFqr->p_Fqs[i]);
+ }
+ XX_Free(p_QmFqr->p_Fqs);
+ }
+
+ if (!p_QmFqr->shadowMode && p_QmFqr->fqidBase)
+ QmFqidPut(p_QmFqr->h_Qm, p_QmFqr->fqidBase);
+
+ XX_FreeSmart(p_QmFqr);
+
+ return E_OK;
+}
+
+t_Error QM_FQR_FreeWDrain(t_Handle h_QmFqr,
+ t_QmFqrDrainedCompletionCB *f_CompletionCB,
+ bool deliverFrame,
+ t_QmReceivedFrameCallback *f_CallBack,
+ t_Handle h_App)
+{
+ t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
+ uint32_t i;
+
+ if (!p_QmFqr)
+ return ERROR_CODE(E_INVALID_HANDLE);
+
+ if (p_QmFqr->shadowMode)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("QM_FQR_FreeWDrain can't be called to shadow FQR!!!. call QM_FQR_Free"));
+
+ p_QmFqr->p_DrainedFqs = (bool *)XX_Malloc(sizeof(bool) * p_QmFqr->numOfFqids);
+ if (!p_QmFqr->p_DrainedFqs)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("QM Drained-FQs obj!!!. Try to Free without draining"));
+ memset(p_QmFqr->p_DrainedFqs, 0, sizeof(bool) * p_QmFqr->numOfFqids);
+
+ if (f_CompletionCB)
+ {
+ p_QmFqr->f_CompletionCB = f_CompletionCB;
+ p_QmFqr->h_App = h_App;
+ }
+
+ if (deliverFrame)
+ {
+ if (!f_CallBack)
+ {
+ REPORT_ERROR(MAJOR, E_NULL_POINTER, ("f_CallBack must be given."));
+ XX_Free(p_QmFqr->p_DrainedFqs);
+ return ERROR_CODE(E_NULL_POINTER);
+ }
+ QM_FQR_RegisterCB(p_QmFqr, f_CallBack, h_App);
+ }
+ else
+ QM_FQR_RegisterCB(p_QmFqr, drainCB, h_App);
+
+ for (i=0;i<p_QmFqr->numOfFqids;i++)
+ {
+ if (qman_retire_fq(p_QmFqr->h_QmPortal, p_QmFqr->p_Fqs[i], 0, TRUE) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_retire_fq() failed!"));
+
+ if (p_QmFqr->p_Fqs[i]->flags & QMAN_FQ_STATE_CHANGING)
+ DBG(INFO, ("fq %d currently in use, will be retired", p_QmFqr->p_Fqs[i]->fqid));
+ else
+ drainRetiredFq(p_QmFqr->p_Fqs[i]);
+ }
+
+ if (!p_QmFqr->f_CompletionCB)
+ {
+ while(p_QmFqr->p_DrainedFqs) ;
+ DBG(TRACE, ("QM-FQR with base %d completed", p_QmFqr->fqidBase));
+ XX_FreeSmart(p_QmFqr->p_Fqs);
+ if (p_QmFqr->fqidBase)
+ QmFqidPut(p_QmFqr->h_Qm, p_QmFqr->fqidBase);
+ XX_FreeSmart(p_QmFqr);
+ }
+
+ return E_OK;
+}
+
+t_Error QM_FQR_RegisterCB(t_Handle h_QmFqr, t_QmReceivedFrameCallback *f_CallBack, t_Handle h_App)
+{
+ t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
+ int i;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
+
+ for (i=0;i<p_QmFqr->numOfFqids;i++)
+ {
+ p_QmFqr->p_Fqs[i]->cb.dqrr = f_CallBack;
+ p_QmFqr->p_Fqs[i]->h_App = h_App;
+ }
+
+ return E_OK;
+}
+
+t_Error QM_FQR_Enqueue(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset, t_DpaaFD *p_Frame)
+{
+ t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
+ t_QmPortal *p_QmPortal;
+ struct qm_eqcr_entry *p_Eq;
+ uint32_t *p_Dst, *p_Src;
+ const struct qman_fq *p_Fq;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE);
+
+ if (!h_QmPortal)
+ {
+ SANITY_CHECK_RETURN_ERROR(p_QmFqr->h_Qm, E_INVALID_HANDLE);
+ h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
+ SANITY_CHECK_RETURN_ERROR(h_QmPortal, E_INVALID_HANDLE);
+ }
+ p_QmPortal = (t_QmPortal *)h_QmPortal;
+
+ p_Fq = p_QmFqr->p_Fqs[fqidOffset];
+
+#ifdef QM_CHECKING
+ if (p_Fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+ if ((!(p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)) &&
+ ((p_Fq->state == qman_fq_state_retired) ||
+ (p_Fq->state == qman_fq_state_oos)))
+ return ERROR_CODE(E_BUSY);
+#endif /* QM_CHECKING */
+
+ NCSW_PLOCK(p_QmPortal);
+ p_Eq = try_eq_start(p_QmPortal);
+ if (!p_Eq)
+ {
+ PUNLOCK(p_QmPortal);
+ return ERROR_CODE(E_BUSY);
+ }
+
+ p_Eq->fqid = p_Fq->fqid;
+ p_Eq->tag = (uint32_t)p_Fq;
+ /* gcc does a dreadful job of the following;
+ * eq->fd = *fd;
+ * It causes the entire function to save/restore a wider range of
+ * registers, and comes up with instruction-waste galore. This will do
+ * until we can rework the function for better code-generation. */
+ p_Dst = (uint32_t *)&p_Eq->fd;
+ p_Src = (uint32_t *)p_Frame;
+ p_Dst[0] = p_Src[0];
+ p_Dst[1] = p_Src[1];
+ p_Dst[2] = p_Src[2];
+ p_Dst[3] = p_Src[3];
+
+ qmPortalEqcrPvbCommit(p_QmPortal->p_LowQmPortal,
+ (uint8_t)(QM_EQCR_VERB_CMD_ENQUEUE/* |
+ (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))*/));
+ PUNLOCK(p_QmPortal);
+
+ return E_OK;
+}
+
+
+t_Error QM_FQR_PullFrame(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset, t_DpaaFD *p_Frame)
+{
+ t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
+ uint32_t pdqcr = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(p_Frame, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR((p_QmFqr->p_Fqs[fqidOffset]->state == qman_fq_state_oos) ||
+ (p_QmFqr->p_Fqs[fqidOffset]->state == qman_fq_state_parked),
+ E_INVALID_STATE);
+ if (!h_QmPortal)
+ {
+ SANITY_CHECK_RETURN_ERROR(p_QmFqr->h_Qm, E_INVALID_HANDLE);
+ h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
+ SANITY_CHECK_RETURN_ERROR(h_QmPortal, E_INVALID_HANDLE);
+ }
+
+ pdqcr |= QM_PDQCR_MODE_UNSCHEDULED;
+ pdqcr |= QM_PDQCR_FQID(p_QmFqr->p_Fqs[fqidOffset]->fqid);
+ return QmPortalPullFrame(h_QmPortal, pdqcr, p_Frame);
+}
+
+t_Error QM_FQR_Resume(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset)
+{
+ t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE);
+
+ if (!h_QmPortal)
+ {
+ SANITY_CHECK_RETURN_ERROR(p_QmFqr->h_Qm, E_INVALID_HANDLE);
+ h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
+ SANITY_CHECK_RETURN_ERROR(h_QmPortal, E_INVALID_HANDLE);
+ }
+ return qman_schedule_fq(h_QmPortal, p_QmFqr->p_Fqs[fqidOffset]);
+}
+
+t_Error QM_FQR_Suspend(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset)
+{
+ t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR((p_QmFqr->p_Fqs[fqidOffset]->flags & QM_FQCTRL_HOLDACTIVE), E_INVALID_STATE);
+
+ UNUSED(h_QmPortal);
+ p_QmFqr->p_Fqs[fqidOffset]->state = qman_fq_state_waiting_parked;
+
+ return E_OK;
+}
+
+uint32_t QM_FQR_GetFqid(t_Handle h_QmFqr)
+{
+ t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
+
+ SANITY_CHECK_RETURN_VALUE(p_QmFqr, E_INVALID_HANDLE, 0);
+
+ return p_QmFqr->fqidBase;
+}
+
+uint32_t QM_FQR_GetCounter(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset, e_QmFqrCounters counter)
+{
+ t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
+ struct qm_mcr_queryfq_np queryfq_np;
+
+ SANITY_CHECK_RETURN_VALUE(p_QmFqr, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE, 0);
+
+ if (!h_QmPortal)
+ {
+ SANITY_CHECK_RETURN_VALUE(p_QmFqr->h_Qm, E_INVALID_HANDLE, 0);
+ h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
+ SANITY_CHECK_RETURN_VALUE(h_QmPortal, E_INVALID_HANDLE, 0);
+ }
+ if (qman_query_fq_np(h_QmPortal, p_QmFqr->p_Fqs[fqidOffset], &queryfq_np) != E_OK)
+ return 0;
+ switch (counter)
+ {
+ case e_QM_FQR_COUNTERS_FRAME :
+ return queryfq_np.frm_cnt;
+ case e_QM_FQR_COUNTERS_BYTE :
+ return queryfq_np.byte_cnt;
+ default :
+ break;
+ }
+ /* should never get here */
+ ASSERT_COND(FALSE);
+
+ return 0;
+}
+
+
+t_Handle QM_CG_Create(t_QmCgParams *p_CgParams)
+{
+ t_QmCg *p_QmCg;
+ t_QmPortal *p_QmPortal;
+ t_Error err;
+ uint32_t wredParams;
+ uint32_t tmpA, tmpN, ta=0, tn=0;
+ int gap, tmp;
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+
+ SANITY_CHECK_RETURN_VALUE(p_CgParams, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_CgParams->h_Qm, E_INVALID_HANDLE, NULL);
+
+ if(p_CgParams->notifyDcPortal &&
+ ((p_CgParams->dcPortalId == e_DPAA_DCPORTAL2) || (p_CgParams->dcPortalId == e_DPAA_DCPORTAL3)))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("notifyDcPortal is invalid for this DC Portal"));
+ return NULL;
+ }
+
+ if (!p_CgParams->h_QmPortal)
+ {
+ p_QmPortal = QmGetPortalHandle(p_CgParams->h_Qm);
+ SANITY_CHECK_RETURN_VALUE(p_QmPortal, E_INVALID_STATE, NULL);
+ }
+ else
+ p_QmPortal = p_CgParams->h_QmPortal;
+
+ p_QmCg = (t_QmCg *)XX_Malloc(sizeof(t_QmCg));
+ if (!p_QmCg)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("QM CG obj!!!"));
+ return NULL;
+ }
+ memset(p_QmCg, 0, sizeof(t_QmCg));
+
+ /* build CG struct */
+ p_QmCg->h_Qm = p_CgParams->h_Qm;
+ p_QmCg->h_QmPortal = p_QmPortal;
+ p_QmCg->h_App = p_CgParams->h_App;
+ err = QmGetCgId(p_CgParams->h_Qm, &p_QmCg->id);
+ if (err)
+ {
+ XX_Free(p_QmCg);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("QmGetCgId failed"));
+ return NULL;
+ }
+
+ NCSW_PLOCK(p_QmPortal);
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->initcgr.cgid = p_QmCg->id;
+
+ err = QmPortalRegisterCg(p_QmPortal, p_QmCg, p_QmCg->id);
+ if (err)
+ {
+ XX_Free(p_QmCg);
+ PUNLOCK(p_QmPortal);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("QmPortalRegisterCg failed"));
+ return NULL;
+ }
+
+ /* Build CGR command */
+ {
+#ifdef QM_CGS_NO_FRAME_MODE
+ t_QmRevisionInfo revInfo;
+
+ QmGetRevision(p_QmCg->h_Qm, &revInfo);
+
+ if (!((revInfo.majorRev == 1) && (revInfo.minorRev == 0)))
+#endif /* QM_CGS_NO_FRAME_MODE */
+ if (p_CgParams->frameCount)
+ {
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_MODE;
+ p_Mcc->initcgr.cgr.frame_mode = QM_CGR_EN;
+ }
+ }
+
+ if (p_CgParams->wredEnable)
+ {
+ if (p_CgParams->wredParams.enableGreen)
+ {
+ err = CalcWredCurve(&p_CgParams->wredParams.greenCurve, &wredParams);
+ if(err)
+ {
+ XX_Free(p_QmCg);
+ PUNLOCK(p_QmPortal);
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return NULL;
+ }
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_G | QM_CGR_WE_WR_PARM_G;
+ p_Mcc->initcgr.cgr.wr_en_g = QM_CGR_EN;
+ p_Mcc->initcgr.cgr.wr_parm_g.word = wredParams;
+ }
+ if (p_CgParams->wredParams.enableYellow)
+ {
+ err = CalcWredCurve(&p_CgParams->wredParams.yellowCurve, &wredParams);
+ if(err)
+ {
+ XX_Free(p_QmCg);
+ PUNLOCK(p_QmPortal);
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return NULL;
+ }
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_Y | QM_CGR_WE_WR_PARM_Y;
+ p_Mcc->initcgr.cgr.wr_en_y = QM_CGR_EN;
+ p_Mcc->initcgr.cgr.wr_parm_y.word = wredParams;
+ }
+ if (p_CgParams->wredParams.enableRed)
+ {
+ err = CalcWredCurve(&p_CgParams->wredParams.redCurve, &wredParams);
+ if(err)
+ {
+ XX_Free(p_QmCg);
+ PUNLOCK(p_QmPortal);
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return NULL;
+ }
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_R | QM_CGR_WE_WR_PARM_R;
+ p_Mcc->initcgr.cgr.wr_en_r = QM_CGR_EN;
+ p_Mcc->initcgr.cgr.wr_parm_r.word = wredParams;
+ }
+ }
+
+ if (p_CgParams->tailDropEnable)
+ {
+ if (!p_CgParams->threshold)
+ {
+ XX_Free(p_QmCg);
+ PUNLOCK(p_QmPortal);
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("tailDropThreshold must be configured if tailDropEnable "));
+ return NULL;
+ }
+ p_Mcc->initcgr.cgr.cstd_en = QM_CGR_EN;
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
+ }
+
+ if (p_CgParams->threshold)
+ {
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_CS_THRES;
+ p_QmCg->f_Exception = p_CgParams->f_Exception;
+ if (p_QmCg->f_Exception || p_CgParams->notifyDcPortal)
+ {
+ p_Mcc->initcgr.cgr.cscn_en = QM_CGR_EN;
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_CSCN_EN | QM_CGR_WE_CSCN_TARG;
+ /* if SW - set target, if HW - if FM, set HW target, otherwize, set SW target */
+ p_Mcc->initcgr.cgr.cscn_targ = 0;
+ if (p_QmCg->f_Exception)
+ p_Mcc->initcgr.cgr.cscn_targ = (uint32_t)QM_CGR_TARGET_SWP(QmPortalGetSwPortalId(p_QmCg->h_QmPortal));
+ if (p_CgParams->notifyDcPortal)
+ p_Mcc->initcgr.cgr.cscn_targ |= (uint32_t)QM_CGR_TARGET_DCP(p_CgParams->dcPortalId);
+ }
+
+ /* express thresh as ta*2^tn */
+ gap = (int)p_CgParams->threshold;
+ for (tmpA=0 ; tmpA<256; tmpA++ )
+ for (tmpN=0 ; tmpN<32; tmpN++ )
+ {
+ tmp = ABS((int)(p_CgParams->threshold - tmpA*(1<<tmpN)));
+ if (tmp < gap)
+ {
+ ta = tmpA;
+ tn = tmpN;
+ gap = tmp;
+ }
+ }
+ p_Mcc->initcgr.cgr.cs_thres.TA = ta;
+ p_Mcc->initcgr.cgr.cs_thres.Tn = tn;
+ }
+ else if(p_CgParams->f_Exception)
+ {
+ XX_Free(p_QmCg);
+ PUNLOCK(p_QmPortal);
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("No threshold configured, but f_Exception defined"));
+ return NULL;
+ }
+
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_INITCGR);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_INITCGR);
+ if (p_Mcr->result != QM_MCR_RESULT_OK)
+ {
+ XX_Free(p_QmCg);
+ PUNLOCK(p_QmPortal);
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
+ return NULL;
+ }
+ PUNLOCK(p_QmPortal);
+
+ return p_QmCg;
+}
+
+t_Error QM_CG_Free(t_Handle h_QmCg)
+{
+
+ t_QmCg *p_QmCg = (t_QmCg *)h_QmCg;
+ t_Error err;
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+ t_QmPortal *p_QmPortal;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmCg, E_INVALID_HANDLE);
+
+ p_QmPortal = (t_QmPortal *)p_QmCg->h_QmPortal;
+
+ NCSW_PLOCK(p_QmPortal);
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->initcgr.cgid = p_QmCg->id;
+ p_Mcc->initcgr.we_mask = QM_CGR_WE_MASK;
+
+ err = QmFreeCgId(p_QmCg->h_Qm, p_QmCg->id);
+ if(err)
+ {
+ XX_Free(p_QmCg);
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("QmFreeCgId failed"));
+ }
+
+ err = QmPortalUnregisterCg(p_QmCg->h_QmPortal, p_QmCg->id);
+ if(err)
+ {
+ XX_Free(p_QmCg);
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("QmPortalUnregisterCg failed"));
+ }
+
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_MODIFYCGR);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_MODIFYCGR);
+ if (p_Mcr->result != QM_MCR_RESULT_OK)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
+ }
+ PUNLOCK(p_QmPortal);
+
+ XX_Free(p_QmCg);
+
+ return E_OK;
+}
+
+t_Error QM_CG_SetException(t_Handle h_QmCg, e_QmExceptions exception, bool enable)
+{
+ t_QmCg *p_QmCg = (t_QmCg *)h_QmCg;
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+ t_QmPortal *p_QmPortal;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmCg, E_INVALID_HANDLE);
+
+ p_QmPortal = (t_QmPortal *)p_QmCg->h_QmPortal;
+ if (!p_QmCg->f_Exception)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Either threshold or exception callback was not configured."));
+
+ NCSW_PLOCK(p_QmPortal);
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->initcgr.cgid = p_QmCg->id;
+ p_Mcc->initcgr.we_mask = QM_CGR_WE_CSCN_EN;
+
+ if(exception == e_QM_EX_CG_STATE_CHANGE)
+ {
+ if(enable)
+ p_Mcc->initcgr.cgr.cscn_en = QM_CGR_EN;
+ }
+ else
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal exception"));
+ }
+
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_MODIFYCGR);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_MODIFYCGR);
+ if (p_Mcr->result != QM_MCR_RESULT_OK)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
+ }
+ PUNLOCK(p_QmPortal);
+
+ return E_OK;
+}
+
+t_Error QM_CG_ModifyWredCurve(t_Handle h_QmCg, t_QmCgModifyWredParams *p_QmCgModifyParams)
+{
+ t_QmCg *p_QmCg = (t_QmCg *)h_QmCg;
+ uint32_t wredParams;
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+ t_QmPortal *p_QmPortal;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmCg, E_INVALID_HANDLE);
+
+ p_QmPortal = (t_QmPortal *)p_QmCg->h_QmPortal;
+
+ NCSW_PLOCK(p_QmPortal);
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->initcgr.cgid = p_QmCg->id;
+
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYCGR);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYCGR);
+ if (p_Mcr->result != QM_MCR_RESULT_OK)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("QM_MCC_VERB_QUERYCGR failed: %s", mcr_result_str(p_Mcr->result)));
+ }
+
+ switch(p_QmCgModifyParams->color)
+ {
+ case(e_QM_CG_COLOR_GREEN):
+ if(!p_Mcr->querycgr.cgr.wr_en_g)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("WRED is not enabled for green"));
+ }
+ break;
+ case(e_QM_CG_COLOR_YELLOW):
+ if(!p_Mcr->querycgr.cgr.wr_en_y)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("WRED is not enabled for yellow"));
+ }
+ break;
+ case(e_QM_CG_COLOR_RED):
+ if(!p_Mcr->querycgr.cgr.wr_en_r)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("WRED is not enabled for red"));
+ }
+ break;
+ }
+
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->initcgr.cgid = p_QmCg->id;
+
+ switch(p_QmCgModifyParams->color)
+ {
+ case(e_QM_CG_COLOR_GREEN):
+ err = CalcWredCurve(&p_QmCgModifyParams->wredParams, &wredParams);
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_G | QM_CGR_WE_WR_PARM_G;
+ p_Mcc->initcgr.cgr.wr_en_g = QM_CGR_EN;
+ p_Mcc->initcgr.cgr.wr_parm_g.word = wredParams;
+ break;
+ case(e_QM_CG_COLOR_YELLOW):
+ err = CalcWredCurve(&p_QmCgModifyParams->wredParams, &wredParams);
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_Y | QM_CGR_WE_WR_PARM_Y;
+ p_Mcc->initcgr.cgr.wr_en_y = QM_CGR_EN;
+ p_Mcc->initcgr.cgr.wr_parm_y.word = wredParams;
+ break;
+ case(e_QM_CG_COLOR_RED):
+ err = CalcWredCurve(&p_QmCgModifyParams->wredParams, &wredParams);
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_R | QM_CGR_WE_WR_PARM_R;
+ p_Mcc->initcgr.cgr.wr_en_r = QM_CGR_EN;
+ p_Mcc->initcgr.cgr.wr_parm_r.word = wredParams;
+ break;
+ }
+ if (err)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_MODIFYCGR);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_MODIFYCGR);
+ if (p_Mcr->result != QM_MCR_RESULT_OK)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
+ }
+ PUNLOCK(p_QmPortal);
+
+ return E_OK;
+}
+
+t_Error QM_CG_ModifyTailDropThreshold(t_Handle h_QmCg, uint32_t threshold)
+{
+ t_QmCg *p_QmCg = (t_QmCg *)h_QmCg;
+ struct qm_mc_command *p_Mcc;
+ struct qm_mc_result *p_Mcr;
+ t_QmPortal *p_QmPortal;
+ uint32_t tmpA, tmpN, ta=0, tn=0;
+ int gap, tmp;
+
+ SANITY_CHECK_RETURN_ERROR(p_QmCg, E_INVALID_HANDLE);
+
+ p_QmPortal = (t_QmPortal *)p_QmCg->h_QmPortal;
+
+ NCSW_PLOCK(p_QmPortal);
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->initcgr.cgid = p_QmCg->id;
+
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYCGR);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYCGR);
+ if (p_Mcr->result != QM_MCR_RESULT_OK)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("QM_MCC_VERB_QUERYCGR failed: %s", mcr_result_str(p_Mcr->result)));
+ }
+
+ if(!p_Mcr->querycgr.cgr.cstd_en)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Tail Drop is not enabled!"));
+ }
+
+ p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
+ p_Mcc->initcgr.cgid = p_QmCg->id;
+ p_Mcc->initcgr.we_mask |= QM_CGR_WE_CS_THRES;
+
+ /* express thresh as ta*2^tn */
+ gap = (int)threshold;
+ for (tmpA=0 ; tmpA<256; tmpA++ )
+ for (tmpN=0 ; tmpN<32; tmpN++ )
+ {
+ tmp = ABS((int)(threshold - tmpA*(1<<tmpN)));
+ if (tmp < gap)
+ {
+ ta = tmpA;
+ tn = tmpN;
+ gap = tmp;
+ }
+ }
+ p_Mcc->initcgr.cgr.cs_thres.TA = ta;
+ p_Mcc->initcgr.cgr.cs_thres.Tn = tn;
+
+ qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_MODIFYCGR);
+ while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
+ ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_MODIFYCGR);
+ if (p_Mcr->result != QM_MCR_RESULT_OK)
+ {
+ PUNLOCK(p_QmPortal);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
+ }
+ PUNLOCK(p_QmPortal);
+
+ return E_OK;
+}
+
OpenPOWER on IntegriCloud