mirror of https://github.com/F-Stack/f-stack.git
2702 lines
98 KiB
C
2702 lines
98 KiB
C
/******************************************************************************
|
|
|
|
© 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;
|
|
}
|
|
|