diff --git a/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c b/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c index bdb7d5175530..31313d37f97c 100644 --- a/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c +++ b/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c @@ -1,2734 +1,2732 @@ /****************************************************************************** © 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 #include #include #include "error_ext.h" #include "std_ext.h" #include "string_ext.h" #include "mm_ext.h" #include "qm.h" #include "qman_low.h" #include /****************************************/ /* static functions */ /****************************************/ #define SLOW_POLL_IDLE 1000 #define SLOW_POLL_BUSY 10 /* * Context entries are 32-bit. The qman driver uses the pointer to the queue as * its context, and the pointer is 64-byte aligned, per the XX_MallocSmart() * call. Take advantage of this fact to shove a 64-bit kernel pointer into a * 32-bit context integer, and back. * * XXX: This depends on the fact that VM_MAX_KERNEL_ADDRESS is less than 38-bit * count from VM_MIN_KERNEL_ADDRESS. If this ever changes, this needs to be * updated. */ CTASSERT((VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) < (1ULL << 35)); static inline uint32_t aligned_int_from_ptr(const void *p) { uintptr_t ctx; ctx = (uintptr_t)p; KASSERT(ctx >= VM_MIN_KERNEL_ADDRESS, ("%p is too low!\n", p)); ctx -= VM_MIN_KERNEL_ADDRESS; KASSERT((ctx & 0x07) == 0, ("Pointer %p is not 8-byte aligned!\n", p)); return (ctx >> 3); } static inline void * ptr_from_aligned_int(uint32_t ctx) { uintptr_t p; p = ctx; p = VM_MIN_KERNEL_ADDRESS + (p << 3); return ((void *)p); } 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 ""; } 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 = aligned_int_from_ptr(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;inumOfFqids;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 = ptr_from_aligned_int(p_Msg->fq.contextB); struct qman_fq *p_FqErn = ptr_from_aligned_int(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 = ptr_from_aligned_int(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 = ptr_from_aligned_int(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 = ptr_from_aligned_int(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;icb.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;ih_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<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;ioverheadAccountingLength)) { 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<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<maxTh = ma*(1<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/(1UL<<(tmpN%32)))); if (tmp < gap) { sa = tmpA; sn = tmpN; gap = tmp; } } sa = sa/pres; ASSERT_COND(sa<128 && sa>=64); 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); mb(); 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 = ptr_from_aligned_int(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;ip_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;ip_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 = ptr_from_aligned_int(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;inumOfFqids;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;inumOfFqids;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;inumOfFqids;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;inumOfFqids;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 = aligned_int_from_ptr(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<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<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; } diff --git a/sys/dev/dpaa/fman.c b/sys/dev/dpaa/fman.c index d3327399fb88..64709b07fc42 100644 --- a/sys/dev/dpaa/fman.c +++ b/sys/dev/dpaa/fman.c @@ -1,559 +1,557 @@ /*- * Copyright (c) 2011-2012 Semihalf. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "opt_platform.h" #include #include #include #include #include "fman.h" static MALLOC_DEFINE(M_FMAN, "fman", "fman devices information"); /** * @group FMan private defines. * @{ */ enum fman_irq_enum { FMAN_IRQ_NUM = 0, FMAN_ERR_IRQ_NUM = 1 }; enum fman_mu_ram_map { FMAN_MURAM_OFF = 0x0, FMAN_MURAM_SIZE = 0x28000 }; struct fman_config { device_t fman_device; uintptr_t mem_base_addr; uintptr_t irq_num; uintptr_t err_irq_num; uint8_t fm_id; t_FmExceptionsCallback *exception_callback; t_FmBusErrorCallback *bus_error_callback; }; /** * @group FMan private methods/members. * @{ */ /** * Frame Manager firmware. * We use the same firmware for both P3041 and P2041 devices. */ const uint32_t fman_firmware[] = FMAN_UC_IMG; const uint32_t fman_firmware_size = sizeof(fman_firmware); int fman_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { struct fman_softc *sc; bus_space_tag_t bt; bus_space_handle_t bh; int i, rv; sc = device_get_softc(bus); if (type != SYS_RES_IRQ) { for (i = 0; i < sc->sc_base.nranges; i++) { if (rman_is_region_manager(res, &sc->rman) != 0) { bt = rman_get_bustag(sc->mem_res); rv = bus_space_subregion(bt, rman_get_bushandle(sc->mem_res), rman_get_start(res) - rman_get_start(sc->mem_res), rman_get_size(res), &bh); if (rv != 0) return (rv); rman_set_bustag(res, bt); rman_set_bushandle(res, bh); return (rman_activate_resource(res)); } } return (EINVAL); } return (bus_generic_activate_resource(bus, child, type, rid, res)); } int fman_release_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { - struct fman_softc *sc; struct resource_list *rl; struct resource_list_entry *rle; int passthrough, rv; passthrough = (device_get_parent(child) != bus); rl = BUS_GET_RESOURCE_LIST(bus, child); - sc = device_get_softc(bus); if (type != SYS_RES_IRQ) { if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){ rv = bus_deactivate_resource(child, type, rid, res); if (rv != 0) return (rv); } rv = rman_release_resource(res); if (rv != 0) return (rv); if (!passthrough) { rle = resource_list_find(rl, type, rid); KASSERT(rle != NULL, ("%s: resource entry not found!", __func__)); KASSERT(rle->res != NULL, ("%s: resource entry is not busy", __func__)); rle->res = NULL; } return (0); } return (resource_list_release(rl, bus, child, type, rid, res)); } struct resource * fman_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct fman_softc *sc; struct resource_list *rl; struct resource_list_entry *rle = NULL; struct resource *res; int i, isdefault, passthrough; isdefault = RMAN_IS_DEFAULT_RANGE(start, end); passthrough = (device_get_parent(child) != bus); sc = device_get_softc(bus); rl = BUS_GET_RESOURCE_LIST(bus, child); switch (type) { case SYS_RES_MEMORY: KASSERT(!(isdefault && passthrough), ("%s: passthrough of default allocation", __func__)); if (!passthrough) { rle = resource_list_find(rl, type, *rid); if (rle == NULL) return (NULL); KASSERT(rle->res == NULL, ("%s: resource entry is busy", __func__)); if (isdefault) { start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } } res = NULL; /* Map fman ranges to nexus ranges. */ for (i = 0; i < sc->sc_base.nranges; i++) { if (start >= sc->sc_base.ranges[i].bus && end < sc->sc_base.ranges[i].bus + sc->sc_base.ranges[i].size) { start += rman_get_start(sc->mem_res); end += rman_get_start(sc->mem_res); res = rman_reserve_resource(&sc->rman, start, end, count, flags & ~RF_ACTIVE, child); if (res == NULL) return (NULL); rman_set_rid(res, *rid); if ((flags & RF_ACTIVE) != 0 && bus_activate_resource( child, type, *rid, res) != 0) { rman_release_resource(res); return (NULL); } break; } } if (!passthrough) rle->res = res; return (res); case SYS_RES_IRQ: return (resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags)); } return (NULL); } static int fman_fill_ranges(phandle_t node, struct simplebus_softc *sc) { int host_address_cells; cell_t *base_ranges; ssize_t nbase_ranges; int err; int i, j, k; err = OF_searchencprop(OF_parent(node), "#address-cells", &host_address_cells, sizeof(host_address_cells)); if (err <= 0) return (-1); nbase_ranges = OF_getproplen(node, "ranges"); if (nbase_ranges < 0) return (-1); sc->nranges = nbase_ranges / sizeof(cell_t) / (sc->acells + host_address_cells + sc->scells); if (sc->nranges == 0) return (0); sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), M_DEVBUF, M_WAITOK); base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); OF_getencprop(node, "ranges", base_ranges, nbase_ranges); for (i = 0, j = 0; i < sc->nranges; i++) { sc->ranges[i].bus = 0; for (k = 0; k < sc->acells; k++) { sc->ranges[i].bus <<= 32; sc->ranges[i].bus |= base_ranges[j++]; } sc->ranges[i].host = 0; for (k = 0; k < host_address_cells; k++) { sc->ranges[i].host <<= 32; sc->ranges[i].host |= base_ranges[j++]; } sc->ranges[i].size = 0; for (k = 0; k < sc->scells; k++) { sc->ranges[i].size <<= 32; sc->ranges[i].size |= base_ranges[j++]; } } free(base_ranges, M_DEVBUF); return (sc->nranges); } static t_Handle fman_init(struct fman_softc *sc, struct fman_config *cfg) { phandle_t node; t_FmParams fm_params; t_Handle muram_handle, fm_handle; t_Error error; t_FmRevisionInfo revision_info; uint16_t clock; uint32_t tmp, mod; /* MURAM configuration */ muram_handle = FM_MURAM_ConfigAndInit(cfg->mem_base_addr + FMAN_MURAM_OFF, FMAN_MURAM_SIZE); if (muram_handle == NULL) { device_printf(cfg->fman_device, "couldn't init FM MURAM module" "\n"); return (NULL); } sc->muram_handle = muram_handle; /* Fill in FM configuration */ fm_params.fmId = cfg->fm_id; /* XXX we support only one partition thus each fman has master id */ fm_params.guestId = NCSW_MASTER_ID; fm_params.baseAddr = cfg->mem_base_addr; fm_params.h_FmMuram = muram_handle; /* Get FMan clock in Hz */ if ((tmp = fman_get_clock(sc)) == 0) return (NULL); /* Convert FMan clock to MHz */ clock = (uint16_t)(tmp / 1000000); mod = tmp % 1000000; if (mod >= 500000) ++clock; fm_params.fmClkFreq = clock; fm_params.f_Exception = cfg->exception_callback; fm_params.f_BusError = cfg->bus_error_callback; fm_params.h_App = cfg->fman_device; fm_params.irq = cfg->irq_num; fm_params.errIrq = cfg->err_irq_num; fm_params.firmware.size = fman_firmware_size; fm_params.firmware.p_Code = (uint32_t*)fman_firmware; fm_handle = FM_Config(&fm_params); if (fm_handle == NULL) { device_printf(cfg->fman_device, "couldn't configure FM " "module\n"); goto err; } FM_ConfigResetOnInit(fm_handle, TRUE); error = FM_Init(fm_handle); if (error != E_OK) { device_printf(cfg->fman_device, "couldn't init FM module\n"); goto err2; } error = FM_GetRevision(fm_handle, &revision_info); if (error != E_OK) { device_printf(cfg->fman_device, "couldn't get FM revision\n"); goto err2; } device_printf(cfg->fman_device, "Hardware version: %d.%d.\n", revision_info.majorRev, revision_info.minorRev); /* Initialize the simplebus part of things */ simplebus_init(sc->sc_base.dev, 0); node = ofw_bus_get_node(sc->sc_base.dev); fman_fill_ranges(node, &sc->sc_base); sc->rman.rm_type = RMAN_ARRAY; sc->rman.rm_descr = "FMan range"; rman_init_from_resource(&sc->rman, sc->mem_res); for (node = OF_child(node); node > 0; node = OF_peer(node)) { simplebus_add_device(sc->sc_base.dev, node, 0, NULL, -1, NULL); } return (fm_handle); err2: FM_Free(fm_handle); err: FM_MURAM_Free(muram_handle); return (NULL); } static void fman_exception_callback(t_Handle app_handle, e_FmExceptions exception) { struct fman_softc *sc; sc = app_handle; device_printf(sc->sc_base.dev, "FMan exception occurred.\n"); } static void fman_error_callback(t_Handle app_handle, e_FmPortType port_type, uint8_t port_id, uint64_t addr, uint8_t tnum, uint16_t liodn) { struct fman_softc *sc; sc = app_handle; device_printf(sc->sc_base.dev, "FMan error occurred.\n"); } /** @} */ /** * @group FMan driver interface. * @{ */ int fman_get_handle(device_t dev, t_Handle *fmh) { struct fman_softc *sc = device_get_softc(dev); *fmh = sc->fm_handle; return (0); } int fman_get_muram_handle(device_t dev, t_Handle *muramh) { struct fman_softc *sc = device_get_softc(dev); *muramh = sc->muram_handle; return (0); } int fman_get_bushandle(device_t dev, vm_offset_t *fm_base) { struct fman_softc *sc = device_get_softc(dev); *fm_base = rman_get_bushandle(sc->mem_res); return (0); } int fman_attach(device_t dev) { struct fman_softc *sc; struct fman_config cfg; pcell_t qchan_range[2]; phandle_t node; sc = device_get_softc(dev); sc->sc_base.dev = dev; /* Check if MallocSmart allocator is ready */ if (XX_MallocSmartInit() != E_OK) { device_printf(dev, "could not initialize smart allocator.\n"); return (ENXIO); } node = ofw_bus_get_node(dev); if (OF_getencprop(node, "fsl,qman-channel-range", qchan_range, sizeof(qchan_range)) <= 0) { device_printf(dev, "Missing QMan channel range property!\n"); return (ENXIO); } sc->qman_chan_base = qchan_range[0]; sc->qman_chan_count = qchan_range[1]; sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE | RF_SHAREABLE); if (!sc->mem_res) { device_printf(dev, "could not allocate memory.\n"); return (ENXIO); } sc->irq_rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE); if (!sc->irq_res) { device_printf(dev, "could not allocate interrupt.\n"); goto err; } sc->err_irq_rid = 1; sc->err_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->err_irq_rid, RF_ACTIVE | RF_SHAREABLE); if (!sc->err_irq_res) { device_printf(dev, "could not allocate error interrupt.\n"); goto err; } /* Set FMan configuration */ cfg.fman_device = dev; cfg.fm_id = device_get_unit(dev); cfg.mem_base_addr = rman_get_bushandle(sc->mem_res); cfg.irq_num = (uintptr_t)sc->irq_res; cfg.err_irq_num = (uintptr_t)sc->err_irq_res; cfg.exception_callback = fman_exception_callback; cfg.bus_error_callback = fman_error_callback; sc->fm_handle = fman_init(sc, &cfg); if (sc->fm_handle == NULL) { device_printf(dev, "could not be configured\n"); return (ENXIO); } return (bus_generic_attach(dev)); err: fman_detach(dev); return (ENXIO); } int fman_detach(device_t dev) { struct fman_softc *sc; sc = device_get_softc(dev); if (sc->muram_handle) { FM_MURAM_Free(sc->muram_handle); } if (sc->fm_handle) { FM_Free(sc->fm_handle); } if (sc->mem_res) { bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); } if (sc->irq_res) { bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); } if (sc->irq_res) { bus_release_resource(dev, SYS_RES_IRQ, sc->err_irq_rid, sc->err_irq_res); } return (0); } int fman_suspend(device_t dev) { return (0); } int fman_resume_dev(device_t dev) { return (0); } int fman_shutdown(device_t dev) { return (0); } int fman_qman_channel_id(device_t dev, int port) { struct fman_softc *sc; int qman_port_id[] = {0x31, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; int i; sc = device_get_softc(dev); for (i = 0; i < sc->qman_chan_count; i++) { if (qman_port_id[i] == port) return (sc->qman_chan_base + i); } return (0); } /** @} */ diff --git a/sys/dev/dpaa/qman.c b/sys/dev/dpaa/qman.c index a090d49adea1..92ea38a16534 100644 --- a/sys/dev/dpaa/qman.c +++ b/sys/dev/dpaa/qman.c @@ -1,555 +1,553 @@ /*- * Copyright (c) 2011-2012 Semihalf. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "qman.h" #include "portals.h" extern struct dpaa_portals_softc *qp_sc; static struct qman_softc *qman_sc; extern t_Handle qman_portal_setup(struct qman_softc *qsc); static void qman_exception(t_Handle app, e_QmExceptions exception) { struct qman_softc *sc; const char *message; sc = app; switch (exception) { case e_QM_EX_CORENET_INITIATOR_DATA: message = "Initiator Data Error"; break; case e_QM_EX_CORENET_TARGET_DATA: message = "CoreNet Target Data Error"; break; case e_QM_EX_CORENET_INVALID_TARGET_TRANSACTION: message = "Invalid Target Transaction"; break; case e_QM_EX_PFDR_THRESHOLD: message = "PFDR Low Watermark Interrupt"; break; case e_QM_EX_PFDR_ENQUEUE_BLOCKED: message = "PFDR Enqueues Blocked Interrupt"; break; case e_QM_EX_SINGLE_ECC: message = "Single Bit ECC Error Interrupt"; break; case e_QM_EX_MULTI_ECC: message = "Multi Bit ECC Error Interrupt"; break; case e_QM_EX_INVALID_COMMAND: message = "Invalid Command Verb Interrupt"; break; case e_QM_EX_DEQUEUE_DCP: message = "Invalid Dequeue Direct Connect Portal Interrupt"; break; case e_QM_EX_DEQUEUE_FQ: message = "Invalid Dequeue FQ Interrupt"; break; case e_QM_EX_DEQUEUE_SOURCE: message = "Invalid Dequeue Source Interrupt"; break; case e_QM_EX_DEQUEUE_QUEUE: message = "Invalid Dequeue Queue Interrupt"; break; case e_QM_EX_ENQUEUE_OVERFLOW: message = "Invalid Enqueue Overflow Interrupt"; break; case e_QM_EX_ENQUEUE_STATE: message = "Invalid Enqueue State Interrupt"; break; case e_QM_EX_ENQUEUE_CHANNEL: message = "Invalid Enqueue Channel Interrupt"; break; case e_QM_EX_ENQUEUE_QUEUE: message = "Invalid Enqueue Queue Interrupt"; break; case e_QM_EX_CG_STATE_CHANGE: message = "CG change state notification"; break; default: message = "Unknown error"; } device_printf(sc->sc_dev, "QMan Exception: %s.\n", message); } /** * General received frame callback. * This is called, when user did not register his own callback for a given * frame queue range (fqr). */ e_RxStoreResponse qman_received_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal, uint32_t fqid_offset, t_DpaaFD *frame) { struct qman_softc *sc; sc = app; device_printf(sc->sc_dev, "dummy callback for received frame.\n"); return (e_RX_STORE_RESPONSE_CONTINUE); } /** * General rejected frame callback. * This is called, when user did not register his own callback for a given * frame queue range (fqr). */ e_RxStoreResponse qman_rejected_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal, uint32_t fqid_offset, t_DpaaFD *frame, t_QmRejectedFrameInfo *qm_rejected_frame_info) { struct qman_softc *sc; sc = app; device_printf(sc->sc_dev, "dummy callback for rejected frame.\n"); return (e_RX_STORE_RESPONSE_CONTINUE); } int qman_attach(device_t dev) { struct qman_softc *sc; t_QmParam qp; t_Error error; t_QmRevisionInfo rev; sc = device_get_softc(dev); sc->sc_dev = dev; qman_sc = sc; if (XX_MallocSmartInit() != E_OK) { device_printf(dev, "could not initialize smart allocator.\n"); return (ENXIO); } sched_pin(); /* Allocate resources */ sc->sc_rrid = 0; sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rrid, 0, ~0, QMAN_CCSR_SIZE, RF_ACTIVE); if (sc->sc_rres == NULL) { device_printf(dev, "could not allocate memory.\n"); goto err; } sc->sc_irid = 0; sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE); if (sc->sc_ires == NULL) { device_printf(dev, "could not allocate error interrupt.\n"); goto err; } if (qp_sc == NULL) goto err; dpaa_portal_map_registers(qp_sc); /* Initialize QMan */ qp.guestId = NCSW_MASTER_ID; qp.baseAddress = rman_get_bushandle(sc->sc_rres); qp.swPortalsBaseAddress = rman_get_bushandle(qp_sc->sc_rres[0]); qp.liodn = 0; qp.totalNumOfFqids = QMAN_MAX_FQIDS; qp.fqdMemPartitionId = NCSW_MASTER_ID; qp.pfdrMemPartitionId = NCSW_MASTER_ID; qp.f_Exception = qman_exception; qp.h_App = sc; qp.errIrq = (uintptr_t)sc->sc_ires; qp.partFqidBase = QMAN_FQID_BASE; qp.partNumOfFqids = QMAN_MAX_FQIDS; qp.partCgsBase = 0; qp.partNumOfCgs = 0; sc->sc_qh = QM_Config(&qp); if (sc->sc_qh == NULL) { device_printf(dev, "could not be configured\n"); goto err; } error = QM_Init(sc->sc_qh); if (error != E_OK) { device_printf(dev, "could not be initialized\n"); goto err; } error = QM_GetRevision(sc->sc_qh, &rev); if (error != E_OK) { device_printf(dev, "could not get QMan revision\n"); goto err; } device_printf(dev, "Hardware version: %d.%d.\n", rev.majorRev, rev.minorRev); sched_unpin(); qman_portal_setup(sc); return (0); err: sched_unpin(); qman_detach(dev); return (ENXIO); } int qman_detach(device_t dev) { struct qman_softc *sc; sc = device_get_softc(dev); if (sc->sc_qh) QM_Free(sc->sc_qh); if (sc->sc_ires != NULL) XX_DeallocIntr((uintptr_t)sc->sc_ires); if (sc->sc_ires != NULL) bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires); if (sc->sc_rres != NULL) bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres); return (0); } int qman_suspend(device_t dev) { return (0); } int qman_resume(device_t dev) { return (0); } int qman_shutdown(device_t dev) { return (0); } /** * @group QMan API functions implementation. * @{ */ t_Handle qman_fqr_create(uint32_t fqids_num, e_QmFQChannel channel, uint8_t wq, bool force_fqid, uint32_t fqid_or_align, bool init_parked, bool hold_active, bool prefer_in_cache, bool congst_avoid_ena, t_Handle congst_group, int8_t overhead_accounting_len, uint32_t tail_drop_threshold) { struct qman_softc *sc; t_QmFqrParams fqr; - unsigned int cpu; t_Handle fqrh, portal; sc = qman_sc; sched_pin(); - cpu = PCPU_GET(cpuid); /* Ensure we have got QMan port initialized */ portal = qman_portal_setup(sc); if (portal == NULL) { device_printf(sc->sc_dev, "could not setup QMan portal\n"); goto err; } fqr.h_Qm = sc->sc_qh; fqr.h_QmPortal = portal; fqr.initParked = init_parked; fqr.holdActive = hold_active; fqr.preferInCache = prefer_in_cache; /* We do not support stashing */ fqr.useContextAForStash = FALSE; fqr.p_ContextA = 0; fqr.p_ContextB = 0; fqr.channel = channel; fqr.wq = wq; fqr.shadowMode = FALSE; fqr.numOfFqids = fqids_num; /* FQID */ fqr.useForce = force_fqid; if (force_fqid) { fqr.qs.frcQ.fqid = fqid_or_align; } else { fqr.qs.nonFrcQs.align = fqid_or_align; } /* Congestion Avoidance */ fqr.congestionAvoidanceEnable = congst_avoid_ena; if (congst_avoid_ena) { fqr.congestionAvoidanceParams.h_QmCg = congst_group; fqr.congestionAvoidanceParams.overheadAccountingLength = overhead_accounting_len; fqr.congestionAvoidanceParams.fqTailDropThreshold = tail_drop_threshold; } else { fqr.congestionAvoidanceParams.h_QmCg = 0; fqr.congestionAvoidanceParams.overheadAccountingLength = 0; fqr.congestionAvoidanceParams.fqTailDropThreshold = 0; } fqrh = QM_FQR_Create(&fqr); if (fqrh == NULL) { device_printf(sc->sc_dev, "could not create Frame Queue Range" "\n"); goto err; } sc->sc_fqr_cpu[QM_FQR_GetFqid(fqrh)] = PCPU_GET(cpuid); sched_unpin(); return (fqrh); err: sched_unpin(); return (NULL); } t_Error qman_fqr_free(t_Handle fqr) { struct qman_softc *sc; t_Error error; sc = qman_sc; thread_lock(curthread); sched_bind(curthread, sc->sc_fqr_cpu[QM_FQR_GetFqid(fqr)]); thread_unlock(curthread); error = QM_FQR_Free(fqr); thread_lock(curthread); sched_unbind(curthread); thread_unlock(curthread); return (error); } t_Error qman_fqr_register_cb(t_Handle fqr, t_QmReceivedFrameCallback *callback, t_Handle app) { struct qman_softc *sc; t_Error error; t_Handle portal; sc = qman_sc; sched_pin(); /* Ensure we have got QMan port initialized */ portal = qman_portal_setup(sc); if (portal == NULL) { device_printf(sc->sc_dev, "could not setup QMan portal\n"); sched_unpin(); return (E_NOT_SUPPORTED); } error = QM_FQR_RegisterCB(fqr, callback, app); sched_unpin(); return (error); } t_Error qman_fqr_enqueue(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame) { struct qman_softc *sc; t_Error error; t_Handle portal; sc = qman_sc; sched_pin(); /* Ensure we have got QMan port initialized */ portal = qman_portal_setup(sc); if (portal == NULL) { device_printf(sc->sc_dev, "could not setup QMan portal\n"); sched_unpin(); return (E_NOT_SUPPORTED); } error = QM_FQR_Enqueue(fqr, portal, fqid_off, frame); sched_unpin(); return (error); } uint32_t qman_fqr_get_counter(t_Handle fqr, uint32_t fqid_off, e_QmFqrCounters counter) { struct qman_softc *sc; uint32_t val; t_Handle portal; sc = qman_sc; sched_pin(); /* Ensure we have got QMan port initialized */ portal = qman_portal_setup(sc); if (portal == NULL) { device_printf(sc->sc_dev, "could not setup QMan portal\n"); sched_unpin(); return (0); } val = QM_FQR_GetCounter(fqr, portal, fqid_off, counter); sched_unpin(); return (val); } t_Error qman_fqr_pull_frame(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame) { struct qman_softc *sc; t_Error error; t_Handle portal; sc = qman_sc; sched_pin(); /* Ensure we have got QMan port initialized */ portal = qman_portal_setup(sc); if (portal == NULL) { device_printf(sc->sc_dev, "could not setup QMan portal\n"); sched_unpin(); return (E_NOT_SUPPORTED); } error = QM_FQR_PullFrame(fqr, portal, fqid_off, frame); sched_unpin(); return (error); } uint32_t qman_fqr_get_base_fqid(t_Handle fqr) { struct qman_softc *sc; uint32_t val; t_Handle portal; sc = qman_sc; sched_pin(); /* Ensure we have got QMan port initialized */ portal = qman_portal_setup(sc); if (portal == NULL) { device_printf(sc->sc_dev, "could not setup QMan portal\n"); sched_unpin(); return (0); } val = QM_FQR_GetFqid(fqr); sched_unpin(); return (val); } t_Error qman_poll(e_QmPortalPollSource source) { struct qman_softc *sc; t_Error error; t_Handle portal; sc = qman_sc; sched_pin(); /* Ensure we have got QMan port initialized */ portal = qman_portal_setup(sc); if (portal == NULL) { device_printf(sc->sc_dev, "could not setup QMan portal\n"); sched_unpin(); return (E_NOT_SUPPORTED); } error = QM_Poll(sc->sc_qh, source); sched_unpin(); return (error); } /* * TODO: add polling and/or congestion support. */ /** @} */