1/******************************************************************************
2
3 � 1995-2003, 2004, 2005-2011 Freescale Semiconductor, Inc.
4 All rights reserved.
5
6 This is proprietary source code of Freescale Semiconductor Inc.,
7 and its use is subject to the NetComm Device Drivers EULA.
8 The copyright notice above does not evidence any actual or intended
9 publication of such source code.
10
11 ALTERNATIVELY, redistribution and use in source and binary forms, with
12 or without modification, are permitted provided that the following
13 conditions are met:
14     * Redistributions of source code must retain the above copyright
15       notice, this list of conditions and the following disclaimer.
16     * Redistributions in binary form must reproduce the above copyright
17       notice, this list of conditions and the following disclaimer in the
18       documentation and/or other materials provided with the distribution.
19     * Neither the name of Freescale Semiconductor nor the
20       names of its contributors may be used to endorse or promote products
21       derived from this software without specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
24 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
27 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34
35 **************************************************************************/
36/******************************************************************************
37 @File          qm.c
38
39 @Description   QM & Portal implementation
40*//***************************************************************************/
41#include "error_ext.h"
42#include "std_ext.h"
43#include "string_ext.h"
44#include "mm_ext.h"
45#include "qm.h"
46#include "qman_low.h"
47
48
49/****************************************/
50/*       static functions               */
51/****************************************/
52
53#define SLOW_POLL_IDLE   1000
54#define SLOW_POLL_BUSY   10
55
56
57static t_Error qman_volatile_dequeue(t_QmPortal     *p_QmPortal,
58                                     struct qman_fq *p_Fq,
59                                     uint32_t       vdqcr)
60{
61    ASSERT_COND((p_Fq->state == qman_fq_state_parked) ||
62                (p_Fq->state == qman_fq_state_retired));
63    ASSERT_COND(!(vdqcr & QM_VDQCR_FQID_MASK));
64    ASSERT_COND(!(p_Fq->flags & QMAN_FQ_STATE_VDQCR));
65
66    vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | p_Fq->fqid;
67    NCSW_PLOCK(p_QmPortal);
68    FQLOCK(p_Fq);
69    p_Fq->flags |= QMAN_FQ_STATE_VDQCR;
70    qm_dqrr_vdqcr_set(p_QmPortal->p_LowQmPortal, vdqcr);
71    FQUNLOCK(p_Fq);
72    PUNLOCK(p_QmPortal);
73
74    return E_OK;
75}
76
77static const char *mcr_result_str(uint8_t result)
78{
79    switch (result) {
80    case QM_MCR_RESULT_NULL:
81        return "QM_MCR_RESULT_NULL";
82    case QM_MCR_RESULT_OK:
83        return "QM_MCR_RESULT_OK";
84    case QM_MCR_RESULT_ERR_FQID:
85        return "QM_MCR_RESULT_ERR_FQID";
86    case QM_MCR_RESULT_ERR_FQSTATE:
87        return "QM_MCR_RESULT_ERR_FQSTATE";
88    case QM_MCR_RESULT_ERR_NOTEMPTY:
89        return "QM_MCR_RESULT_ERR_NOTEMPTY";
90    case QM_MCR_RESULT_PENDING:
91        return "QM_MCR_RESULT_PENDING";
92    }
93    return "<unknown MCR result>";
94}
95
96static t_Error qman_create_fq(t_QmPortal        *p_QmPortal,
97                              uint32_t          fqid,
98                              uint32_t          flags,
99                              struct qman_fq    *p_Fq)
100{
101    struct qm_fqd fqd;
102    struct qm_mcr_queryfq_np np;
103    struct qm_mc_command *p_Mcc;
104    struct qm_mc_result *p_Mcr;
105
106    p_Fq->fqid = fqid;
107    p_Fq->flags = flags;
108    p_Fq->state = qman_fq_state_oos;
109    p_Fq->cgr_groupid = 0;
110    if (!(flags & QMAN_FQ_FLAG_RECOVER) ||
111            (flags & QMAN_FQ_FLAG_NO_MODIFY))
112        return E_OK;
113    /* Everything else is RECOVER support */
114    NCSW_PLOCK(p_QmPortal);
115    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
116    p_Mcc->queryfq.fqid = fqid;
117    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYFQ);
118    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
119    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ);
120    if (p_Mcr->result != QM_MCR_RESULT_OK) {
121        PUNLOCK(p_QmPortal);
122        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("QUERYFQ failed: %s", mcr_result_str(p_Mcr->result)));
123    }
124    fqd = p_Mcr->queryfq.fqd;
125    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
126    p_Mcc->queryfq_np.fqid = fqid;
127    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYFQ_NP);
128    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
129    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ_NP);
130    if (p_Mcr->result != QM_MCR_RESULT_OK) {
131        PUNLOCK(p_QmPortal);
132        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("UERYFQ_NP failed: %s", mcr_result_str(p_Mcr->result)));
133    }
134    np = p_Mcr->queryfq_np;
135    /* Phew, have queryfq and queryfq_np results, stitch together
136     * the FQ object from those. */
137    p_Fq->cgr_groupid = fqd.cgid;
138    switch (np.state & QM_MCR_NP_STATE_MASK) {
139    case QM_MCR_NP_STATE_OOS:
140        break;
141    case QM_MCR_NP_STATE_RETIRED:
142        p_Fq->state = qman_fq_state_retired;
143        if (np.frm_cnt)
144            p_Fq->flags |= QMAN_FQ_STATE_NE;
145        break;
146    case QM_MCR_NP_STATE_TEN_SCHED:
147    case QM_MCR_NP_STATE_TRU_SCHED:
148    case QM_MCR_NP_STATE_ACTIVE:
149        p_Fq->state = qman_fq_state_sched;
150        if (np.state & QM_MCR_NP_STATE_R)
151            p_Fq->flags |= QMAN_FQ_STATE_CHANGING;
152        break;
153    case QM_MCR_NP_STATE_PARKED:
154        p_Fq->state = qman_fq_state_parked;
155        break;
156    default:
157        ASSERT_COND(FALSE);
158    }
159    if (fqd.fq_ctrl & QM_FQCTRL_CGE)
160        p_Fq->state |= QMAN_FQ_STATE_CGR_EN;
161    PUNLOCK(p_QmPortal);
162
163    return E_OK;
164}
165
166static void qman_destroy_fq(struct qman_fq *p_Fq, uint32_t flags)
167{
168    /* We don't need to lock the FQ as it is a pre-condition that the FQ be
169     * quiesced. Instead, run some checks. */
170    UNUSED(flags);
171    switch (p_Fq->state) {
172    case qman_fq_state_parked:
173        ASSERT_COND(flags & QMAN_FQ_DESTROY_PARKED);
174    case qman_fq_state_oos:
175        return;
176    default:
177        break;
178    }
179    ASSERT_COND(FALSE);
180}
181
182static t_Error qman_init_fq(t_QmPortal          *p_QmPortal,
183                            struct qman_fq      *p_Fq,
184                            uint32_t            flags,
185                            struct qm_mcc_initfq *p_Opts)
186{
187    struct qm_mc_command    *p_Mcc;
188    struct qm_mc_result     *p_Mcr;
189    uint8_t res, myverb = (uint8_t)((flags & QMAN_INITFQ_FLAG_SCHED) ?
190        QM_MCC_VERB_INITFQ_SCHED : QM_MCC_VERB_INITFQ_PARKED);
191
192    SANITY_CHECK_RETURN_ERROR((p_Fq->state == qman_fq_state_oos) ||
193                              (p_Fq->state == qman_fq_state_parked),
194                              E_INVALID_STATE);
195
196    if (p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)
197        return ERROR_CODE(E_INVALID_VALUE);
198    /* Issue an INITFQ_[PARKED|SCHED] management command */
199    NCSW_PLOCK(p_QmPortal);
200    FQLOCK(p_Fq);
201    if ((p_Fq->flags & QMAN_FQ_STATE_CHANGING) ||
202            ((p_Fq->state != qman_fq_state_oos) &&
203                (p_Fq->state != qman_fq_state_parked))) {
204        FQUNLOCK(p_Fq);
205        PUNLOCK(p_QmPortal);
206        return ERROR_CODE(E_BUSY);
207    }
208    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
209    Mem2IOCpy32((void*)&p_Mcc->initfq, p_Opts, sizeof(struct qm_mcc_initfq));
210    qm_mc_commit(p_QmPortal->p_LowQmPortal, myverb);
211    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
212    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == myverb);
213    res = p_Mcr->result;
214    if (res != QM_MCR_RESULT_OK) {
215        FQUNLOCK(p_Fq);
216        PUNLOCK(p_QmPortal);
217        RETURN_ERROR(MINOR, E_INVALID_STATE,("INITFQ failed: %s", mcr_result_str(res)));
218    }
219
220    if (p_Mcc->initfq.we_mask & QM_INITFQ_WE_FQCTRL) {
221        if (p_Mcc->initfq.fqd.fq_ctrl & QM_FQCTRL_CGE)
222            p_Fq->flags |= QMAN_FQ_STATE_CGR_EN;
223        else
224            p_Fq->flags &= ~QMAN_FQ_STATE_CGR_EN;
225    }
226    if (p_Mcc->initfq.we_mask & QM_INITFQ_WE_CGID)
227        p_Fq->cgr_groupid = p_Mcc->initfq.fqd.cgid;
228    p_Fq->state = (flags & QMAN_INITFQ_FLAG_SCHED) ?
229            qman_fq_state_sched : qman_fq_state_parked;
230    FQUNLOCK(p_Fq);
231    PUNLOCK(p_QmPortal);
232    return E_OK;
233}
234
235static t_Error qman_retire_fq(t_QmPortal        *p_QmPortal,
236                              struct qman_fq    *p_Fq,
237                              uint32_t          *p_Flags,
238                              bool              drain)
239{
240    struct qm_mc_command    *p_Mcc;
241    struct qm_mc_result     *p_Mcr;
242    t_Error                 err = E_OK;
243    uint8_t                 res;
244
245    SANITY_CHECK_RETURN_ERROR((p_Fq->state == qman_fq_state_parked) ||
246                              (p_Fq->state == qman_fq_state_sched),
247                              E_INVALID_STATE);
248
249    if (p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)
250        return E_INVALID_VALUE;
251    NCSW_PLOCK(p_QmPortal);
252    FQLOCK(p_Fq);
253    if ((p_Fq->flags & QMAN_FQ_STATE_CHANGING) ||
254            (p_Fq->state == qman_fq_state_retired) ||
255                (p_Fq->state == qman_fq_state_oos)) {
256        err = E_BUSY;
257        goto out;
258    }
259    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
260    p_Mcc->alterfq.fqid = p_Fq->fqid;
261    if (drain)
262        p_Mcc->alterfq.context_b = (uint32_t)PTR_TO_UINT(p_Fq);
263    qm_mc_commit(p_QmPortal->p_LowQmPortal,
264                 (uint8_t)((drain)?QM_MCC_VERB_ALTER_RETIRE_CTXB:QM_MCC_VERB_ALTER_RETIRE));
265    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
266    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) ==
267                (drain)?QM_MCR_VERB_ALTER_RETIRE_CTXB:QM_MCR_VERB_ALTER_RETIRE);
268    res = p_Mcr->result;
269    if (res == QM_MCR_RESULT_OK)
270    {
271        /* Process 'fq' right away, we'll ignore FQRNI */
272        if (p_Mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY)
273            p_Fq->flags |= QMAN_FQ_STATE_NE;
274        if (p_Mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT)
275            p_Fq->flags |= QMAN_FQ_STATE_ORL;
276        p_Fq->state = qman_fq_state_retired;
277    }
278    else if (res == QM_MCR_RESULT_PENDING)
279        p_Fq->flags |= QMAN_FQ_STATE_CHANGING;
280    else {
281        XX_Print("ALTER_RETIRE failed: %s\n",
282                mcr_result_str(res));
283        err = E_INVALID_STATE;
284    }
285    if (p_Flags)
286        *p_Flags = p_Fq->flags;
287out:
288    FQUNLOCK(p_Fq);
289    PUNLOCK(p_QmPortal);
290    return err;
291}
292
293static t_Error qman_oos_fq(t_QmPortal *p_QmPortal, struct qman_fq *p_Fq)
294{
295    struct qm_mc_command    *p_Mcc;
296    struct qm_mc_result     *p_Mcr;
297    uint8_t                 res;
298
299    ASSERT_COND(p_Fq->state == qman_fq_state_retired);
300    if (p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)
301        return ERROR_CODE(E_INVALID_VALUE);
302    NCSW_PLOCK(p_QmPortal);
303    FQLOCK(p_Fq);
304    if ((p_Fq->flags & QMAN_FQ_STATE_BLOCKOOS) ||
305            (p_Fq->state != qman_fq_state_retired)) {
306        FQUNLOCK(p_Fq);
307        PUNLOCK(p_QmPortal);
308        return ERROR_CODE(E_BUSY);
309    }
310    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
311    p_Mcc->alterfq.fqid = p_Fq->fqid;
312    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_ALTER_OOS);
313    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
314    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_OOS);
315    res = p_Mcr->result;
316    if (res != QM_MCR_RESULT_OK) {
317        FQUNLOCK(p_Fq);
318        PUNLOCK(p_QmPortal);
319        RETURN_ERROR(MINOR, E_INVALID_STATE, ("ALTER_OOS failed: %s\n", mcr_result_str(res)));
320    }
321    p_Fq->state = qman_fq_state_oos;
322
323    FQUNLOCK(p_Fq);
324    PUNLOCK(p_QmPortal);
325    return E_OK;
326}
327
328static t_Error qman_schedule_fq(t_QmPortal *p_QmPortal, struct qman_fq *p_Fq)
329{
330    struct qm_mc_command    *p_Mcc;
331    struct qm_mc_result     *p_Mcr;
332    uint8_t                 res;
333
334    ASSERT_COND(p_Fq->state == qman_fq_state_parked);
335    if (p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)
336        return ERROR_CODE(E_INVALID_VALUE);
337    /* Issue a ALTERFQ_SCHED management command */
338    NCSW_PLOCK(p_QmPortal);
339    FQLOCK(p_Fq);
340    if ((p_Fq->flags & QMAN_FQ_STATE_CHANGING) ||
341            (p_Fq->state != qman_fq_state_parked)) {
342        FQUNLOCK(p_Fq);
343        PUNLOCK(p_QmPortal);
344        return ERROR_CODE(E_BUSY);
345    }
346    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
347    p_Mcc->alterfq.fqid = p_Fq->fqid;
348    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_ALTER_SCHED);
349    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
350    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_SCHED);
351    res = p_Mcr->result;
352    if (res != QM_MCR_RESULT_OK) {
353        FQUNLOCK(p_Fq);
354        PUNLOCK(p_QmPortal);
355        RETURN_ERROR(MINOR, E_INVALID_STATE, ("ALTER_SCHED failed: %s\n", mcr_result_str(res)));
356    }
357    p_Fq->state = qman_fq_state_sched;
358
359    FQUNLOCK(p_Fq);
360    PUNLOCK(p_QmPortal);
361    return E_OK;
362}
363
364/* Inline helper to reduce nesting in LoopMessageRing() */
365static __inline__ void fq_state_change(struct qman_fq *p_Fq,
366                                       struct qm_mr_entry *p_Msg,
367                                       uint8_t verb)
368{
369    FQLOCK(p_Fq);
370    switch(verb) {
371        case QM_MR_VERB_FQRL:
372            ASSERT_COND(p_Fq->flags & QMAN_FQ_STATE_ORL);
373            p_Fq->flags &= ~QMAN_FQ_STATE_ORL;
374            break;
375        case QM_MR_VERB_FQRN:
376            ASSERT_COND((p_Fq->state == qman_fq_state_parked) ||
377                (p_Fq->state == qman_fq_state_sched));
378            ASSERT_COND(p_Fq->flags & QMAN_FQ_STATE_CHANGING);
379            p_Fq->flags &= ~QMAN_FQ_STATE_CHANGING;
380            if (p_Msg->fq.fqs & QM_MR_FQS_NOTEMPTY)
381                p_Fq->flags |= QMAN_FQ_STATE_NE;
382            if (p_Msg->fq.fqs & QM_MR_FQS_ORLPRESENT)
383                p_Fq->flags |= QMAN_FQ_STATE_ORL;
384            p_Fq->state = qman_fq_state_retired;
385            break;
386        case QM_MR_VERB_FQPN:
387            ASSERT_COND(p_Fq->state == qman_fq_state_sched);
388            ASSERT_COND(p_Fq->flags & QMAN_FQ_STATE_CHANGING);
389            p_Fq->state = qman_fq_state_parked;
390    }
391    FQUNLOCK(p_Fq);
392}
393
394static t_Error freeDrainedFq(struct qman_fq *p_Fq)
395{
396    t_QmFqr     *p_QmFqr;
397    uint32_t    i;
398
399    ASSERT_COND(p_Fq);
400    p_QmFqr = (t_QmFqr *)p_Fq->h_QmFqr;
401    ASSERT_COND(p_QmFqr);
402
403    ASSERT_COND(!p_QmFqr->p_DrainedFqs[p_Fq->fqidOffset]);
404    p_QmFqr->p_DrainedFqs[p_Fq->fqidOffset] = TRUE;
405    p_QmFqr->numOfDrainedFqids++;
406    if (p_QmFqr->numOfDrainedFqids == p_QmFqr->numOfFqids)
407    {
408        for (i=0;i<p_QmFqr->numOfFqids;i++)
409        {
410            if ((p_QmFqr->p_Fqs[i]->state == qman_fq_state_retired) &&
411                    (qman_oos_fq(p_QmFqr->h_QmPortal, p_QmFqr->p_Fqs[i]) != E_OK))
412                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_oos_fq() failed!"));
413            qman_destroy_fq(p_QmFqr->p_Fqs[i], 0);
414            XX_FreeSmart(p_QmFqr->p_Fqs[i]);
415        }
416        XX_Free(p_QmFqr->p_DrainedFqs);
417        p_QmFqr->p_DrainedFqs = NULL;
418
419        if (p_QmFqr->f_CompletionCB)
420        {
421            p_QmFqr->f_CompletionCB(p_QmFqr->h_App, p_QmFqr);
422            XX_Free(p_QmFqr->p_Fqs);
423            if (p_QmFqr->fqidBase)
424                QmFqidPut(p_QmFqr->h_Qm, p_QmFqr->fqidBase);
425            XX_Free(p_QmFqr);
426        }
427    }
428
429    return E_OK;
430}
431
432static t_Error drainRetiredFq(struct qman_fq *p_Fq)
433{
434    t_QmFqr     *p_QmFqr;
435
436    ASSERT_COND(p_Fq);
437    p_QmFqr = (t_QmFqr *)p_Fq->h_QmFqr;
438    ASSERT_COND(p_QmFqr);
439
440    if (p_Fq->flags & QMAN_FQ_STATE_NE)
441    {
442        if (qman_volatile_dequeue(p_QmFqr->h_QmPortal, p_Fq,
443                                (QM_VDQCR_PRECEDENCE_VDQCR | QM_VDQCR_NUMFRAMES_TILLEMPTY)) != E_OK)
444
445            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("drain with volatile failed"));
446        return E_OK;
447    }
448    else
449        return freeDrainedFq(p_Fq);
450}
451
452static e_RxStoreResponse drainCB(t_Handle h_App,
453                                 t_Handle h_QmFqr,
454                                 t_Handle h_QmPortal,
455                                 uint32_t fqidOffset,
456                                 t_DpaaFD *p_Frame)
457{
458    UNUSED(h_App);
459    UNUSED(h_QmFqr);
460    UNUSED(h_QmPortal);
461    UNUSED(fqidOffset);
462    UNUSED(p_Frame);
463
464    DBG(TRACE,("got fd for fqid %d", ((t_QmFqr *)h_QmFqr)->fqidBase + fqidOffset));
465    return e_RX_STORE_RESPONSE_CONTINUE;
466}
467
468static void cb_ern_dcErn(t_Handle                   h_App,
469                         t_Handle                   h_QmPortal,
470                         struct qman_fq             *p_Fq,
471                         const struct qm_mr_entry   *p_Msg)
472{
473    static int cnt = 0;
474    UNUSED(p_Fq);
475    UNUSED(p_Msg);
476    UNUSED(h_App);
477    UNUSED(h_QmPortal);
478
479    XX_Print("cb_ern_dcErn_fqs() unimplemented %d\n", ++cnt);
480}
481
482static void cb_fqs(t_Handle                   h_App,
483                   t_Handle                   h_QmPortal,
484                   struct qman_fq             *p_Fq,
485                   const struct qm_mr_entry   *p_Msg)
486{
487    UNUSED(p_Msg);
488    UNUSED(h_App);
489    UNUSED(h_QmPortal);
490
491    if (p_Fq->state == qman_fq_state_retired &&
492        !(p_Fq->flags & QMAN_FQ_STATE_ORL))
493        drainRetiredFq(p_Fq);
494}
495
496static void null_cb_mr(t_Handle                   h_App,
497                       t_Handle                   h_QmPortal,
498                       struct qman_fq             *p_Fq,
499                       const struct qm_mr_entry   *p_Msg)
500{
501    t_QmPortal      *p_QmPortal = (t_QmPortal *)h_QmPortal;
502
503    UNUSED(p_Fq);UNUSED(h_App);
504
505    if ((p_Msg->verb & QM_MR_VERB_DC_ERN) == QM_MR_VERB_DC_ERN)
506        XX_Print("Ignoring unowned MR frame on cpu %d, dc-portal 0x%02x.\n",
507                 p_QmPortal->p_LowQmPortal->config.cpu,p_Msg->dcern.portal);
508    else
509        XX_Print("Ignoring unowned MR frame on cpu %d, verb 0x%02x.\n",
510                 p_QmPortal->p_LowQmPortal->config.cpu,p_Msg->verb);
511}
512
513static uint32_t LoopMessageRing(t_QmPortal *p_QmPortal, uint32_t is)
514{
515    struct qm_mr_entry          *p_Msg;
516
517    if (is & QM_PIRQ_CSCI) {
518        struct qm_mc_result *p_Mcr;
519        struct qman_cgrs    tmp;
520        uint32_t            mask;
521        unsigned int        i, j;
522
523        NCSW_PLOCK(p_QmPortal);
524        qm_mc_start(p_QmPortal->p_LowQmPortal);
525        qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYCONGESTION);
526        while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
527
528        /* cgrs[0] is the portal mask for its cg's, cgrs[1] is the
529           previous state of cg's */
530        for (i = 0; i < QM_MAX_NUM_OF_CGS/32; i++)
531        {
532            /* get curent state */
533            tmp.q.__state[i] = p_Mcr->querycongestion.state.__state[i];
534            /* keep only cg's that are registered for this portal */
535            tmp.q.__state[i] &= p_QmPortal->cgrs[0].q.__state[i];
536            /* handle only cg's that changed their state from previous exception */
537            tmp.q.__state[i] ^= p_QmPortal->cgrs[1].q.__state[i];
538            /* update previous */
539            p_QmPortal->cgrs[1].q.__state[i] = p_Mcr->querycongestion.state.__state[i];
540        }
541        PUNLOCK(p_QmPortal);
542
543        /* if in interrupt */
544        /* call the callback routines for any CG with a changed state */
545        for (i = 0; i < QM_MAX_NUM_OF_CGS/32; i++)
546            for(j=0, mask = 0x80000000; j<32 ; j++, mask>>=1)
547            {
548                if(tmp.q.__state[i] & mask)
549                {
550                    t_QmCg *p_QmCg = (t_QmCg *)(p_QmPortal->cgsHandles[i*32 + j]);
551                    if(p_QmCg->f_Exception)
552                        p_QmCg->f_Exception(p_QmCg->h_App, e_QM_EX_CG_STATE_CHANGE);
553                }
554            }
555
556    }
557
558
559    if (is & QM_PIRQ_EQRI) {
560        NCSW_PLOCK(p_QmPortal);
561        qmPortalEqcrCceUpdate(p_QmPortal->p_LowQmPortal);
562        qm_eqcr_set_ithresh(p_QmPortal->p_LowQmPortal, 0);
563        PUNLOCK(p_QmPortal);
564    }
565
566    if (is & QM_PIRQ_MRI) {
567mr_loop:
568        qmPortalMrPvbUpdate(p_QmPortal->p_LowQmPortal);
569        p_Msg = qm_mr_current(p_QmPortal->p_LowQmPortal);
570        if (p_Msg) {
571            struct qman_fq  *p_FqFqs  = (void *)p_Msg->fq.contextB;
572            struct qman_fq  *p_FqErn  = (void *)p_Msg->ern.tag;
573            uint8_t         verb    =(uint8_t)(p_Msg->verb & QM_MR_VERB_TYPE_MASK);
574            t_QmRejectedFrameInfo   rejectedFrameInfo;
575
576            memset(&rejectedFrameInfo, 0, sizeof(t_QmRejectedFrameInfo));
577            if (!(verb & QM_MR_VERB_DC_ERN))
578            {
579                switch(p_Msg->ern.rc)
580                {
581                    case(QM_MR_RC_CGR_TAILDROP):
582                        rejectedFrameInfo.rejectionCode = e_QM_RC_CG_TAILDROP;
583                        rejectedFrameInfo.cg.cgId = (uint8_t)p_FqErn->cgr_groupid;
584                        break;
585                    case(QM_MR_RC_WRED):
586                        rejectedFrameInfo.rejectionCode = e_QM_RC_CG_WRED;
587                        rejectedFrameInfo.cg.cgId = (uint8_t)p_FqErn->cgr_groupid;
588                        break;
589                    case(QM_MR_RC_FQ_TAILDROP):
590                        rejectedFrameInfo.rejectionCode = e_QM_RC_FQ_TAILDROP;
591                        rejectedFrameInfo.cg.cgId = (uint8_t)p_FqErn->cgr_groupid;
592                        break;
593                    case(QM_MR_RC_ERROR):
594                        break;
595                    default:
596                        REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ("Unknown rejection code"));
597                }
598                if (!p_FqErn)
599                    p_QmPortal->p_NullCB->ern(p_QmPortal->h_App, NULL, p_QmPortal, 0, (t_DpaaFD*)&p_Msg->ern.fd, &rejectedFrameInfo);
600                else
601                    p_FqErn->cb.ern(p_FqErn->h_App, p_FqErn->h_QmFqr, p_QmPortal, p_FqErn->fqidOffset, (t_DpaaFD*)&p_Msg->ern.fd, &rejectedFrameInfo);
602            } else if (verb == QM_MR_VERB_DC_ERN)
603            {
604                if (!p_FqErn)
605                    p_QmPortal->p_NullCB->dc_ern(NULL, p_QmPortal, NULL, p_Msg);
606                else
607                    p_FqErn->cb.dc_ern(p_FqErn->h_App, p_QmPortal, p_FqErn, p_Msg);
608            } else
609            {
610                if (verb == QM_MR_VERB_FQRNI)
611                    ; /* we drop FQRNIs on the floor */
612                else if (!p_FqFqs)
613                            p_QmPortal->p_NullCB->fqs(NULL, p_QmPortal, NULL, p_Msg);
614                else if ((verb == QM_MR_VERB_FQRN) ||
615                         (verb == QM_MR_VERB_FQRL) ||
616                         (verb == QM_MR_VERB_FQPN))
617                {
618                    fq_state_change(p_FqFqs, p_Msg, verb);
619                    p_FqFqs->cb.fqs(p_FqFqs->h_App, p_QmPortal, p_FqFqs, p_Msg);
620                }
621            }
622            qm_mr_next(p_QmPortal->p_LowQmPortal);
623            qmPortalMrCciConsume(p_QmPortal->p_LowQmPortal, 1);
624
625            goto mr_loop;
626        }
627    }
628
629    return is & (QM_PIRQ_CSCI | QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI);
630}
631
632static void LoopDequeueRing(t_Handle h_QmPortal)
633{
634    struct qm_dqrr_entry        *p_Dq;
635    struct qman_fq              *p_Fq;
636    enum qman_cb_dqrr_result    res = qman_cb_dqrr_consume;
637    e_RxStoreResponse           tmpRes;
638    t_QmPortal                  *p_QmPortal = (t_QmPortal *)h_QmPortal;
639    int                         prefetch = !(p_QmPortal->options & QMAN_PORTAL_FLAG_RSTASH);
640
641    while (res != qman_cb_dqrr_pause)
642    {
643        if (prefetch)
644            qmPortalDqrrPvbPrefetch(p_QmPortal->p_LowQmPortal);
645        qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
646        p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
647        if (!p_Dq)
648            break;
649        p_Fq = (void *)p_Dq->contextB;
650        if (p_Dq->stat & QM_DQRR_STAT_UNSCHEDULED) {
651            /* We only set QMAN_FQ_STATE_NE when retiring, so we only need
652             * to check for clearing it when doing volatile dequeues. It's
653             * one less thing to check in the critical path (SDQCR). */
654            tmpRes = p_Fq->cb.dqrr(p_Fq->h_App, p_Fq->h_QmFqr, p_QmPortal, p_Fq->fqidOffset, (t_DpaaFD*)&p_Dq->fd);
655            if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
656                res = qman_cb_dqrr_pause;
657            /* Check for VDQCR completion */
658            if (p_Dq->stat & QM_DQRR_STAT_DQCR_EXPIRED)
659                p_Fq->flags &= ~QMAN_FQ_STATE_VDQCR;
660            if (p_Dq->stat & QM_DQRR_STAT_FQ_EMPTY)
661            {
662                p_Fq->flags &= ~QMAN_FQ_STATE_NE;
663                freeDrainedFq(p_Fq);
664            }
665        }
666        else
667        {
668            /* Interpret 'dq' from the owner's perspective. */
669            /* use portal default handlers */
670            ASSERT_COND(p_Dq->fqid);
671            if (p_Fq)
672            {
673                tmpRes = p_Fq->cb.dqrr(p_Fq->h_App,
674                                       p_Fq->h_QmFqr,
675                                       p_QmPortal,
676                                       p_Fq->fqidOffset,
677                                       (t_DpaaFD*)&p_Dq->fd);
678                if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
679                    res = qman_cb_dqrr_pause;
680                else if (p_Fq->state == qman_fq_state_waiting_parked)
681                    res = qman_cb_dqrr_park;
682            }
683            else
684            {
685                tmpRes = p_QmPortal->p_NullCB->dqrr(p_QmPortal->h_App,
686                                                    NULL,
687                                                    p_QmPortal,
688                                                    p_Dq->fqid,
689                                                    (t_DpaaFD*)&p_Dq->fd);
690                if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
691                    res = qman_cb_dqrr_pause;
692            }
693        }
694
695        /* Parking isn't possible unless HELDACTIVE was set. NB,
696         * FORCEELIGIBLE implies HELDACTIVE, so we only need to
697         * check for HELDACTIVE to cover both. */
698        ASSERT_COND((p_Dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) ||
699                    (res != qman_cb_dqrr_park));
700        if (p_QmPortal->options & QMAN_PORTAL_FLAG_DCA) {
701            /* Defer just means "skip it, I'll consume it myself later on" */
702            if (res != qman_cb_dqrr_defer)
703                qmPortalDqrrDcaConsume1ptr(p_QmPortal->p_LowQmPortal,
704                                           p_Dq,
705                                           (res == qman_cb_dqrr_park));
706            qm_dqrr_next(p_QmPortal->p_LowQmPortal);
707        } else {
708            if (res == qman_cb_dqrr_park)
709                /* The only thing to do for non-DCA is the park-request */
710                qm_dqrr_park_ci(p_QmPortal->p_LowQmPortal);
711            qm_dqrr_next(p_QmPortal->p_LowQmPortal);
712            qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
713        }
714    }
715}
716
717static void LoopDequeueRingDcaOptimized(t_Handle h_QmPortal)
718{
719    struct qm_dqrr_entry        *p_Dq;
720    struct qman_fq              *p_Fq;
721    enum qman_cb_dqrr_result    res = qman_cb_dqrr_consume;
722    e_RxStoreResponse           tmpRes;
723    t_QmPortal                  *p_QmPortal = (t_QmPortal *)h_QmPortal;
724
725    while (res != qman_cb_dqrr_pause)
726    {
727        qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
728        p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
729        if (!p_Dq)
730            break;
731        p_Fq = (void *)p_Dq->contextB;
732        if (p_Dq->stat & QM_DQRR_STAT_UNSCHEDULED) {
733            /* We only set QMAN_FQ_STATE_NE when retiring, so we only need
734             * to check for clearing it when doing volatile dequeues. It's
735             * one less thing to check in the critical path (SDQCR). */
736            tmpRes = p_Fq->cb.dqrr(p_Fq->h_App, p_Fq->h_QmFqr, p_QmPortal, p_Fq->fqidOffset, (t_DpaaFD*)&p_Dq->fd);
737            if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
738                res = qman_cb_dqrr_pause;
739            /* Check for VDQCR completion */
740            if (p_Dq->stat & QM_DQRR_STAT_DQCR_EXPIRED)
741                p_Fq->flags &= ~QMAN_FQ_STATE_VDQCR;
742            if (p_Dq->stat & QM_DQRR_STAT_FQ_EMPTY)
743            {
744                p_Fq->flags &= ~QMAN_FQ_STATE_NE;
745                freeDrainedFq(p_Fq);
746            }
747        }
748        else
749        {
750            /* Interpret 'dq' from the owner's perspective. */
751            /* use portal default handlers */
752            ASSERT_COND(p_Dq->fqid);
753            if (p_Fq)
754            {
755                tmpRes = p_Fq->cb.dqrr(p_Fq->h_App,
756                                       p_Fq->h_QmFqr,
757                                       p_QmPortal,
758                                       p_Fq->fqidOffset,
759                                       (t_DpaaFD*)&p_Dq->fd);
760                if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
761                    res = qman_cb_dqrr_pause;
762                else if (p_Fq->state == qman_fq_state_waiting_parked)
763                    res = qman_cb_dqrr_park;
764            }
765            else
766            {
767                tmpRes = p_QmPortal->p_NullCB->dqrr(p_QmPortal->h_App,
768                                                    NULL,
769                                                    p_QmPortal,
770                                                    p_Dq->fqid,
771                                                    (t_DpaaFD*)&p_Dq->fd);
772                if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
773                    res = qman_cb_dqrr_pause;
774            }
775        }
776
777        /* Parking isn't possible unless HELDACTIVE was set. NB,
778         * FORCEELIGIBLE implies HELDACTIVE, so we only need to
779         * check for HELDACTIVE to cover both. */
780        ASSERT_COND((p_Dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) ||
781                (res != qman_cb_dqrr_park));
782        /* Defer just means "skip it, I'll consume it myself later on" */
783        if (res != qman_cb_dqrr_defer)
784            qmPortalDqrrDcaConsume1ptr(p_QmPortal->p_LowQmPortal,
785                                       p_Dq,
786                                       (res == qman_cb_dqrr_park));
787        qm_dqrr_next(p_QmPortal->p_LowQmPortal);
788    }
789}
790
791static void LoopDequeueRingOptimized(t_Handle h_QmPortal)
792{
793    struct qm_dqrr_entry        *p_Dq;
794    struct qman_fq              *p_Fq;
795    enum qman_cb_dqrr_result    res = qman_cb_dqrr_consume;
796    e_RxStoreResponse           tmpRes;
797    t_QmPortal                  *p_QmPortal = (t_QmPortal *)h_QmPortal;
798
799    while (res != qman_cb_dqrr_pause)
800    {
801        qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
802        p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
803        if (!p_Dq)
804            break;
805        p_Fq = (void *)p_Dq->contextB;
806        if (p_Dq->stat & QM_DQRR_STAT_UNSCHEDULED) {
807            /* We only set QMAN_FQ_STATE_NE when retiring, so we only need
808             * to check for clearing it when doing volatile dequeues. It's
809             * one less thing to check in the critical path (SDQCR). */
810            tmpRes = p_Fq->cb.dqrr(p_Fq->h_App, p_Fq->h_QmFqr, p_QmPortal, p_Fq->fqidOffset, (t_DpaaFD*)&p_Dq->fd);
811            if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
812                res = qman_cb_dqrr_pause;
813            /* Check for VDQCR completion */
814            if (p_Dq->stat & QM_DQRR_STAT_DQCR_EXPIRED)
815                p_Fq->flags &= ~QMAN_FQ_STATE_VDQCR;
816            if (p_Dq->stat & QM_DQRR_STAT_FQ_EMPTY)
817            {
818                p_Fq->flags &= ~QMAN_FQ_STATE_NE;
819                freeDrainedFq(p_Fq);
820            }
821        }
822        else
823        {
824            /* Interpret 'dq' from the owner's perspective. */
825            /* use portal default handlers */
826            ASSERT_COND(p_Dq->fqid);
827            if (p_Fq)
828            {
829                tmpRes = p_Fq->cb.dqrr(p_Fq->h_App,
830                                       p_Fq->h_QmFqr,
831                                       p_QmPortal,
832                                       p_Fq->fqidOffset,
833                                       (t_DpaaFD*)&p_Dq->fd);
834                if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
835                    res = qman_cb_dqrr_pause;
836                else if (p_Fq->state == qman_fq_state_waiting_parked)
837                    res = qman_cb_dqrr_park;
838            }
839            else
840            {
841                tmpRes = p_QmPortal->p_NullCB->dqrr(p_QmPortal->h_App,
842                                                    NULL,
843                                                    p_QmPortal,
844                                                    p_Dq->fqid,
845                                                    (t_DpaaFD*)&p_Dq->fd);
846                if (tmpRes == e_RX_STORE_RESPONSE_PAUSE)
847                    res = qman_cb_dqrr_pause;
848            }
849        }
850
851        /* Parking isn't possible unless HELDACTIVE was set. NB,
852         * FORCEELIGIBLE implies HELDACTIVE, so we only need to
853         * check for HELDACTIVE to cover both. */
854        ASSERT_COND((p_Dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) ||
855                (res != qman_cb_dqrr_park));
856        if (res == qman_cb_dqrr_park)
857            /* The only thing to do for non-DCA is the park-request */
858            qm_dqrr_park_ci(p_QmPortal->p_LowQmPortal);
859        qm_dqrr_next(p_QmPortal->p_LowQmPortal);
860        qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
861    }
862}
863
864/* Portal interrupt handler */
865static void portal_isr(void *ptr)
866{
867    t_QmPortal  *p_QmPortal = ptr;
868    uint32_t    event = 0;
869    uint32_t    enableEvents = qm_isr_enable_read(p_QmPortal->p_LowQmPortal);
870
871    DBG(TRACE, ("software-portal %d got interrupt", p_QmPortal->p_LowQmPortal->config.cpu));
872
873    event |= (qm_isr_status_read(p_QmPortal->p_LowQmPortal) &
874            enableEvents);
875
876    qm_isr_status_clear(p_QmPortal->p_LowQmPortal, event);
877    /* Only do fast-path handling if it's required */
878    if (/*(event & QM_PIRQ_DQRI) &&*/
879        (p_QmPortal->options & QMAN_PORTAL_FLAG_IRQ_FAST))
880        p_QmPortal->f_LoopDequeueRingCB(p_QmPortal);
881    if (p_QmPortal->options & QMAN_PORTAL_FLAG_IRQ_SLOW)
882        LoopMessageRing(p_QmPortal, event);
883}
884
885
886static t_Error qman_query_fq_np(t_QmPortal *p_QmPortal, struct qman_fq *p_Fq, struct qm_mcr_queryfq_np *p_Np)
887{
888    struct qm_mc_command    *p_Mcc;
889    struct qm_mc_result     *p_Mcr;
890    uint8_t                 res;
891
892    NCSW_PLOCK(p_QmPortal);
893    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
894    p_Mcc->queryfq_np.fqid = p_Fq->fqid;
895    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYFQ_NP);
896    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
897    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP);
898    res = p_Mcr->result;
899    if (res == QM_MCR_RESULT_OK)
900        *p_Np = p_Mcr->queryfq_np;
901    PUNLOCK(p_QmPortal);
902    if (res != QM_MCR_RESULT_OK)
903        RETURN_ERROR(MINOR, E_INVALID_STATE, ("QUERYFQ_NP failed: %s\n", mcr_result_str(res)));
904    return E_OK;
905}
906
907static uint8_t QmCgGetCgId(t_Handle h_QmCg)
908{
909   t_QmCg *p_QmCg = (t_QmCg *)h_QmCg;
910
911   return p_QmCg->id;
912
913}
914
915static t_Error qm_new_fq(t_QmPortal                         *p_QmPortal,
916                         uint32_t                           fqid,
917                         uint32_t                           fqidOffset,
918                         uint32_t                           channel,
919                         uint32_t                           wqid,
920                         uint16_t                           count,
921                         uint32_t                           flags,
922                         t_QmFqrCongestionAvoidanceParams   *p_CgParams,
923                         t_QmContextA                       *p_ContextA,
924                         t_QmContextB                       *p_ContextB,
925                         bool                               initParked,
926                         t_Handle                           h_QmFqr,
927                         struct qman_fq                     **p_Fqs)
928{
929    struct qman_fq          *p_Fq = NULL;
930    struct qm_mcc_initfq    fq_opts;
931    uint32_t                i;
932    t_Error                 err = E_OK;
933    int         gap, tmp;
934    uint32_t    tmpA, tmpN, ta=0, tn=0, initFqFlag;
935
936    ASSERT_COND(p_QmPortal);
937    ASSERT_COND(count);
938
939    for(i=0;i<count;i++)
940    {
941        p_Fq = (struct qman_fq *)XX_MallocSmart(sizeof(struct qman_fq), 0, 64);
942        if (!p_Fq)
943            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!"));
944        memset(p_Fq, 0, sizeof(struct qman_fq));
945        p_Fq->cb.dqrr     = p_QmPortal->f_DfltFrame;
946        p_Fq->cb.ern      = p_QmPortal->f_RejectedFrame;
947        p_Fq->cb.dc_ern   = cb_ern_dcErn;
948        p_Fq->cb.fqs      = cb_fqs;
949        p_Fq->h_App       = p_QmPortal->h_App;
950        p_Fq->h_QmFqr     = h_QmFqr;
951        p_Fq->fqidOffset  = fqidOffset;
952        p_Fqs[i] = p_Fq;
953        if ((err = qman_create_fq(p_QmPortal,(uint32_t)(fqid + i), 0, p_Fqs[i])) != E_OK)
954            break;
955    }
956
957    if (err != E_OK)
958    {
959        for(i=0;i<count;i++)
960            if (p_Fqs[i])
961            {
962                XX_FreeSmart(p_Fqs[i]);
963                p_Fqs[i] = NULL;
964            }
965        RETURN_ERROR(MINOR, err, ("Failed to create Fqs"));
966    }
967
968    memset(&fq_opts,0,sizeof(fq_opts));
969    fq_opts.fqid = fqid;
970    fq_opts.count = (uint16_t)(count-1);
971    fq_opts.we_mask |= QM_INITFQ_WE_DESTWQ;
972    fq_opts.fqd.dest.channel = channel;
973    fq_opts.fqd.dest.wq = wqid;
974    fq_opts.we_mask |= QM_INITFQ_WE_FQCTRL;
975    fq_opts.fqd.fq_ctrl = (uint16_t)flags;
976
977    if ((flags & QM_FQCTRL_CGE) || (flags & QM_FQCTRL_TDE))
978        ASSERT_COND(p_CgParams);
979
980    if(flags & QM_FQCTRL_CGE)
981    {
982        ASSERT_COND(p_CgParams->h_QmCg);
983
984        /* CG OAC and FQ TD may not be configured at the same time. if both are required,
985           than we configure CG first, and the FQ TD later - see below. */
986        fq_opts.fqd.cgid = QmCgGetCgId(p_CgParams->h_QmCg);
987        fq_opts.we_mask |= QM_INITFQ_WE_CGID;
988        if(p_CgParams->overheadAccountingLength)
989        {
990            fq_opts.we_mask |= QM_INITFQ_WE_OAC;
991            fq_opts.we_mask &= ~QM_INITFQ_WE_TDTHRESH;
992            fq_opts.fqd.td_thresh = (uint16_t)(QM_FQD_TD_THRESH_OAC_EN | p_CgParams->overheadAccountingLength);
993        }
994    }
995    if((flags & QM_FQCTRL_TDE) && (!p_CgParams->overheadAccountingLength))
996    {
997        ASSERT_COND(p_CgParams->fqTailDropThreshold);
998
999        fq_opts.we_mask |= QM_INITFQ_WE_TDTHRESH;
1000
1001            /* express thresh as ta*2^tn */
1002            gap = (int)p_CgParams->fqTailDropThreshold;
1003            for (tmpA=0 ; tmpA<256; tmpA++ )
1004                for (tmpN=0 ; tmpN<32; tmpN++ )
1005                {
1006                    tmp = ABS((int)(p_CgParams->fqTailDropThreshold - tmpA*(1<<tmpN)));
1007                    if (tmp < gap)
1008                    {
1009                       ta = tmpA;
1010                       tn = tmpN;
1011                       gap = tmp;
1012                    }
1013                }
1014            fq_opts.fqd.td.exp = tn;
1015            fq_opts.fqd.td.mant = ta;
1016    }
1017
1018    if (p_ContextA)
1019    {
1020        fq_opts.we_mask |= QM_INITFQ_WE_CONTEXTA;
1021        memcpy((void*)&fq_opts.fqd.context_a, p_ContextA, sizeof(t_QmContextA));
1022    }
1023    /* If this FQ will not be used for tx, we can use contextB field */
1024    if (fq_opts.fqd.dest.channel < e_QM_FQ_CHANNEL_FMAN0_SP0)
1025    {
1026        if (sizeof(p_Fqs[0]) <= sizeof(fq_opts.fqd.context_b))
1027        {
1028            fq_opts.we_mask |= QM_INITFQ_WE_CONTEXTB;
1029            fq_opts.fqd.context_b = (uint32_t)PTR_TO_UINT(p_Fqs[0]);
1030        }
1031        else
1032            RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("64 bit pointer (virtual) not supported yet!!!"));
1033    }
1034    else if (p_ContextB) /* Tx-Queue */
1035    {
1036        fq_opts.we_mask |= QM_INITFQ_WE_CONTEXTB;
1037        memcpy((void*)&fq_opts.fqd.context_b, p_ContextB, sizeof(t_QmContextB));
1038    }
1039
1040    if((flags & QM_FQCTRL_TDE) && (p_CgParams->overheadAccountingLength))
1041        initFqFlag = 0;
1042    else
1043        initFqFlag = (uint32_t)(initParked?0:QMAN_INITFQ_FLAG_SCHED);
1044
1045    if ((err = qman_init_fq(p_QmPortal, p_Fqs[0], initFqFlag, &fq_opts)) != E_OK)
1046    {
1047        for(i=0;i<count;i++)
1048            if (p_Fqs[i])
1049            {
1050                XX_FreeSmart(p_Fqs[i]);
1051                p_Fqs[i] = NULL;
1052            }
1053        RETURN_ERROR(MINOR, err, ("Failed to init Fqs [%d-%d]", fqid, fqid+count-1));
1054    }
1055
1056    /* if both CG OAC and FQ TD are needed, we call qman_init_fq again, this time for the FQ TD only */
1057    if((flags & QM_FQCTRL_TDE) && (p_CgParams->overheadAccountingLength))
1058    {
1059        ASSERT_COND(p_CgParams->fqTailDropThreshold);
1060
1061        fq_opts.we_mask = QM_INITFQ_WE_TDTHRESH;
1062
1063        /* express thresh as ta*2^tn */
1064        gap = (int)p_CgParams->fqTailDropThreshold;
1065        for (tmpA=0 ; tmpA<256; tmpA++ )
1066            for (tmpN=0 ; tmpN<32; tmpN++ )
1067            {
1068                tmp = ABS((int)(p_CgParams->fqTailDropThreshold - tmpA*(1<<tmpN)));
1069                if (tmp < gap)
1070                {
1071                   ta = tmpA;
1072                   tn = tmpN;
1073                   gap = tmp;
1074                }
1075            }
1076        fq_opts.fqd.td.exp = tn;
1077        fq_opts.fqd.td.mant = ta;
1078        if ((err = qman_init_fq(p_QmPortal, p_Fqs[0], (uint32_t)(initParked?0:QMAN_INITFQ_FLAG_SCHED), &fq_opts)) != E_OK)
1079        {
1080            for(i=0;i<count;i++)
1081                if (p_Fqs[i])
1082                {
1083                    XX_FreeSmart(p_Fqs[i]);
1084                    p_Fqs[i] = NULL;
1085                }
1086            RETURN_ERROR(MINOR, err, ("Failed to init Fqs"));
1087        }
1088    }
1089
1090
1091    for(i=1;i<count;i++)
1092    {
1093        memcpy(p_Fqs[i], p_Fqs[0], sizeof(struct qman_fq));
1094        p_Fqs[i]->fqid += i;
1095    }
1096
1097    return err;
1098}
1099
1100
1101static t_Error qm_free_fq(t_QmPortal *p_QmPortal, struct qman_fq *p_Fq)
1102{
1103    uint32_t flags=0;
1104
1105    if (qman_retire_fq(p_QmPortal, p_Fq, &flags, FALSE) != E_OK)
1106        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_retire_fq() failed!"));
1107
1108    if (flags & QMAN_FQ_STATE_CHANGING)
1109        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("fq %d currently in use, will be retired", p_Fq->fqid));
1110
1111    if (flags & QMAN_FQ_STATE_NE)
1112        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_retire_fq() failed;" \
1113                                          "Frame Queue Not Empty, Need to dequeue"));
1114
1115    if (qman_oos_fq(p_QmPortal, p_Fq) != E_OK)
1116        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_oos_fq() failed!"));
1117
1118    qman_destroy_fq(p_Fq,0);
1119
1120    return E_OK;
1121}
1122
1123static void qman_disable_portal(t_QmPortal *p_QmPortal)
1124{
1125    NCSW_PLOCK(p_QmPortal);
1126    if (!(p_QmPortal->disable_count++))
1127        qm_dqrr_set_maxfill(p_QmPortal->p_LowQmPortal, 0);
1128    PUNLOCK(p_QmPortal);
1129}
1130
1131
1132/* quiesce SDQCR/VDQCR, then drain till h/w wraps up anything it
1133 * was doing (5ms is more than enough to ensure it's done). */
1134static void clean_dqrr_mr(t_QmPortal *p_QmPortal)
1135{
1136    struct qm_dqrr_entry    *p_Dq;
1137    struct qm_mr_entry      *p_Msg;
1138    int                     idle = 0;
1139
1140    qm_dqrr_sdqcr_set(p_QmPortal->p_LowQmPortal, 0);
1141    qm_dqrr_vdqcr_set(p_QmPortal->p_LowQmPortal, 0);
1142drain_loop:
1143    qmPortalDqrrPvbPrefetch(p_QmPortal->p_LowQmPortal);
1144    qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
1145    qmPortalMrPvbUpdate(p_QmPortal->p_LowQmPortal);
1146    p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
1147    p_Msg = qm_mr_current(p_QmPortal->p_LowQmPortal);
1148    if (p_Dq) {
1149        qm_dqrr_next(p_QmPortal->p_LowQmPortal);
1150        qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
1151    }
1152    if (p_Msg) {
1153    qm_mr_next(p_QmPortal->p_LowQmPortal);
1154        qmPortalMrCciConsume(p_QmPortal->p_LowQmPortal, 1);
1155    }
1156    if (!p_Dq && !p_Msg) {
1157    if (++idle < 5) {
1158    XX_UDelay(1000);
1159    goto drain_loop;
1160    }
1161    } else {
1162    idle = 0;
1163    goto drain_loop;
1164    }
1165}
1166
1167static t_Error qman_create_portal(t_QmPortal *p_QmPortal,
1168                                   uint32_t flags,
1169                                   uint32_t sdqcrFlags,
1170                                   uint8_t  dqrrSize)
1171{
1172    const struct qm_portal_config   *p_Config = &(p_QmPortal->p_LowQmPortal->config);
1173    int                             ret = 0;
1174    t_Error                         err;
1175    uint32_t                        isdr;
1176
1177    if ((err = qm_eqcr_init(p_QmPortal->p_LowQmPortal, e_QmPortalPVB, e_QmPortalEqcrCCE)) != E_OK)
1178        RETURN_ERROR(MINOR, err, ("Qman EQCR initialization failed\n"));
1179
1180    if (qm_dqrr_init(p_QmPortal->p_LowQmPortal,
1181                     sdqcrFlags ? e_QmPortalDequeuePushMode : e_QmPortalDequeuePullMode,
1182                     e_QmPortalPVB,
1183                     (flags & QMAN_PORTAL_FLAG_DCA) ? e_QmPortalDqrrDCA : e_QmPortalDqrrCCI,
1184                     dqrrSize,
1185                     (flags & QMAN_PORTAL_FLAG_RSTASH) ? 1 : 0,
1186                     (flags & QMAN_PORTAL_FLAG_DSTASH) ? 1 : 0)) {
1187        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("DQRR initialization failed"));
1188        goto fail_dqrr;
1189    }
1190
1191    if (qm_mr_init(p_QmPortal->p_LowQmPortal, e_QmPortalPVB, e_QmPortalMrCCI)) {
1192        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("MR initialization failed"));
1193        goto fail_mr;
1194    }
1195    if (qm_mc_init(p_QmPortal->p_LowQmPortal)) {
1196        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("MC initialization failed"));
1197        goto fail_mc;
1198    }
1199    if (qm_isr_init(p_QmPortal->p_LowQmPortal)) {
1200        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("ISR initialization failed"));
1201        goto fail_isr;
1202    }
1203    /* static interrupt-gating controls */
1204    qm_dqrr_set_ithresh(p_QmPortal->p_LowQmPortal, 12);
1205    qm_mr_set_ithresh(p_QmPortal->p_LowQmPortal, 4);
1206    qm_isr_set_iperiod(p_QmPortal->p_LowQmPortal, 100);
1207    p_QmPortal->options = flags;
1208    isdr = 0xffffffff;
1209    qm_isr_status_clear(p_QmPortal->p_LowQmPortal, 0xffffffff);
1210    qm_isr_enable_write(p_QmPortal->p_LowQmPortal, DEFAULT_portalExceptions);
1211    qm_isr_disable_write(p_QmPortal->p_LowQmPortal, isdr);
1212    if (flags & QMAN_PORTAL_FLAG_IRQ)
1213    {
1214        XX_SetIntr(p_Config->irq, portal_isr, p_QmPortal);
1215        XX_EnableIntr(p_Config->irq);
1216        qm_isr_uninhibit(p_QmPortal->p_LowQmPortal);
1217    } else
1218        /* without IRQ, we can't block */
1219        flags &= ~QMAN_PORTAL_FLAG_WAIT;
1220    /* Need EQCR to be empty before continuing */
1221    isdr ^= QM_PIRQ_EQCI;
1222    qm_isr_disable_write(p_QmPortal->p_LowQmPortal, isdr);
1223    ret = qm_eqcr_get_fill(p_QmPortal->p_LowQmPortal);
1224    if (ret) {
1225        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("EQCR unclean"));
1226        goto fail_eqcr_empty;
1227    }
1228    isdr ^= (QM_PIRQ_DQRI | QM_PIRQ_MRI);
1229    qm_isr_disable_write(p_QmPortal->p_LowQmPortal, isdr);
1230    if (qm_dqrr_current(p_QmPortal->p_LowQmPortal) != NULL)
1231    {
1232        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("DQRR unclean"));
1233goto fail_dqrr_mr_empty;
1234    }
1235    if (qm_mr_current(p_QmPortal->p_LowQmPortal) != NULL)
1236    {
1237        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("MR unclean"));
1238goto fail_dqrr_mr_empty;
1239    }
1240    qm_isr_disable_write(p_QmPortal->p_LowQmPortal, 0);
1241    qm_dqrr_sdqcr_set(p_QmPortal->p_LowQmPortal, sdqcrFlags);
1242    return E_OK;
1243fail_dqrr_mr_empty:
1244fail_eqcr_empty:
1245    qm_isr_finish(p_QmPortal->p_LowQmPortal);
1246fail_isr:
1247    qm_mc_finish(p_QmPortal->p_LowQmPortal);
1248fail_mc:
1249    qm_mr_finish(p_QmPortal->p_LowQmPortal);
1250fail_mr:
1251    qm_dqrr_finish(p_QmPortal->p_LowQmPortal);
1252fail_dqrr:
1253    qm_eqcr_finish(p_QmPortal->p_LowQmPortal);
1254    return ERROR_CODE(E_INVALID_STATE);
1255}
1256
1257static void qman_destroy_portal(t_QmPortal *p_QmPortal)
1258{
1259    /* NB we do this to "quiesce" EQCR. If we add enqueue-completions or
1260     * something related to QM_PIRQ_EQCI, this may need fixing. */
1261    qmPortalEqcrCceUpdate(p_QmPortal->p_LowQmPortal);
1262    if (p_QmPortal->options & QMAN_PORTAL_FLAG_IRQ)
1263    {
1264        XX_DisableIntr(p_QmPortal->p_LowQmPortal->config.irq);
1265        XX_FreeIntr(p_QmPortal->p_LowQmPortal->config.irq);
1266    }
1267    qm_isr_finish(p_QmPortal->p_LowQmPortal);
1268    qm_mc_finish(p_QmPortal->p_LowQmPortal);
1269    qm_mr_finish(p_QmPortal->p_LowQmPortal);
1270    qm_dqrr_finish(p_QmPortal->p_LowQmPortal);
1271    qm_eqcr_finish(p_QmPortal->p_LowQmPortal);
1272}
1273
1274static inline struct qm_eqcr_entry *try_eq_start(t_QmPortal *p_QmPortal)
1275{
1276    struct qm_eqcr_entry    *p_Eq;
1277    uint8_t                 avail;
1278
1279    avail = qm_eqcr_get_avail(p_QmPortal->p_LowQmPortal);
1280    if (avail == EQCR_THRESH)
1281        qmPortalEqcrCcePrefetch(p_QmPortal->p_LowQmPortal);
1282    else if (avail < EQCR_THRESH)
1283            qmPortalEqcrCceUpdate(p_QmPortal->p_LowQmPortal);
1284    p_Eq = qm_eqcr_start(p_QmPortal->p_LowQmPortal);
1285
1286    return p_Eq;
1287}
1288
1289
1290static t_Error qman_orp_update(t_QmPortal   *p_QmPortal,
1291                               uint32_t     orpId,
1292                               uint16_t     orpSeqnum,
1293                               uint32_t     flags)
1294{
1295    struct qm_eqcr_entry *p_Eq;
1296
1297    NCSW_PLOCK(p_QmPortal);
1298    p_Eq = try_eq_start(p_QmPortal);
1299    if (!p_Eq)
1300    {
1301        PUNLOCK(p_QmPortal);
1302        return ERROR_CODE(E_BUSY);
1303    }
1304
1305    if (flags & QMAN_ENQUEUE_FLAG_NESN)
1306        orpSeqnum |= QM_EQCR_SEQNUM_NESN;
1307    else
1308        /* No need to check 4 QMAN_ENQUEUE_FLAG_HOLE */
1309        orpSeqnum &= ~QM_EQCR_SEQNUM_NESN;
1310    p_Eq->seqnum  = orpSeqnum;
1311    p_Eq->orp     = orpId;
1312qmPortalEqcrPvbCommit(p_QmPortal->p_LowQmPortal, (uint8_t)QM_EQCR_VERB_ORP);
1313
1314    PUNLOCK(p_QmPortal);
1315    return E_OK;
1316}
1317
1318static __inline__ t_Error CheckStashParams(t_QmFqrParams *p_QmFqrParams)
1319{
1320    ASSERT_COND(p_QmFqrParams);
1321
1322    if (p_QmFqrParams->stashingParams.frameAnnotationSize > QM_CONTEXTA_MAX_STASH_SIZE)
1323        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Frame Annotation Size Exceeded Max Stash Size(%d)", QM_CONTEXTA_MAX_STASH_SIZE));
1324    if (p_QmFqrParams->stashingParams.frameDataSize > QM_CONTEXTA_MAX_STASH_SIZE)
1325        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Frame Data Size Exceeded Max Stash Size(%d)", QM_CONTEXTA_MAX_STASH_SIZE));
1326    if (p_QmFqrParams->stashingParams.fqContextSize > QM_CONTEXTA_MAX_STASH_SIZE)
1327        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Frame Context Size Exceeded Max Stash Size(%d)", QM_CONTEXTA_MAX_STASH_SIZE));
1328    if (p_QmFqrParams->stashingParams.fqContextSize)
1329    {
1330        if (!p_QmFqrParams->stashingParams.fqContextAddr)
1331            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FQ Context Address Must be givven"));
1332        if (!IS_ALIGNED(p_QmFqrParams->stashingParams.fqContextAddr, CACHELINE_SIZE))
1333            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FQ Context Address Must be aligned to %d", CACHELINE_SIZE));
1334        if (p_QmFqrParams->stashingParams.fqContextAddr & 0xffffff0000000000LL)
1335            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FQ Context Address May be up to 40 bit"));
1336    }
1337
1338    return E_OK;
1339}
1340
1341static t_Error QmPortalRegisterCg(t_Handle h_QmPortal, t_Handle h_QmCg, uint8_t  cgId)
1342{
1343    t_QmPortal  *p_QmPortal = (t_QmPortal *)h_QmPortal;
1344
1345    /* cgrs[0] is the mask of registered CG's*/
1346    if(p_QmPortal->cgrs[0].q.__state[cgId/32] & (0x80000000 >> (cgId % 32)))
1347        RETURN_ERROR(MINOR, E_BUSY, ("CG already used"));
1348
1349    p_QmPortal->cgrs[0].q.__state[cgId/32] |=  0x80000000 >> (cgId % 32);
1350    p_QmPortal->cgsHandles[cgId] = h_QmCg;
1351
1352    return E_OK;
1353}
1354
1355static t_Error QmPortalUnregisterCg(t_Handle h_QmPortal, uint8_t  cgId)
1356{
1357    t_QmPortal  *p_QmPortal = (t_QmPortal *)h_QmPortal;
1358
1359    /* cgrs[0] is the mask of registered CG's*/
1360    if(!(p_QmPortal->cgrs[0].q.__state[cgId/32] & (0x80000000 >> (cgId % 32))))
1361        RETURN_ERROR(MINOR, E_BUSY, ("CG is not in use"));
1362
1363    p_QmPortal->cgrs[0].q.__state[cgId/32] &=  ~0x80000000 >> (cgId % 32);
1364    p_QmPortal->cgsHandles[cgId] = NULL;
1365
1366    return E_OK;
1367}
1368
1369static e_DpaaSwPortal QmPortalGetSwPortalId(t_Handle h_QmPortal)
1370{
1371    t_QmPortal *p_QmPortal = (t_QmPortal *)h_QmPortal;
1372
1373    return (e_DpaaSwPortal)p_QmPortal->p_LowQmPortal->config.cpu;
1374}
1375
1376static t_Error CalcWredCurve(t_QmCgWredCurve *p_WredCurve, uint32_t  *p_CurveWord)
1377{
1378    uint32_t    maxP, roundDown, roundUp, tmpA, tmpN;
1379    uint32_t    ma=0, mn=0, slope, sa=0, sn=0, pn;
1380    int         pres = 1000;
1381    int         gap, tmp;
1382
1383/*  TODO - change maxTh to uint64_t?
1384   if(p_WredCurve->maxTh > (1<<39))
1385        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("maxTh is not in range"));*/
1386
1387    /* express maxTh as ma*2^mn */
1388     gap = (int)p_WredCurve->maxTh;
1389     for (tmpA=0 ; tmpA<256; tmpA++ )
1390         for (tmpN=0 ; tmpN<32; tmpN++ )
1391         {
1392             tmp = ABS((int)(p_WredCurve->maxTh - tmpA*(1<<tmpN)));
1393             if (tmp < gap)
1394             {
1395                ma = tmpA;
1396                mn = tmpN;
1397                gap = tmp;
1398             }
1399         }
1400     ASSERT_COND(ma <256);
1401     ASSERT_COND(mn <32);
1402     p_WredCurve->maxTh = ma*(1<<mn);
1403
1404     if(p_WredCurve->maxTh <= p_WredCurve->minTh)
1405        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("maxTh must be larger than minTh"));
1406     if(p_WredCurve->probabilityDenominator > 64)
1407        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("probabilityDenominator mustn't be 1-64"));
1408
1409    /* first we translate from Cisco probabilityDenominator
1410       to 256 fixed denominator, result must be divisible by 4. */
1411    /* we multiply by a fixed value to get better accuracy (without
1412       using floating point) */
1413    maxP = (uint32_t)(256*1000/p_WredCurve->probabilityDenominator);
1414    if (maxP % 4*pres)
1415    {
1416        roundDown  = maxP + (maxP % (4*pres));
1417        roundUp = roundDown + 4*pres;
1418        if((roundUp - maxP) > (maxP - roundDown))
1419            maxP = roundDown;
1420        else
1421            maxP = roundUp;
1422    }
1423    maxP = maxP/pres;
1424    ASSERT_COND(maxP <= 256);
1425    pn = (uint8_t)(maxP/4 - 1);
1426
1427    if(maxP >= (p_WredCurve->maxTh - p_WredCurve->minTh))
1428        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Due to probabilityDenominator selected, maxTh-minTh must be larger than %d", maxP));
1429
1430    pres = 1000000;
1431    slope = maxP*pres/(p_WredCurve->maxTh - p_WredCurve->minTh);
1432    /* express slope as sa/2^sn */
1433    gap = (int)slope;
1434    for (tmpA=(uint32_t)(64*pres) ; tmpA<128*pres; tmpA += pres )
1435        for (tmpN=7 ; tmpN<64; tmpN++ )
1436        {
1437            tmp = ABS((int)(slope - tmpA/(1<<tmpN)));
1438            if (tmp < gap)
1439            {
1440               sa = tmpA;
1441               sn = tmpN;
1442               gap = tmp;
1443            }
1444        }
1445    sa = sa/pres;
1446    ASSERT_COND(sa<128 && sa>=64);
1447    sn = sn;
1448    ASSERT_COND(sn<64 && sn>=7);
1449
1450    *p_CurveWord = ((ma << 24) |
1451                    (mn << 19) |
1452                    (sa << 12) |
1453                    (sn << 6) |
1454                    pn);
1455
1456    return E_OK;
1457}
1458
1459static t_Error QmPortalPullFrame(t_Handle h_QmPortal, uint32_t pdqcr, t_DpaaFD *p_Frame)
1460{
1461    t_QmPortal              *p_QmPortal = (t_QmPortal *)h_QmPortal;
1462    struct qm_dqrr_entry    *p_Dq;
1463    struct qman_fq          *p_Fq;
1464    int                     prefetch;
1465    uint32_t                *p_Dst, *p_Src;
1466
1467    ASSERT_COND(p_QmPortal);
1468    ASSERT_COND(p_Frame);
1469    SANITY_CHECK_RETURN_ERROR(p_QmPortal->pullMode, E_INVALID_STATE);
1470
1471    NCSW_PLOCK(p_QmPortal);
1472
1473    qm_dqrr_pdqcr_set(p_QmPortal->p_LowQmPortal, pdqcr);
1474    CORE_MemoryBarrier();
1475    while (qm_dqrr_pdqcr_get(p_QmPortal->p_LowQmPortal)) ;
1476
1477    prefetch = !(p_QmPortal->options & QMAN_PORTAL_FLAG_RSTASH);
1478    while(TRUE)
1479    {
1480        if (prefetch)
1481            qmPortalDqrrPvbPrefetch(p_QmPortal->p_LowQmPortal);
1482        qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
1483        p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
1484        if (!p_Dq)
1485            continue;
1486        p_Fq = (void *)p_Dq->contextB;
1487        ASSERT_COND(p_Dq->fqid);
1488        p_Dst = (uint32_t *)p_Frame;
1489        p_Src = (uint32_t *)&p_Dq->fd;
1490        p_Dst[0] = p_Src[0];
1491        p_Dst[1] = p_Src[1];
1492        p_Dst[2] = p_Src[2];
1493        p_Dst[3] = p_Src[3];
1494        if (p_QmPortal->options & QMAN_PORTAL_FLAG_DCA)
1495        {
1496            qmPortalDqrrDcaConsume1ptr(p_QmPortal->p_LowQmPortal,
1497                                       p_Dq,
1498                                       FALSE);
1499            qm_dqrr_next(p_QmPortal->p_LowQmPortal);
1500        }
1501        else
1502        {
1503            qm_dqrr_next(p_QmPortal->p_LowQmPortal);
1504            qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
1505        }
1506        break;
1507    }
1508
1509    PUNLOCK(p_QmPortal);
1510
1511    if (!(p_Dq->stat & QM_DQRR_STAT_FD_VALID))
1512        return ERROR_CODE(E_EMPTY);
1513
1514    return E_OK;
1515}
1516
1517
1518/****************************************/
1519/*       API Init unit functions        */
1520/****************************************/
1521t_Handle QM_PORTAL_Config(t_QmPortalParam *p_QmPortalParam)
1522{
1523    t_QmPortal          *p_QmPortal;
1524    uint32_t            i;
1525
1526    SANITY_CHECK_RETURN_VALUE(p_QmPortalParam, E_INVALID_HANDLE, NULL);
1527    SANITY_CHECK_RETURN_VALUE(p_QmPortalParam->swPortalId < DPAA_MAX_NUM_OF_SW_PORTALS, E_INVALID_VALUE, 0);
1528
1529    p_QmPortal = (t_QmPortal *)XX_Malloc(sizeof(t_QmPortal));
1530    if (!p_QmPortal)
1531    {
1532        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Qm Portal obj!!!"));
1533        return NULL;
1534    }
1535    memset(p_QmPortal, 0, sizeof(t_QmPortal));
1536
1537    p_QmPortal->p_LowQmPortal = (struct qm_portal *)XX_Malloc(sizeof(struct qm_portal));
1538    if (!p_QmPortal->p_LowQmPortal)
1539    {
1540        XX_Free(p_QmPortal);
1541        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Low qm p_QmPortal obj!!!"));
1542        return NULL;
1543    }
1544    memset(p_QmPortal->p_LowQmPortal, 0, sizeof(struct qm_portal));
1545
1546    p_QmPortal->p_QmPortalDriverParams = (t_QmPortalDriverParams *)XX_Malloc(sizeof(t_QmPortalDriverParams));
1547    if (!p_QmPortal->p_QmPortalDriverParams)
1548    {
1549        XX_Free(p_QmPortal->p_LowQmPortal);
1550        XX_Free(p_QmPortal);
1551        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Qm Portal driver parameters"));
1552        return NULL;
1553    }
1554    memset(p_QmPortal->p_QmPortalDriverParams, 0, sizeof(t_QmPortalDriverParams));
1555
1556    p_QmPortal->p_LowQmPortal->addr.addr_ce = UINT_TO_PTR(p_QmPortalParam->ceBaseAddress);
1557    p_QmPortal->p_LowQmPortal->addr.addr_ci = UINT_TO_PTR(p_QmPortalParam->ciBaseAddress);
1558    p_QmPortal->p_LowQmPortal->config.irq = p_QmPortalParam->irq;
1559    p_QmPortal->p_LowQmPortal->config.bound = 0;
1560    p_QmPortal->p_LowQmPortal->config.cpu = (int)p_QmPortalParam->swPortalId;
1561    p_QmPortal->p_LowQmPortal->config.channel = (e_QmFQChannel)(e_QM_FQ_CHANNEL_SWPORTAL0 + p_QmPortalParam->swPortalId);
1562    p_QmPortal->p_LowQmPortal->bind_lock = XX_InitSpinlock();
1563
1564    p_QmPortal->h_Qm                = p_QmPortalParam->h_Qm;
1565    p_QmPortal->f_DfltFrame         = p_QmPortalParam->f_DfltFrame;
1566    p_QmPortal->f_RejectedFrame     = p_QmPortalParam->f_RejectedFrame;
1567    p_QmPortal->h_App               = p_QmPortalParam->h_App;
1568
1569    p_QmPortal->p_QmPortalDriverParams->fdLiodnOffset           = p_QmPortalParam->fdLiodnOffset;
1570    p_QmPortal->p_QmPortalDriverParams->dequeueDcaMode          = DEFAULT_dequeueDcaMode;
1571    p_QmPortal->p_QmPortalDriverParams->dequeueUpToThreeFrames  = DEFAULT_dequeueUpToThreeFrames;
1572    p_QmPortal->p_QmPortalDriverParams->commandType             = DEFAULT_dequeueCommandType;
1573    p_QmPortal->p_QmPortalDriverParams->userToken               = DEFAULT_dequeueUserToken;
1574    p_QmPortal->p_QmPortalDriverParams->specifiedWq             = DEFAULT_dequeueSpecifiedWq;
1575    p_QmPortal->p_QmPortalDriverParams->dedicatedChannel        = DEFAULT_dequeueDedicatedChannel;
1576    p_QmPortal->p_QmPortalDriverParams->dedicatedChannelHasPrecedenceOverPoolChannels =
1577        DEFAULT_dequeueDedicatedChannelHasPrecedenceOverPoolChannels;
1578    p_QmPortal->p_QmPortalDriverParams->poolChannelId           = DEFAULT_dequeuePoolChannelId;
1579    p_QmPortal->p_QmPortalDriverParams->wqId                    = DEFAULT_dequeueWqId;
1580    for (i=0;i<QM_MAX_NUM_OF_POOL_CHANNELS;i++)
1581        p_QmPortal->p_QmPortalDriverParams->poolChannels[i] = FALSE;
1582    p_QmPortal->p_QmPortalDriverParams->dqrrSize                = DEFAULT_dqrrSize;
1583    p_QmPortal->p_QmPortalDriverParams->pullMode                = DEFAULT_pullMode;
1584
1585    return p_QmPortal;
1586}
1587
1588t_Error QM_PORTAL_Init(t_Handle h_QmPortal)
1589{
1590    t_QmPortal                          *p_QmPortal = (t_QmPortal *)h_QmPortal;
1591    uint32_t                            i, flags=0, sdqcrFlags=0;
1592    t_Error                             err;
1593    t_QmInterModulePortalInitParams     qmParams;
1594
1595    SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
1596    SANITY_CHECK_RETURN_ERROR(p_QmPortal->p_QmPortalDriverParams, E_INVALID_HANDLE);
1597
1598    memset(&qmParams, 0, sizeof(qmParams));
1599    qmParams.portalId       = (uint8_t)p_QmPortal->p_LowQmPortal->config.cpu;
1600    qmParams.liodn          = p_QmPortal->p_QmPortalDriverParams->fdLiodnOffset;
1601    qmParams.dqrrLiodn      = p_QmPortal->p_QmPortalDriverParams->dqrrLiodn;
1602    qmParams.fdFqLiodn      = p_QmPortal->p_QmPortalDriverParams->fdFqLiodn;
1603    qmParams.stashDestQueue = p_QmPortal->p_QmPortalDriverParams->stashDestQueue;
1604    if ((err = QmGetSetPortalParams(p_QmPortal->h_Qm, &qmParams)) != E_OK)
1605        RETURN_ERROR(MAJOR, err, NO_MSG);
1606
1607    flags = (uint32_t)(((p_QmPortal->p_LowQmPortal->config.irq == NO_IRQ) ?
1608            0 :
1609            (QMAN_PORTAL_FLAG_IRQ |
1610             QMAN_PORTAL_FLAG_IRQ_FAST |
1611             QMAN_PORTAL_FLAG_IRQ_SLOW)));
1612    flags |= ((p_QmPortal->p_QmPortalDriverParams->dequeueDcaMode) ? QMAN_PORTAL_FLAG_DCA : 0);
1613    flags |= (p_QmPortal->p_QmPortalDriverParams->dqrr)?QMAN_PORTAL_FLAG_RSTASH:0;
1614    flags |= (p_QmPortal->p_QmPortalDriverParams->fdFq)?QMAN_PORTAL_FLAG_DSTASH:0;
1615
1616    p_QmPortal->pullMode = p_QmPortal->p_QmPortalDriverParams->pullMode;
1617    if (!p_QmPortal->pullMode)
1618    {
1619        sdqcrFlags |= (p_QmPortal->p_QmPortalDriverParams->dequeueUpToThreeFrames) ? QM_SDQCR_COUNT_UPTO3 : QM_SDQCR_COUNT_EXACT1;
1620        sdqcrFlags |= QM_SDQCR_TOKEN_SET(p_QmPortal->p_QmPortalDriverParams->userToken);
1621        sdqcrFlags |= QM_SDQCR_TYPE_SET(p_QmPortal->p_QmPortalDriverParams->commandType);
1622        if (!p_QmPortal->p_QmPortalDriverParams->specifiedWq)
1623        {
1624            /* sdqcrFlags |= QM_SDQCR_SOURCE_CHANNELS;*/ /* removed as the macro is '0' */
1625            sdqcrFlags |= (p_QmPortal->p_QmPortalDriverParams->dedicatedChannelHasPrecedenceOverPoolChannels) ? QM_SDQCR_DEDICATED_PRECEDENCE : 0;
1626            sdqcrFlags |= (p_QmPortal->p_QmPortalDriverParams->dedicatedChannel) ? QM_SDQCR_CHANNELS_DEDICATED : 0;
1627            for (i=0;i<QM_MAX_NUM_OF_POOL_CHANNELS;i++)
1628                sdqcrFlags |= ((p_QmPortal->p_QmPortalDriverParams->poolChannels[i]) ?
1629                     QM_SDQCR_CHANNELS_POOL(i+1) : 0);
1630        }
1631        else
1632        {
1633            sdqcrFlags |= QM_SDQCR_SOURCE_SPECIFICWQ;
1634            sdqcrFlags |= (p_QmPortal->p_QmPortalDriverParams->dedicatedChannel) ?
1635                            QM_SDQCR_SPECIFICWQ_DEDICATED : QM_SDQCR_SPECIFICWQ_POOL(p_QmPortal->p_QmPortalDriverParams->poolChannelId);
1636            sdqcrFlags |= QM_SDQCR_SPECIFICWQ_WQ(p_QmPortal->p_QmPortalDriverParams->wqId);
1637        }
1638    }
1639    if ((flags & QMAN_PORTAL_FLAG_RSTASH) && (flags & QMAN_PORTAL_FLAG_DCA))
1640        p_QmPortal->f_LoopDequeueRingCB = LoopDequeueRingDcaOptimized;
1641    else if ((flags & QMAN_PORTAL_FLAG_RSTASH) && !(flags & QMAN_PORTAL_FLAG_DCA))
1642        p_QmPortal->f_LoopDequeueRingCB = LoopDequeueRingOptimized;
1643    else
1644        p_QmPortal->f_LoopDequeueRingCB = LoopDequeueRing;
1645
1646    if ((!p_QmPortal->f_RejectedFrame) || (!p_QmPortal->f_DfltFrame))
1647        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_RejectedFrame or f_DfltFrame callback not provided"));
1648
1649    p_QmPortal->p_NullCB = (struct qman_fq_cb *)XX_Malloc(sizeof(struct qman_fq_cb));
1650    if (!p_QmPortal->p_NullCB)
1651        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FQ Null CB obj!!!"));
1652    memset(p_QmPortal->p_NullCB, 0, sizeof(struct qman_fq_cb));
1653
1654    p_QmPortal->p_NullCB->dqrr      = p_QmPortal->f_DfltFrame;
1655    p_QmPortal->p_NullCB->ern       = p_QmPortal->f_RejectedFrame;
1656    p_QmPortal->p_NullCB->dc_ern    = p_QmPortal->p_NullCB->fqs = null_cb_mr;
1657
1658    if (qman_create_portal(p_QmPortal, flags, sdqcrFlags, p_QmPortal->p_QmPortalDriverParams->dqrrSize) != E_OK)
1659    {
1660        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("create portal failed"));
1661    }
1662
1663    QmSetPortalHandle(p_QmPortal->h_Qm, (t_Handle)p_QmPortal, (e_DpaaSwPortal)p_QmPortal->p_LowQmPortal->config.cpu);
1664    XX_Free(p_QmPortal->p_QmPortalDriverParams);
1665    p_QmPortal->p_QmPortalDriverParams = NULL;
1666
1667    DBG(TRACE, ("Qman-Portal %d @ %p:%p",
1668                p_QmPortal->p_LowQmPortal->config.cpu,
1669                p_QmPortal->p_LowQmPortal->addr.addr_ce,
1670                p_QmPortal->p_LowQmPortal->addr.addr_ci
1671                ));
1672
1673    DBG(TRACE, ("Qman-Portal %d phys @ 0x%016llx:0x%016llx",
1674                p_QmPortal->p_LowQmPortal->config.cpu,
1675                (uint64_t)XX_VirtToPhys(p_QmPortal->p_LowQmPortal->addr.addr_ce),
1676                (uint64_t)XX_VirtToPhys(p_QmPortal->p_LowQmPortal->addr.addr_ci)
1677                ));
1678
1679    return E_OK;
1680}
1681
1682t_Error QM_PORTAL_Free(t_Handle h_QmPortal)
1683{
1684    t_QmPortal  *p_QmPortal = (t_QmPortal *)h_QmPortal;
1685
1686    if (!p_QmPortal)
1687       return ERROR_CODE(E_INVALID_HANDLE);
1688
1689    ASSERT_COND(p_QmPortal->p_LowQmPortal);
1690    QmSetPortalHandle(p_QmPortal->h_Qm, NULL, (e_DpaaSwPortal)p_QmPortal->p_LowQmPortal->config.cpu);
1691    qman_destroy_portal(p_QmPortal);
1692    if (p_QmPortal->p_NullCB)
1693        XX_Free(p_QmPortal->p_NullCB);
1694
1695    if (p_QmPortal->p_LowQmPortal->bind_lock)
1696        XX_FreeSpinlock(p_QmPortal->p_LowQmPortal->bind_lock);
1697    if(p_QmPortal->p_QmPortalDriverParams)
1698        XX_Free(p_QmPortal->p_QmPortalDriverParams);
1699    XX_Free(p_QmPortal->p_LowQmPortal);
1700    XX_Free(p_QmPortal);
1701
1702    return E_OK;
1703}
1704
1705t_Error QM_PORTAL_ConfigDcaMode(t_Handle h_QmPortal, bool enable)
1706{
1707    t_QmPortal  *p_QmPortal = (t_QmPortal *)h_QmPortal;
1708
1709    SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
1710    SANITY_CHECK_RETURN_ERROR(p_QmPortal->p_QmPortalDriverParams, E_INVALID_HANDLE);
1711
1712    p_QmPortal->p_QmPortalDriverParams->dequeueDcaMode = enable;
1713
1714    return E_OK;
1715}
1716
1717t_Error QM_PORTAL_ConfigStash(t_Handle h_QmPortal, t_QmPortalStashParam *p_StashParams)
1718{
1719    t_QmPortal  *p_QmPortal = (t_QmPortal *)h_QmPortal;
1720
1721    SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
1722    SANITY_CHECK_RETURN_ERROR(p_QmPortal->p_QmPortalDriverParams, E_NULL_POINTER);
1723    SANITY_CHECK_RETURN_ERROR(p_StashParams, E_NULL_POINTER);
1724
1725    p_QmPortal->p_QmPortalDriverParams->stashDestQueue  = p_StashParams->stashDestQueue;
1726    p_QmPortal->p_QmPortalDriverParams->dqrrLiodn       = p_StashParams->dqrrLiodn;
1727    p_QmPortal->p_QmPortalDriverParams->fdFqLiodn       = p_StashParams->fdFqLiodn;
1728    p_QmPortal->p_QmPortalDriverParams->eqcr            = p_StashParams->eqcr;
1729    p_QmPortal->p_QmPortalDriverParams->eqcrHighPri     = p_StashParams->eqcrHighPri;
1730    p_QmPortal->p_QmPortalDriverParams->dqrr            = p_StashParams->dqrr;
1731    p_QmPortal->p_QmPortalDriverParams->dqrrHighPri     = p_StashParams->dqrrHighPri;
1732    p_QmPortal->p_QmPortalDriverParams->fdFq            = p_StashParams->fdFq;
1733    p_QmPortal->p_QmPortalDriverParams->fdFqHighPri     = p_StashParams->fdFqHighPri;
1734    p_QmPortal->p_QmPortalDriverParams->fdFqDrop        = p_StashParams->fdFqDrop;
1735
1736    return E_OK;
1737}
1738
1739
1740t_Error QM_PORTAL_ConfigPullMode(t_Handle h_QmPortal, bool pullMode)
1741{
1742    t_QmPortal  *p_QmPortal = (t_QmPortal *)h_QmPortal;
1743
1744    SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
1745    SANITY_CHECK_RETURN_ERROR(p_QmPortal->p_QmPortalDriverParams, E_NULL_POINTER);
1746
1747    p_QmPortal->p_QmPortalDriverParams->pullMode  = pullMode;
1748
1749    return E_OK;
1750}
1751
1752t_Error QM_PORTAL_AddPoolChannel(t_Handle h_QmPortal, uint8_t poolChannelId)
1753{
1754    t_QmPortal  *p_QmPortal = (t_QmPortal *)h_QmPortal;
1755    uint32_t    sdqcrFlags;
1756
1757    SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
1758    SANITY_CHECK_RETURN_ERROR((poolChannelId < QM_MAX_NUM_OF_POOL_CHANNELS), E_INVALID_VALUE);
1759
1760    sdqcrFlags = qm_dqrr_sdqcr_get(p_QmPortal->p_LowQmPortal);
1761    sdqcrFlags |= QM_SDQCR_CHANNELS_POOL(poolChannelId+1);
1762    qm_dqrr_sdqcr_set(p_QmPortal->p_LowQmPortal, sdqcrFlags);
1763
1764    return E_OK;
1765}
1766
1767t_Error QM_PORTAL_Poll(t_Handle h_QmPortal, e_QmPortalPollSource source)
1768{
1769    t_QmPortal  *p_QmPortal = (t_QmPortal *)h_QmPortal;
1770
1771    SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
1772
1773    NCSW_PLOCK(p_QmPortal);
1774
1775    if ((source == e_QM_PORTAL_POLL_SOURCE_CONTROL_FRAMES) ||
1776        (source == e_QM_PORTAL_POLL_SOURCE_BOTH))
1777    {
1778        uint32_t is = qm_isr_status_read(p_QmPortal->p_LowQmPortal);
1779        uint32_t active = LoopMessageRing(p_QmPortal, is);
1780        if (active)
1781            qm_isr_status_clear(p_QmPortal->p_LowQmPortal, active);
1782    }
1783    if ((source == e_QM_PORTAL_POLL_SOURCE_DATA_FRAMES) ||
1784        (source == e_QM_PORTAL_POLL_SOURCE_BOTH))
1785        p_QmPortal->f_LoopDequeueRingCB((t_Handle)p_QmPortal);
1786
1787    PUNLOCK(p_QmPortal);
1788
1789    return E_OK;
1790}
1791
1792t_Error QM_PORTAL_PollFrame(t_Handle h_QmPortal, t_QmPortalFrameInfo *p_frameInfo)
1793{
1794    t_QmPortal              *p_QmPortal     = (t_QmPortal *)h_QmPortal;
1795    struct qm_dqrr_entry    *p_Dq;
1796    struct qman_fq          *p_Fq;
1797    int                     prefetch;
1798
1799    SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);
1800    SANITY_CHECK_RETURN_ERROR(p_frameInfo, E_NULL_POINTER);
1801
1802    NCSW_PLOCK(p_QmPortal);
1803
1804    prefetch = !(p_QmPortal->options & QMAN_PORTAL_FLAG_RSTASH);
1805    if (prefetch)
1806        qmPortalDqrrPvbPrefetch(p_QmPortal->p_LowQmPortal);
1807    qmPortalDqrrPvbUpdate(p_QmPortal->p_LowQmPortal);
1808    p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal);
1809    if (!p_Dq)
1810    {
1811        PUNLOCK(p_QmPortal);
1812        return ERROR_CODE(E_EMPTY);
1813    }
1814    p_Fq = (void *)p_Dq->contextB;
1815    ASSERT_COND(p_Dq->fqid);
1816    if (p_Fq)
1817    {
1818        p_frameInfo->h_App = p_Fq->h_App;
1819        p_frameInfo->h_QmFqr = p_Fq->h_QmFqr;
1820        p_frameInfo->fqidOffset = p_Fq->fqidOffset;
1821        memcpy((void*)&p_frameInfo->frame, (void*)&p_Dq->fd, sizeof(t_DpaaFD));
1822    }
1823    else
1824    {
1825        p_frameInfo->h_App = p_QmPortal->h_App;
1826        p_frameInfo->h_QmFqr = NULL;
1827        p_frameInfo->fqidOffset = p_Dq->fqid;
1828        memcpy((void*)&p_frameInfo->frame, (void*)&p_Dq->fd, sizeof(t_DpaaFD));
1829    }
1830    if (p_QmPortal->options & QMAN_PORTAL_FLAG_DCA) {
1831        qmPortalDqrrDcaConsume1ptr(p_QmPortal->p_LowQmPortal,
1832                                   p_Dq,
1833                                   FALSE);
1834        qm_dqrr_next(p_QmPortal->p_LowQmPortal);
1835    } else {
1836        qm_dqrr_next(p_QmPortal->p_LowQmPortal);
1837        qmPortalDqrrCciConsume(p_QmPortal->p_LowQmPortal, 1);
1838    }
1839
1840    PUNLOCK(p_QmPortal);
1841
1842    return E_OK;
1843}
1844
1845
1846t_Handle QM_FQR_Create(t_QmFqrParams *p_QmFqrParams)
1847{
1848    t_QmFqr             *p_QmFqr;
1849    uint32_t            i, flags = 0;
1850    u_QmFqdContextA     cnxtA;
1851
1852    SANITY_CHECK_RETURN_VALUE(p_QmFqrParams, E_INVALID_HANDLE, NULL);
1853    SANITY_CHECK_RETURN_VALUE(p_QmFqrParams->h_Qm, E_INVALID_HANDLE, NULL);
1854
1855    if (p_QmFqrParams->shadowMode &&
1856        (!p_QmFqrParams->useForce || p_QmFqrParams->numOfFqids != 1))
1857    {
1858        REPORT_ERROR(MAJOR, E_CONFLICT, ("shadowMode must be use with useForce and numOfFqids==1!!!"));
1859        return NULL;
1860    }
1861
1862    p_QmFqr = (t_QmFqr *)XX_MallocSmart(sizeof(t_QmFqr), 0, 64);
1863    if (!p_QmFqr)
1864    {
1865        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("QM FQR obj!!!"));
1866        return NULL;
1867    }
1868    memset(p_QmFqr, 0, sizeof(t_QmFqr));
1869
1870    p_QmFqr->h_Qm       = p_QmFqrParams->h_Qm;
1871    p_QmFqr->h_QmPortal = p_QmFqrParams->h_QmPortal;
1872    p_QmFqr->shadowMode = p_QmFqrParams->shadowMode;
1873    p_QmFqr->numOfFqids = (p_QmFqrParams->useForce && !p_QmFqrParams->numOfFqids) ?
1874                              1 : p_QmFqrParams->numOfFqids;
1875
1876    if (!p_QmFqr->h_QmPortal)
1877    {
1878        p_QmFqr->h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
1879        SANITY_CHECK_RETURN_VALUE(p_QmFqr->h_QmPortal, E_INVALID_HANDLE, NULL);
1880    }
1881
1882    p_QmFqr->p_Fqs = (struct qman_fq **)XX_Malloc(sizeof(struct qman_fq *) * p_QmFqr->numOfFqids);
1883    if (!p_QmFqr->p_Fqs)
1884    {
1885        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("QM FQs obj!!!"));
1886        QM_FQR_Free(p_QmFqr);
1887        return NULL;
1888    }
1889    memset(p_QmFqr->p_Fqs, 0, sizeof(struct qman_fq *) * p_QmFqr->numOfFqids);
1890
1891    if (p_QmFqr->shadowMode)
1892    {
1893        struct qman_fq          *p_Fq = NULL;
1894
1895        p_QmFqr->fqidBase = p_QmFqrParams->qs.frcQ.fqid;
1896        p_Fq = (struct qman_fq *)XX_MallocSmart(sizeof(struct qman_fq), 0, 64);
1897        if (!p_Fq)
1898        {
1899            REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!"));
1900            QM_FQR_Free(p_QmFqr);
1901            return NULL;
1902        }
1903        memset(p_Fq, 0, sizeof(struct qman_fq));
1904        p_Fq->cb.dqrr     = ((t_QmPortal*)p_QmFqr->h_QmPortal)->f_DfltFrame;
1905        p_Fq->cb.ern      = ((t_QmPortal*)p_QmFqr->h_QmPortal)->f_RejectedFrame;
1906        p_Fq->cb.dc_ern   = cb_ern_dcErn;
1907        p_Fq->cb.fqs      = cb_fqs;
1908        p_Fq->h_App       = ((t_QmPortal*)p_QmFqr->h_QmPortal)->h_App;
1909        p_Fq->h_QmFqr     = p_QmFqr;
1910        p_Fq->state       = qman_fq_state_sched;
1911        p_Fq->fqid        = p_QmFqr->fqidBase;
1912        p_QmFqr->p_Fqs[0] = p_Fq;
1913    }
1914    else
1915    {
1916        p_QmFqr->channel    = p_QmFqrParams->channel;
1917        p_QmFqr->workQueue  = p_QmFqrParams->wq;
1918
1919        p_QmFqr->fqidBase = QmFqidGet(p_QmFqr->h_Qm,
1920                                      p_QmFqr->numOfFqids,
1921                                      p_QmFqrParams->qs.nonFrcQs.align,
1922                                      p_QmFqrParams->useForce,
1923                                      p_QmFqrParams->qs.frcQ.fqid);
1924        if (p_QmFqr->fqidBase == (uint32_t)ILLEGAL_BASE)
1925        {
1926            REPORT_ERROR(CRITICAL,E_INVALID_STATE,("can't allocate a fqid"));
1927            QM_FQR_Free(p_QmFqr);
1928            return NULL;
1929        }
1930
1931        if(p_QmFqrParams->congestionAvoidanceEnable &&
1932            (p_QmFqrParams->congestionAvoidanceParams.h_QmCg == NULL) &&
1933            (p_QmFqrParams->congestionAvoidanceParams.fqTailDropThreshold == 0))
1934        {
1935            REPORT_ERROR(CRITICAL,E_INVALID_STATE,("NULL congestion group handle and no FQ Threshold"));
1936            QM_FQR_Free(p_QmFqr);
1937            return NULL;
1938        }
1939        if(p_QmFqrParams->congestionAvoidanceEnable)
1940        {
1941            if(p_QmFqrParams->congestionAvoidanceParams.h_QmCg)
1942                flags |= QM_FQCTRL_CGE;
1943            if(p_QmFqrParams->congestionAvoidanceParams.fqTailDropThreshold)
1944                flags |= QM_FQCTRL_TDE;
1945        }
1946
1947    /*
1948        flags |= (p_QmFqrParams->holdActive)    ? QM_FQCTRL_ORP : 0;
1949        flags |= (p_QmFqrParams->holdActive)    ? QM_FQCTRL_CPCSTASH : 0;
1950        flags |= (p_QmFqrParams->holdActive)    ? QM_FQCTRL_FORCESFDR : 0;
1951        flags |= (p_QmFqrParams->holdActive)    ? QM_FQCTRL_AVOIDBLOCK : 0;
1952    */
1953        flags |= (p_QmFqrParams->holdActive)    ? QM_FQCTRL_HOLDACTIVE : 0;
1954        flags |= (p_QmFqrParams->preferInCache) ? QM_FQCTRL_LOCKINCACHE : 0;
1955
1956        if (p_QmFqrParams->useContextAForStash)
1957        {
1958            if (CheckStashParams(p_QmFqrParams) != E_OK)
1959            {
1960                REPORT_ERROR(CRITICAL,E_INVALID_STATE,NO_MSG);
1961                QM_FQR_Free(p_QmFqr);
1962                return NULL;
1963            }
1964
1965            memset(&cnxtA, 0, sizeof(cnxtA));
1966            cnxtA.stashing.annotation_cl = DIV_CEIL(p_QmFqrParams->stashingParams.frameAnnotationSize, CACHELINE_SIZE);
1967            cnxtA.stashing.data_cl = DIV_CEIL(p_QmFqrParams->stashingParams.frameDataSize, CACHELINE_SIZE);
1968            cnxtA.stashing.context_cl = DIV_CEIL(p_QmFqrParams->stashingParams.fqContextSize, CACHELINE_SIZE);
1969            cnxtA.context_hi = (uint8_t)((p_QmFqrParams->stashingParams.fqContextAddr >> 32) & 0xff);
1970            cnxtA.context_lo = (uint32_t)(p_QmFqrParams->stashingParams.fqContextAddr);
1971            flags |= QM_FQCTRL_CTXASTASHING;
1972        }
1973
1974        for(i=0;i<p_QmFqr->numOfFqids;i++)
1975            if (qm_new_fq(p_QmFqr->h_QmPortal,
1976                          p_QmFqr->fqidBase+i,
1977                          i,
1978                          p_QmFqr->channel,
1979                          p_QmFqr->workQueue,
1980                          1/*p_QmFqr->numOfFqids*/,
1981                          flags,
1982                          (p_QmFqrParams->congestionAvoidanceEnable ?
1983                              &p_QmFqrParams->congestionAvoidanceParams : NULL),
1984                          p_QmFqrParams->useContextAForStash ?
1985                              (t_QmContextA *)&cnxtA : p_QmFqrParams->p_ContextA,
1986                          p_QmFqrParams->p_ContextB,
1987                          p_QmFqrParams->initParked,
1988                          p_QmFqr,
1989                          &p_QmFqr->p_Fqs[i]) != E_OK)
1990            {
1991                QM_FQR_Free(p_QmFqr);
1992                return NULL;
1993            }
1994    }
1995    return p_QmFqr;
1996}
1997
1998t_Error  QM_FQR_Free(t_Handle h_QmFqr)
1999{
2000    t_QmFqr     *p_QmFqr    = (t_QmFqr *)h_QmFqr;
2001    uint32_t    i;
2002
2003    if (!p_QmFqr)
2004        return ERROR_CODE(E_INVALID_HANDLE);
2005
2006    if (p_QmFqr->p_Fqs)
2007    {
2008        for (i=0;i<p_QmFqr->numOfFqids;i++)
2009            if (p_QmFqr->p_Fqs[i])
2010            {
2011                if (!p_QmFqr->shadowMode)
2012                    qm_free_fq(p_QmFqr->h_QmPortal, p_QmFqr->p_Fqs[i]);
2013                XX_FreeSmart(p_QmFqr->p_Fqs[i]);
2014            }
2015        XX_Free(p_QmFqr->p_Fqs);
2016    }
2017
2018    if (!p_QmFqr->shadowMode && p_QmFqr->fqidBase)
2019        QmFqidPut(p_QmFqr->h_Qm, p_QmFqr->fqidBase);
2020
2021    XX_FreeSmart(p_QmFqr);
2022
2023    return E_OK;
2024}
2025
2026t_Error  QM_FQR_FreeWDrain(t_Handle                     h_QmFqr,
2027                           t_QmFqrDrainedCompletionCB   *f_CompletionCB,
2028                           bool                         deliverFrame,
2029                           t_QmReceivedFrameCallback    *f_CallBack,
2030                           t_Handle                     h_App)
2031{
2032    t_QmFqr     *p_QmFqr    = (t_QmFqr *)h_QmFqr;
2033    uint32_t    i;
2034
2035    if (!p_QmFqr)
2036        return ERROR_CODE(E_INVALID_HANDLE);
2037
2038    if (p_QmFqr->shadowMode)
2039        RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("QM_FQR_FreeWDrain can't be called to shadow FQR!!!. call QM_FQR_Free"));
2040
2041    p_QmFqr->p_DrainedFqs = (bool *)XX_Malloc(sizeof(bool) * p_QmFqr->numOfFqids);
2042    if (!p_QmFqr->p_DrainedFqs)
2043        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("QM Drained-FQs obj!!!. Try to Free without draining"));
2044    memset(p_QmFqr->p_DrainedFqs, 0, sizeof(bool) * p_QmFqr->numOfFqids);
2045
2046    if (f_CompletionCB)
2047    {
2048        p_QmFqr->f_CompletionCB = f_CompletionCB;
2049        p_QmFqr->h_App          = h_App;
2050    }
2051
2052    if (deliverFrame)
2053    {
2054        if (!f_CallBack)
2055        {
2056            REPORT_ERROR(MAJOR, E_NULL_POINTER, ("f_CallBack must be given."));
2057            XX_Free(p_QmFqr->p_DrainedFqs);
2058            return ERROR_CODE(E_NULL_POINTER);
2059        }
2060        QM_FQR_RegisterCB(p_QmFqr, f_CallBack, h_App);
2061    }
2062    else
2063        QM_FQR_RegisterCB(p_QmFqr, drainCB, h_App);
2064
2065    for (i=0;i<p_QmFqr->numOfFqids;i++)
2066    {
2067        if (qman_retire_fq(p_QmFqr->h_QmPortal, p_QmFqr->p_Fqs[i], 0, TRUE) != E_OK)
2068            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("qman_retire_fq() failed!"));
2069
2070        if (p_QmFqr->p_Fqs[i]->flags & QMAN_FQ_STATE_CHANGING)
2071            DBG(INFO, ("fq %d currently in use, will be retired", p_QmFqr->p_Fqs[i]->fqid));
2072        else
2073            drainRetiredFq(p_QmFqr->p_Fqs[i]);
2074    }
2075
2076    if (!p_QmFqr->f_CompletionCB)
2077    {
2078        while(p_QmFqr->p_DrainedFqs) ;
2079        DBG(TRACE, ("QM-FQR with base %d completed", p_QmFqr->fqidBase));
2080        XX_FreeSmart(p_QmFqr->p_Fqs);
2081        if (p_QmFqr->fqidBase)
2082            QmFqidPut(p_QmFqr->h_Qm, p_QmFqr->fqidBase);
2083        XX_FreeSmart(p_QmFqr);
2084    }
2085
2086    return E_OK;
2087}
2088
2089t_Error QM_FQR_RegisterCB(t_Handle h_QmFqr, t_QmReceivedFrameCallback *f_CallBack, t_Handle h_App)
2090{
2091    t_QmFqr     *p_QmFqr = (t_QmFqr *)h_QmFqr;
2092    int         i;
2093
2094    SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
2095
2096    for (i=0;i<p_QmFqr->numOfFqids;i++)
2097    {
2098        p_QmFqr->p_Fqs[i]->cb.dqrr = f_CallBack;
2099        p_QmFqr->p_Fqs[i]->h_App   = h_App;
2100    }
2101
2102    return E_OK;
2103}
2104
2105t_Error QM_FQR_Enqueue(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset, t_DpaaFD *p_Frame)
2106{
2107    t_QmFqr                 *p_QmFqr = (t_QmFqr *)h_QmFqr;
2108    t_QmPortal              *p_QmPortal;
2109    struct qm_eqcr_entry    *p_Eq;
2110    uint32_t                *p_Dst, *p_Src;
2111    const struct qman_fq    *p_Fq;
2112
2113    SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
2114    SANITY_CHECK_RETURN_ERROR((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE);
2115
2116    if (!h_QmPortal)
2117    {
2118        SANITY_CHECK_RETURN_ERROR(p_QmFqr->h_Qm, E_INVALID_HANDLE);
2119        h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
2120        SANITY_CHECK_RETURN_ERROR(h_QmPortal, E_INVALID_HANDLE);
2121    }
2122    p_QmPortal = (t_QmPortal *)h_QmPortal;
2123
2124    p_Fq = p_QmFqr->p_Fqs[fqidOffset];
2125
2126#ifdef QM_CHECKING
2127    if (p_Fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE)
2128        RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
2129    if ((!(p_Fq->flags & QMAN_FQ_FLAG_NO_MODIFY)) &&
2130        ((p_Fq->state == qman_fq_state_retired) ||
2131         (p_Fq->state == qman_fq_state_oos)))
2132        return ERROR_CODE(E_BUSY);
2133#endif /* QM_CHECKING */
2134
2135    NCSW_PLOCK(p_QmPortal);
2136    p_Eq = try_eq_start(p_QmPortal);
2137    if (!p_Eq)
2138    {
2139        PUNLOCK(p_QmPortal);
2140        return ERROR_CODE(E_BUSY);
2141    }
2142
2143    p_Eq->fqid = p_Fq->fqid;
2144    p_Eq->tag = (uint32_t)p_Fq;
2145    /* gcc does a dreadful job of the following;
2146     *  eq->fd = *fd;
2147     * It causes the entire function to save/restore a wider range of
2148     * registers, and comes up with instruction-waste galore. This will do
2149     * until we can rework the function for better code-generation. */
2150    p_Dst = (uint32_t *)&p_Eq->fd;
2151    p_Src = (uint32_t *)p_Frame;
2152    p_Dst[0] = p_Src[0];
2153    p_Dst[1] = p_Src[1];
2154    p_Dst[2] = p_Src[2];
2155    p_Dst[3] = p_Src[3];
2156
2157    qmPortalEqcrPvbCommit(p_QmPortal->p_LowQmPortal,
2158                          (uint8_t)(QM_EQCR_VERB_CMD_ENQUEUE/* |
2159                          (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))*/));
2160    PUNLOCK(p_QmPortal);
2161
2162    return E_OK;
2163}
2164
2165
2166t_Error QM_FQR_PullFrame(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset, t_DpaaFD *p_Frame)
2167{
2168    t_QmFqr                 *p_QmFqr = (t_QmFqr *)h_QmFqr;
2169    uint32_t                pdqcr = 0;
2170
2171    SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
2172    SANITY_CHECK_RETURN_ERROR((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE);
2173    SANITY_CHECK_RETURN_ERROR(p_Frame, E_NULL_POINTER);
2174    SANITY_CHECK_RETURN_ERROR((p_QmFqr->p_Fqs[fqidOffset]->state == qman_fq_state_oos) ||
2175                              (p_QmFqr->p_Fqs[fqidOffset]->state == qman_fq_state_parked),
2176                              E_INVALID_STATE);
2177    if (!h_QmPortal)
2178    {
2179        SANITY_CHECK_RETURN_ERROR(p_QmFqr->h_Qm, E_INVALID_HANDLE);
2180        h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
2181        SANITY_CHECK_RETURN_ERROR(h_QmPortal, E_INVALID_HANDLE);
2182    }
2183
2184    pdqcr |= QM_PDQCR_MODE_UNSCHEDULED;
2185    pdqcr |= QM_PDQCR_FQID(p_QmFqr->p_Fqs[fqidOffset]->fqid);
2186    return QmPortalPullFrame(h_QmPortal, pdqcr, p_Frame);
2187}
2188
2189t_Error QM_FQR_Resume(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset)
2190{
2191    t_QmFqr     *p_QmFqr = (t_QmFqr *)h_QmFqr;
2192
2193    SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
2194    SANITY_CHECK_RETURN_ERROR((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE);
2195
2196    if (!h_QmPortal)
2197    {
2198        SANITY_CHECK_RETURN_ERROR(p_QmFqr->h_Qm, E_INVALID_HANDLE);
2199        h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
2200        SANITY_CHECK_RETURN_ERROR(h_QmPortal, E_INVALID_HANDLE);
2201    }
2202    return qman_schedule_fq(h_QmPortal, p_QmFqr->p_Fqs[fqidOffset]);
2203}
2204
2205t_Error  QM_FQR_Suspend(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset)
2206{
2207    t_QmFqr     *p_QmFqr = (t_QmFqr *)h_QmFqr;
2208
2209    SANITY_CHECK_RETURN_ERROR(p_QmFqr, E_INVALID_HANDLE);
2210    SANITY_CHECK_RETURN_ERROR((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE);
2211    SANITY_CHECK_RETURN_ERROR((p_QmFqr->p_Fqs[fqidOffset]->flags & QM_FQCTRL_HOLDACTIVE), E_INVALID_STATE);
2212
2213    UNUSED(h_QmPortal);
2214    p_QmFqr->p_Fqs[fqidOffset]->state = qman_fq_state_waiting_parked;
2215
2216    return E_OK;
2217}
2218
2219uint32_t QM_FQR_GetFqid(t_Handle h_QmFqr)
2220{
2221    t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
2222
2223    SANITY_CHECK_RETURN_VALUE(p_QmFqr, E_INVALID_HANDLE, 0);
2224
2225    return p_QmFqr->fqidBase;
2226}
2227
2228uint32_t QM_FQR_GetCounter(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffset, e_QmFqrCounters counter)
2229{
2230    t_QmFqr *p_QmFqr = (t_QmFqr *)h_QmFqr;
2231    struct qm_mcr_queryfq_np    queryfq_np;
2232
2233    SANITY_CHECK_RETURN_VALUE(p_QmFqr, E_INVALID_HANDLE, 0);
2234    SANITY_CHECK_RETURN_VALUE((fqidOffset < p_QmFqr->numOfFqids), E_INVALID_VALUE, 0);
2235
2236    if (!h_QmPortal)
2237    {
2238        SANITY_CHECK_RETURN_VALUE(p_QmFqr->h_Qm, E_INVALID_HANDLE, 0);
2239        h_QmPortal = QmGetPortalHandle(p_QmFqr->h_Qm);
2240        SANITY_CHECK_RETURN_VALUE(h_QmPortal, E_INVALID_HANDLE, 0);
2241    }
2242    if (qman_query_fq_np(h_QmPortal, p_QmFqr->p_Fqs[fqidOffset], &queryfq_np) != E_OK)
2243        return 0;
2244    switch (counter)
2245    {
2246        case e_QM_FQR_COUNTERS_FRAME :
2247            return queryfq_np.frm_cnt;
2248        case e_QM_FQR_COUNTERS_BYTE :
2249            return queryfq_np.byte_cnt;
2250        default :
2251            break;
2252    }
2253    /* should never get here */
2254    ASSERT_COND(FALSE);
2255
2256    return 0;
2257}
2258
2259
2260t_Handle QM_CG_Create(t_QmCgParams *p_CgParams)
2261{
2262    t_QmCg                          *p_QmCg;
2263    t_QmPortal                      *p_QmPortal;
2264    t_Error                         err;
2265    uint32_t                        wredParams;
2266    uint32_t                        tmpA, tmpN, ta=0, tn=0;
2267    int                             gap, tmp;
2268    struct qm_mc_command            *p_Mcc;
2269    struct qm_mc_result             *p_Mcr;
2270
2271    SANITY_CHECK_RETURN_VALUE(p_CgParams, E_INVALID_HANDLE, NULL);
2272    SANITY_CHECK_RETURN_VALUE(p_CgParams->h_Qm, E_INVALID_HANDLE, NULL);
2273
2274    if(p_CgParams->notifyDcPortal &&
2275       ((p_CgParams->dcPortalId == e_DPAA_DCPORTAL2) || (p_CgParams->dcPortalId == e_DPAA_DCPORTAL3)))
2276    {
2277        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("notifyDcPortal is invalid for this DC Portal"));
2278        return NULL;
2279    }
2280
2281    if (!p_CgParams->h_QmPortal)
2282    {
2283        p_QmPortal = QmGetPortalHandle(p_CgParams->h_Qm);
2284        SANITY_CHECK_RETURN_VALUE(p_QmPortal, E_INVALID_STATE, NULL);
2285    }
2286    else
2287        p_QmPortal = p_CgParams->h_QmPortal;
2288
2289    p_QmCg = (t_QmCg *)XX_Malloc(sizeof(t_QmCg));
2290    if (!p_QmCg)
2291    {
2292        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("QM CG obj!!!"));
2293        return NULL;
2294    }
2295    memset(p_QmCg, 0, sizeof(t_QmCg));
2296
2297    /* build CG struct */
2298    p_QmCg->h_Qm        = p_CgParams->h_Qm;
2299    p_QmCg->h_QmPortal  = p_QmPortal;
2300    p_QmCg->h_App       = p_CgParams->h_App;
2301    err = QmGetCgId(p_CgParams->h_Qm, &p_QmCg->id);
2302    if (err)
2303    {
2304        XX_Free(p_QmCg);
2305        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("QmGetCgId failed"));
2306        return NULL;
2307    }
2308
2309    NCSW_PLOCK(p_QmPortal);
2310    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
2311    p_Mcc->initcgr.cgid = p_QmCg->id;
2312
2313    err = QmPortalRegisterCg(p_QmPortal, p_QmCg, p_QmCg->id);
2314    if (err)
2315    {
2316        XX_Free(p_QmCg);
2317        PUNLOCK(p_QmPortal);
2318        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("QmPortalRegisterCg failed"));
2319        return NULL;
2320    }
2321
2322    /*  Build CGR command */
2323    {
2324#ifdef QM_CGS_NO_FRAME_MODE
2325    t_QmRevisionInfo    revInfo;
2326
2327    QmGetRevision(p_QmCg->h_Qm, &revInfo);
2328
2329    if (!((revInfo.majorRev == 1) && (revInfo.minorRev == 0)))
2330#endif /* QM_CGS_NO_FRAME_MODE */
2331        if (p_CgParams->frameCount)
2332        {
2333            p_Mcc->initcgr.we_mask |= QM_CGR_WE_MODE;
2334            p_Mcc->initcgr.cgr.frame_mode = QM_CGR_EN;
2335        }
2336    }
2337
2338    if (p_CgParams->wredEnable)
2339    {
2340        if (p_CgParams->wredParams.enableGreen)
2341        {
2342            err = CalcWredCurve(&p_CgParams->wredParams.greenCurve, &wredParams);
2343            if(err)
2344            {
2345                XX_Free(p_QmCg);
2346                PUNLOCK(p_QmPortal);
2347                REPORT_ERROR(MAJOR, err, NO_MSG);
2348                return NULL;
2349            }
2350            p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_G | QM_CGR_WE_WR_PARM_G;
2351            p_Mcc->initcgr.cgr.wr_en_g = QM_CGR_EN;
2352            p_Mcc->initcgr.cgr.wr_parm_g.word = wredParams;
2353        }
2354        if (p_CgParams->wredParams.enableYellow)
2355        {
2356            err = CalcWredCurve(&p_CgParams->wredParams.yellowCurve, &wredParams);
2357            if(err)
2358            {
2359                XX_Free(p_QmCg);
2360                PUNLOCK(p_QmPortal);
2361                REPORT_ERROR(MAJOR, err, NO_MSG);
2362                return NULL;
2363            }
2364            p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_Y | QM_CGR_WE_WR_PARM_Y;
2365            p_Mcc->initcgr.cgr.wr_en_y = QM_CGR_EN;
2366            p_Mcc->initcgr.cgr.wr_parm_y.word = wredParams;
2367        }
2368        if (p_CgParams->wredParams.enableRed)
2369        {
2370            err = CalcWredCurve(&p_CgParams->wredParams.redCurve, &wredParams);
2371            if(err)
2372            {
2373                XX_Free(p_QmCg);
2374                PUNLOCK(p_QmPortal);
2375                REPORT_ERROR(MAJOR, err, NO_MSG);
2376                return NULL;
2377            }
2378            p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_R | QM_CGR_WE_WR_PARM_R;
2379            p_Mcc->initcgr.cgr.wr_en_r = QM_CGR_EN;
2380            p_Mcc->initcgr.cgr.wr_parm_r.word = wredParams;
2381        }
2382    }
2383
2384    if (p_CgParams->tailDropEnable)
2385    {
2386        if (!p_CgParams->threshold)
2387        {
2388            XX_Free(p_QmCg);
2389            PUNLOCK(p_QmPortal);
2390            REPORT_ERROR(MINOR, E_INVALID_STATE, ("tailDropThreshold must be configured if tailDropEnable "));
2391            return NULL;
2392        }
2393        p_Mcc->initcgr.cgr.cstd_en = QM_CGR_EN;
2394        p_Mcc->initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
2395    }
2396
2397    if (p_CgParams->threshold)
2398    {
2399        p_Mcc->initcgr.we_mask |= QM_CGR_WE_CS_THRES;
2400        p_QmCg->f_Exception = p_CgParams->f_Exception;
2401        if (p_QmCg->f_Exception || p_CgParams->notifyDcPortal)
2402        {
2403            p_Mcc->initcgr.cgr.cscn_en = QM_CGR_EN;
2404            p_Mcc->initcgr.we_mask |= QM_CGR_WE_CSCN_EN | QM_CGR_WE_CSCN_TARG;
2405            /* if SW - set target, if HW - if FM, set HW target, otherwize, set SW target */
2406            p_Mcc->initcgr.cgr.cscn_targ = 0;
2407            if (p_QmCg->f_Exception)
2408                p_Mcc->initcgr.cgr.cscn_targ = (uint32_t)QM_CGR_TARGET_SWP(QmPortalGetSwPortalId(p_QmCg->h_QmPortal));
2409            if (p_CgParams->notifyDcPortal)
2410                p_Mcc->initcgr.cgr.cscn_targ |= (uint32_t)QM_CGR_TARGET_DCP(p_CgParams->dcPortalId);
2411        }
2412
2413        /* express thresh as ta*2^tn */
2414        gap = (int)p_CgParams->threshold;
2415        for (tmpA=0 ; tmpA<256; tmpA++ )
2416            for (tmpN=0 ; tmpN<32; tmpN++ )
2417            {
2418                tmp = ABS((int)(p_CgParams->threshold - tmpA*(1<<tmpN)));
2419                if (tmp < gap)
2420                {
2421                   ta = tmpA;
2422                   tn = tmpN;
2423                   gap = tmp;
2424                }
2425            }
2426        p_Mcc->initcgr.cgr.cs_thres.TA = ta;
2427        p_Mcc->initcgr.cgr.cs_thres.Tn = tn;
2428    }
2429    else if(p_CgParams->f_Exception)
2430    {
2431        XX_Free(p_QmCg);
2432        PUNLOCK(p_QmPortal);
2433        REPORT_ERROR(MINOR, E_INVALID_STATE, ("No threshold configured, but f_Exception defined"));
2434        return NULL;
2435    }
2436
2437    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_INITCGR);
2438    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
2439    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_INITCGR);
2440    if (p_Mcr->result != QM_MCR_RESULT_OK)
2441    {
2442        XX_Free(p_QmCg);
2443        PUNLOCK(p_QmPortal);
2444        REPORT_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
2445        return NULL;
2446    }
2447    PUNLOCK(p_QmPortal);
2448
2449    return p_QmCg;
2450}
2451
2452t_Error QM_CG_Free(t_Handle h_QmCg)
2453{
2454
2455    t_QmCg                  *p_QmCg = (t_QmCg *)h_QmCg;
2456    t_Error                 err;
2457    struct qm_mc_command    *p_Mcc;
2458    struct qm_mc_result     *p_Mcr;
2459    t_QmPortal              *p_QmPortal;
2460
2461    SANITY_CHECK_RETURN_ERROR(p_QmCg, E_INVALID_HANDLE);
2462
2463    p_QmPortal = (t_QmPortal *)p_QmCg->h_QmPortal;
2464
2465    NCSW_PLOCK(p_QmPortal);
2466    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
2467    p_Mcc->initcgr.cgid = p_QmCg->id;
2468    p_Mcc->initcgr.we_mask = QM_CGR_WE_MASK;
2469
2470    err = QmFreeCgId(p_QmCg->h_Qm, p_QmCg->id);
2471    if(err)
2472    {
2473        XX_Free(p_QmCg);
2474        PUNLOCK(p_QmPortal);
2475        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("QmFreeCgId failed"));
2476    }
2477
2478    err = QmPortalUnregisterCg(p_QmCg->h_QmPortal, p_QmCg->id);
2479    if(err)
2480    {
2481        XX_Free(p_QmCg);
2482        PUNLOCK(p_QmPortal);
2483        RETURN_ERROR(MAJOR, E_INVALID_STATE, ("QmPortalUnregisterCg failed"));
2484    }
2485
2486    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_MODIFYCGR);
2487    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
2488    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_MODIFYCGR);
2489    if (p_Mcr->result != QM_MCR_RESULT_OK)
2490    {
2491        PUNLOCK(p_QmPortal);
2492        RETURN_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
2493    }
2494    PUNLOCK(p_QmPortal);
2495
2496    XX_Free(p_QmCg);
2497
2498    return E_OK;
2499}
2500
2501t_Error QM_CG_SetException(t_Handle h_QmCg, e_QmExceptions exception, bool enable)
2502{
2503    t_QmCg                  *p_QmCg = (t_QmCg *)h_QmCg;
2504    struct qm_mc_command    *p_Mcc;
2505    struct qm_mc_result     *p_Mcr;
2506    t_QmPortal              *p_QmPortal;
2507
2508    SANITY_CHECK_RETURN_ERROR(p_QmCg, E_INVALID_HANDLE);
2509
2510    p_QmPortal = (t_QmPortal *)p_QmCg->h_QmPortal;
2511    if (!p_QmCg->f_Exception)
2512        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Either threshold or exception callback was not configured."));
2513
2514    NCSW_PLOCK(p_QmPortal);
2515    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
2516    p_Mcc->initcgr.cgid = p_QmCg->id;
2517    p_Mcc->initcgr.we_mask = QM_CGR_WE_CSCN_EN;
2518
2519    if(exception == e_QM_EX_CG_STATE_CHANGE)
2520    {
2521        if(enable)
2522            p_Mcc->initcgr.cgr.cscn_en = QM_CGR_EN;
2523    }
2524    else
2525    {
2526        PUNLOCK(p_QmPortal);
2527        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal exception"));
2528    }
2529
2530    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_MODIFYCGR);
2531    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
2532    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_MODIFYCGR);
2533    if (p_Mcr->result != QM_MCR_RESULT_OK)
2534    {
2535        PUNLOCK(p_QmPortal);
2536        RETURN_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
2537    }
2538    PUNLOCK(p_QmPortal);
2539
2540    return E_OK;
2541}
2542
2543t_Error QM_CG_ModifyWredCurve(t_Handle h_QmCg, t_QmCgModifyWredParams *p_QmCgModifyParams)
2544{
2545    t_QmCg                  *p_QmCg = (t_QmCg *)h_QmCg;
2546    uint32_t                wredParams;
2547    struct qm_mc_command    *p_Mcc;
2548    struct qm_mc_result     *p_Mcr;
2549    t_QmPortal              *p_QmPortal;
2550    t_Error                 err = E_OK;
2551
2552    SANITY_CHECK_RETURN_ERROR(p_QmCg, E_INVALID_HANDLE);
2553
2554    p_QmPortal = (t_QmPortal *)p_QmCg->h_QmPortal;
2555
2556    NCSW_PLOCK(p_QmPortal);
2557    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
2558    p_Mcc->initcgr.cgid = p_QmCg->id;
2559
2560    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYCGR);
2561    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
2562    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYCGR);
2563    if (p_Mcr->result != QM_MCR_RESULT_OK)
2564    {
2565        PUNLOCK(p_QmPortal);
2566        RETURN_ERROR(MINOR, E_INVALID_STATE, ("QM_MCC_VERB_QUERYCGR failed: %s", mcr_result_str(p_Mcr->result)));
2567    }
2568
2569    switch(p_QmCgModifyParams->color)
2570    {
2571        case(e_QM_CG_COLOR_GREEN):
2572            if(!p_Mcr->querycgr.cgr.wr_en_g)
2573            {
2574                PUNLOCK(p_QmPortal);
2575                RETURN_ERROR(MINOR, E_INVALID_STATE, ("WRED is not enabled for green"));
2576            }
2577            break;
2578        case(e_QM_CG_COLOR_YELLOW):
2579            if(!p_Mcr->querycgr.cgr.wr_en_y)
2580            {
2581                PUNLOCK(p_QmPortal);
2582                RETURN_ERROR(MINOR, E_INVALID_STATE, ("WRED is not enabled for yellow"));
2583            }
2584            break;
2585        case(e_QM_CG_COLOR_RED):
2586            if(!p_Mcr->querycgr.cgr.wr_en_r)
2587            {
2588                PUNLOCK(p_QmPortal);
2589                RETURN_ERROR(MINOR, E_INVALID_STATE, ("WRED is not enabled for red"));
2590            }
2591            break;
2592    }
2593
2594    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
2595    p_Mcc->initcgr.cgid = p_QmCg->id;
2596
2597    switch(p_QmCgModifyParams->color)
2598    {
2599        case(e_QM_CG_COLOR_GREEN):
2600            err = CalcWredCurve(&p_QmCgModifyParams->wredParams, &wredParams);
2601            p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_G | QM_CGR_WE_WR_PARM_G;
2602            p_Mcc->initcgr.cgr.wr_en_g = QM_CGR_EN;
2603            p_Mcc->initcgr.cgr.wr_parm_g.word = wredParams;
2604            break;
2605        case(e_QM_CG_COLOR_YELLOW):
2606            err = CalcWredCurve(&p_QmCgModifyParams->wredParams, &wredParams);
2607            p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_Y | QM_CGR_WE_WR_PARM_Y;
2608            p_Mcc->initcgr.cgr.wr_en_y = QM_CGR_EN;
2609            p_Mcc->initcgr.cgr.wr_parm_y.word = wredParams;
2610            break;
2611        case(e_QM_CG_COLOR_RED):
2612            err = CalcWredCurve(&p_QmCgModifyParams->wredParams, &wredParams);
2613            p_Mcc->initcgr.we_mask |= QM_CGR_WE_WR_EN_R | QM_CGR_WE_WR_PARM_R;
2614            p_Mcc->initcgr.cgr.wr_en_r = QM_CGR_EN;
2615            p_Mcc->initcgr.cgr.wr_parm_r.word = wredParams;
2616            break;
2617    }
2618    if (err)
2619    {
2620        PUNLOCK(p_QmPortal);
2621        RETURN_ERROR(MINOR, err, NO_MSG);
2622    }
2623
2624    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_MODIFYCGR);
2625    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
2626    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_MODIFYCGR);
2627    if (p_Mcr->result != QM_MCR_RESULT_OK)
2628    {
2629        PUNLOCK(p_QmPortal);
2630        RETURN_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
2631    }
2632    PUNLOCK(p_QmPortal);
2633
2634    return E_OK;
2635}
2636
2637t_Error QM_CG_ModifyTailDropThreshold(t_Handle h_QmCg, uint32_t threshold)
2638{
2639    t_QmCg                  *p_QmCg = (t_QmCg *)h_QmCg;
2640    struct qm_mc_command    *p_Mcc;
2641    struct qm_mc_result     *p_Mcr;
2642    t_QmPortal              *p_QmPortal;
2643    uint32_t                tmpA, tmpN, ta=0, tn=0;
2644    int                     gap, tmp;
2645
2646    SANITY_CHECK_RETURN_ERROR(p_QmCg, E_INVALID_HANDLE);
2647
2648    p_QmPortal = (t_QmPortal *)p_QmCg->h_QmPortal;
2649
2650    NCSW_PLOCK(p_QmPortal);
2651    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
2652    p_Mcc->initcgr.cgid = p_QmCg->id;
2653
2654    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_QUERYCGR);
2655    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
2656    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYCGR);
2657    if (p_Mcr->result != QM_MCR_RESULT_OK)
2658    {
2659        PUNLOCK(p_QmPortal);
2660        RETURN_ERROR(MINOR, E_INVALID_STATE, ("QM_MCC_VERB_QUERYCGR failed: %s", mcr_result_str(p_Mcr->result)));
2661    }
2662
2663    if(!p_Mcr->querycgr.cgr.cstd_en)
2664    {
2665        PUNLOCK(p_QmPortal);
2666        RETURN_ERROR(MINOR, E_INVALID_STATE, ("Tail Drop is not enabled!"));
2667    }
2668
2669    p_Mcc = qm_mc_start(p_QmPortal->p_LowQmPortal);
2670    p_Mcc->initcgr.cgid = p_QmCg->id;
2671    p_Mcc->initcgr.we_mask |= QM_CGR_WE_CS_THRES;
2672
2673    /* express thresh as ta*2^tn */
2674    gap = (int)threshold;
2675    for (tmpA=0 ; tmpA<256; tmpA++ )
2676        for (tmpN=0 ; tmpN<32; tmpN++ )
2677        {
2678            tmp = ABS((int)(threshold - tmpA*(1<<tmpN)));
2679            if (tmp < gap)
2680            {
2681               ta = tmpA;
2682               tn = tmpN;
2683               gap = tmp;
2684            }
2685        }
2686    p_Mcc->initcgr.cgr.cs_thres.TA = ta;
2687    p_Mcc->initcgr.cgr.cs_thres.Tn = tn;
2688
2689    qm_mc_commit(p_QmPortal->p_LowQmPortal, QM_MCC_VERB_MODIFYCGR);
2690    while (!(p_Mcr = qm_mc_result(p_QmPortal->p_LowQmPortal))) ;
2691    ASSERT_COND((p_Mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_MODIFYCGR);
2692    if (p_Mcr->result != QM_MCR_RESULT_OK)
2693    {
2694        PUNLOCK(p_QmPortal);
2695        RETURN_ERROR(MINOR, E_INVALID_STATE, ("INITCGR failed: %s", mcr_result_str(p_Mcr->result)));
2696    }
2697    PUNLOCK(p_QmPortal);
2698
2699    return E_OK;
2700}
2701
2702