Path: blob/main/sys/contrib/ncsw/Peripherals/QM/qman_low.h
48378 views
/******************************************************************************12� 1995-2003, 2004, 2005-2011 Freescale Semiconductor, Inc.3All rights reserved.45This is proprietary source code of Freescale Semiconductor Inc.,6and its use is subject to the NetComm Device Drivers EULA.7The copyright notice above does not evidence any actual or intended8publication of such source code.910ALTERNATIVELY, redistribution and use in source and binary forms, with11or without modification, are permitted provided that the following12conditions are met:13* Redistributions of source code must retain the above copyright14notice, this list of conditions and the following disclaimer.15* Redistributions in binary form must reproduce the above copyright16notice, this list of conditions and the following disclaimer in the17documentation and/or other materials provided with the distribution.18* Neither the name of Freescale Semiconductor nor the19names of its contributors may be used to endorse or promote products20derived from this software without specific prior written permission.2122THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY23EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED24WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE25DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY26DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES27(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;28LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND29ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT30(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS31SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.32*3334**************************************************************************/35/******************************************************************************36@File qman_low.c3738@Description QM Low-level implementation39*//***************************************************************************/40#include "std_ext.h"41#include "core_ext.h"42#include "xx_ext.h"43#include "error_ext.h"4445#include "qman_private.h"464748/***************************/49/* Portal register assists */50/***************************/5152/* Cache-inhibited register offsets */53#define REG_EQCR_PI_CINH 0x000054#define REG_EQCR_CI_CINH 0x000455#define REG_EQCR_ITR 0x000856#define REG_DQRR_PI_CINH 0x004057#define REG_DQRR_CI_CINH 0x004458#define REG_DQRR_ITR 0x004859#define REG_DQRR_DCAP 0x005060#define REG_DQRR_SDQCR 0x005461#define REG_DQRR_VDQCR 0x005862#define REG_DQRR_PDQCR 0x005c63#define REG_MR_PI_CINH 0x008064#define REG_MR_CI_CINH 0x008465#define REG_MR_ITR 0x008866#define REG_CFG 0x010067#define REG_ISR 0x0e0068#define REG_IER 0x0e0469#define REG_ISDR 0x0e0870#define REG_IIR 0x0e0c71#define REG_ITPR 0x0e147273/* Cache-enabled register offsets */74#define CL_EQCR 0x000075#define CL_DQRR 0x100076#define CL_MR 0x200077#define CL_EQCR_PI_CENA 0x300078#define CL_EQCR_CI_CENA 0x310079#define CL_DQRR_PI_CENA 0x320080#define CL_DQRR_CI_CENA 0x330081#define CL_MR_PI_CENA 0x340082#define CL_MR_CI_CENA 0x350083#define CL_RORI_CENA 0x360084#define CL_CR 0x380085#define CL_RR0 0x390086#define CL_RR1 0x39408788static __inline__ void *ptr_ADD(void *a, uintptr_t b)89{90return (void *)((uintptr_t)a + b);91}9293/* The h/w design requires mappings to be size-aligned so that "add"s can be94* reduced to "or"s. The primitives below do the same for s/w. */95/* Bitwise-OR two pointers */96static __inline__ void *ptr_OR(void *a, uintptr_t b)97{98return (void *)((uintptr_t)a | b);99}100101/* Cache-inhibited register access */102static __inline__ uint32_t __qm_in(struct qm_addr *qm, uintptr_t offset)103{104uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ci, offset);105return GET_UINT32(*tmp);106}107static __inline__ void __qm_out(struct qm_addr *qm, uintptr_t offset, uint32_t val)108{109uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ci, offset);110WRITE_UINT32(*tmp, val);111}112#define qm_in(reg) __qm_in(&portal->addr, REG_##reg)113#define qm_out(reg, val) __qm_out(&portal->addr, REG_##reg, (uint32_t)val)114115/* Convert 'n' cachelines to a pointer value for bitwise OR */116#define qm_cl(n) ((n) << 6)117118/* Cache-enabled (index) register access */119static __inline__ void __qm_cl_touch_ro(struct qm_addr *qm, uintptr_t offset)120{121dcbt_ro(ptr_ADD(qm->addr_ce, offset));122}123static __inline__ void __qm_cl_touch_rw(struct qm_addr *qm, uintptr_t offset)124{125dcbt_rw(ptr_ADD(qm->addr_ce, offset));126}127static __inline__ uint32_t __qm_cl_in(struct qm_addr *qm, uintptr_t offset)128{129uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ce, offset);130return GET_UINT32(*tmp);131}132static __inline__ void __qm_cl_out(struct qm_addr *qm, uintptr_t offset, uint32_t val)133{134uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ce, offset);135WRITE_UINT32(*tmp, val);136dcbf(tmp);137}138static __inline__ void __qm_cl_invalidate(struct qm_addr *qm, uintptr_t offset)139{140dcbi(ptr_ADD(qm->addr_ce, offset));141}142#define qm_cl_touch_ro(reg) __qm_cl_touch_ro(&portal->addr, CL_##reg##_CENA)143#define qm_cl_touch_rw(reg) __qm_cl_touch_rw(&portal->addr, CL_##reg##_CENA)144#define qm_cl_in(reg) __qm_cl_in(&portal->addr, CL_##reg##_CENA)145#define qm_cl_out(reg, val) __qm_cl_out(&portal->addr, CL_##reg##_CENA, val)146#define qm_cl_invalidate(reg) __qm_cl_invalidate(&portal->addr, CL_##reg##_CENA)147148/* Cyclic helper for rings. TODO: once we are able to do fine-grain perf149* analysis, look at using the "extra" bit in the ring index registers to avoid150* cyclic issues. */151static __inline__ uint8_t cyc_diff(uint8_t ringsize, uint8_t first, uint8_t last)152{153/* 'first' is included, 'last' is excluded */154if (first <= last)155return (uint8_t)(last - first);156return (uint8_t)(ringsize + last - first);157}158159static __inline__ t_Error __qm_portal_bind(struct qm_portal *portal, uint8_t iface)160{161t_Error ret = E_BUSY;162if (!(portal->config.bound & iface)) {163portal->config.bound |= iface;164ret = E_OK;165}166return ret;167}168169static __inline__ void __qm_portal_unbind(struct qm_portal *portal, uint8_t iface)170{171#ifdef QM_CHECKING172ASSERT_COND(portal->config.bound & iface);173#endif /* QM_CHECKING */174portal->config.bound &= ~iface;175}176177/* ---------------- */178/* --- EQCR API --- */179180/* It's safer to code in terms of the 'eqcr' object than the 'portal' object,181* because the latter runs the risk of copy-n-paste errors from other code where182* we could manipulate some other structure within 'portal'. */183/* #define EQCR_API_START() register struct qm_eqcr *eqcr = &portal->eqcr */184185/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */186#define EQCR_CARRYCLEAR(p) \187(void *)((uintptr_t)(p) & (~(uintptr_t)(QM_EQCR_SIZE << 6)))188189/* Bit-wise logic to convert a ring pointer to a ring index */190static __inline__ uint8_t EQCR_PTR2IDX(struct qm_eqcr_entry *e)191{192return (uint8_t)(((uintptr_t)e >> 6) & (QM_EQCR_SIZE - 1));193}194195/* Increment the 'cursor' ring pointer, taking 'vbit' into account */196static __inline__ void EQCR_INC(struct qm_eqcr *eqcr)197{198/* NB: this is odd-looking, but experiments show that it generates fast199* code with essentially no branching overheads. We increment to the200* next EQCR pointer and handle overflow and 'vbit'. */201struct qm_eqcr_entry *partial = eqcr->cursor + 1;202eqcr->cursor = EQCR_CARRYCLEAR(partial);203if (partial != eqcr->cursor)204eqcr->vbit ^= QM_EQCR_VERB_VBIT;205}206207static __inline__ t_Error qm_eqcr_init(struct qm_portal *portal, e_QmPortalProduceMode pmode,208e_QmPortalEqcrConsumeMode cmode)209{210register struct qm_eqcr *eqcr = &portal->eqcr;211uint32_t cfg;212uint8_t pi;213214if (__qm_portal_bind(portal, QM_BIND_EQCR))215return ERROR_CODE(E_BUSY);216eqcr->ring = ptr_ADD(portal->addr.addr_ce, CL_EQCR);217eqcr->ci = (uint8_t)(qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1));218qm_cl_invalidate(EQCR_CI);219pi = (uint8_t)(qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1));220eqcr->cursor = eqcr->ring + pi;221eqcr->vbit = (uint8_t)((qm_in(EQCR_PI_CINH) & QM_EQCR_SIZE) ?222QM_EQCR_VERB_VBIT : 0);223eqcr->available = (uint8_t)(QM_EQCR_SIZE - 1 -224cyc_diff(QM_EQCR_SIZE, eqcr->ci, pi));225eqcr->ithresh = (uint8_t)qm_in(EQCR_ITR);226227#ifdef QM_CHECKING228eqcr->busy = 0;229eqcr->pmode = pmode;230eqcr->cmode = cmode;231#else232UNUSED(cmode);233#endif /* QM_CHECKING */234cfg = (qm_in(CFG) & 0x00ffffff) |235((pmode & 0x3) << 24); /* QCSP_CFG::EPM */236qm_out(CFG, cfg);237return 0;238}239240static __inline__ void qm_eqcr_finish(struct qm_portal *portal)241{242register struct qm_eqcr *eqcr = &portal->eqcr;243uint8_t pi = (uint8_t)(qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1));244uint8_t ci = (uint8_t)(qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1));245246#ifdef QM_CHECKING247ASSERT_COND(!eqcr->busy);248#endif /* QM_CHECKING */249if (pi != EQCR_PTR2IDX(eqcr->cursor))250REPORT_ERROR(WARNING, E_INVALID_STATE, ("losing uncommitted EQCR entries"));251if (ci != eqcr->ci)252REPORT_ERROR(WARNING, E_INVALID_STATE, ("missing existing EQCR completions"));253if (eqcr->ci != EQCR_PTR2IDX(eqcr->cursor))254REPORT_ERROR(WARNING, E_INVALID_STATE, ("EQCR destroyed unquiesced"));255__qm_portal_unbind(portal, QM_BIND_EQCR);256}257258static __inline__ struct qm_eqcr_entry *qm_eqcr_start(struct qm_portal *portal)259{260register struct qm_eqcr *eqcr = &portal->eqcr;261#ifdef QM_CHECKING262ASSERT_COND(!eqcr->busy);263#endif /* QM_CHECKING */264if (!eqcr->available)265return NULL;266#ifdef QM_CHECKING267eqcr->busy = 1;268#endif /* QM_CHECKING */269dcbz_64(eqcr->cursor);270return eqcr->cursor;271}272273static __inline__ void qm_eqcr_abort(struct qm_portal *portal)274{275#ifdef QM_CHECKING276register struct qm_eqcr *eqcr = &portal->eqcr;277ASSERT_COND(eqcr->busy);278eqcr->busy = 0;279#else280UNUSED(portal);281#endif /* QM_CHECKING */282}283284static __inline__ struct qm_eqcr_entry *qm_eqcr_pend_and_next(struct qm_portal *portal, uint8_t myverb)285{286register struct qm_eqcr *eqcr = &portal->eqcr;287#ifdef QM_CHECKING288ASSERT_COND(eqcr->busy);289ASSERT_COND(eqcr->pmode != e_QmPortalPVB);290#endif /* QM_CHECKING */291if (eqcr->available == 1)292return NULL;293eqcr->cursor->__dont_write_directly__verb = (uint8_t)(myverb | eqcr->vbit);294dcbf_64(eqcr->cursor);295EQCR_INC(eqcr);296eqcr->available--;297dcbz_64(eqcr->cursor);298return eqcr->cursor;299}300301#ifdef QM_CHECKING302#define EQCR_COMMIT_CHECKS(eqcr) \303do { \304ASSERT_COND(eqcr->busy); \305ASSERT_COND(eqcr->cursor->orp == (eqcr->cursor->orp & 0x00ffffff)); \306ASSERT_COND(eqcr->cursor->fqid == (eqcr->cursor->fqid & 0x00ffffff)); \307} while(0)308309#else310#define EQCR_COMMIT_CHECKS(eqcr)311#endif /* QM_CHECKING */312313314static __inline__ void qmPortalEqcrPciCommit(struct qm_portal *portal, uint8_t myverb)315{316register struct qm_eqcr *eqcr = &portal->eqcr;317#ifdef QM_CHECKING318EQCR_COMMIT_CHECKS(eqcr);319ASSERT_COND(eqcr->pmode == e_QmPortalPCI);320#endif /* QM_CHECKING */321eqcr->cursor->__dont_write_directly__verb = (uint8_t)(myverb | eqcr->vbit);322EQCR_INC(eqcr);323eqcr->available--;324dcbf_64(eqcr->cursor);325mb();326qm_out(EQCR_PI_CINH, EQCR_PTR2IDX(eqcr->cursor));327#ifdef QM_CHECKING328eqcr->busy = 0;329#endif /* QM_CHECKING */330}331332static __inline__ void qmPortalEqcrPcePrefetch(struct qm_portal *portal)333{334#ifdef QM_CHECKING335register struct qm_eqcr *eqcr = &portal->eqcr;336ASSERT_COND(eqcr->pmode == e_QmPortalPCE);337#endif /* QM_CHECKING */338qm_cl_invalidate(EQCR_PI);339qm_cl_touch_rw(EQCR_PI);340}341342static __inline__ void qmPortalEqcrPceCommit(struct qm_portal *portal, uint8_t myverb)343{344register struct qm_eqcr *eqcr = &portal->eqcr;345#ifdef QM_CHECKING346EQCR_COMMIT_CHECKS(eqcr);347ASSERT_COND(eqcr->pmode == e_QmPortalPCE);348#endif /* QM_CHECKING */349eqcr->cursor->__dont_write_directly__verb = (uint8_t)(myverb | eqcr->vbit);350EQCR_INC(eqcr);351eqcr->available--;352dcbf_64(eqcr->cursor);353wmb();354qm_cl_out(EQCR_PI, EQCR_PTR2IDX(eqcr->cursor));355#ifdef QM_CHECKING356eqcr->busy = 0;357#endif /* QM_CHECKING */358}359360static __inline__ void qmPortalEqcrPvbCommit(struct qm_portal *portal, uint8_t myverb)361{362register struct qm_eqcr *eqcr = &portal->eqcr;363struct qm_eqcr_entry *eqcursor;364#ifdef QM_CHECKING365EQCR_COMMIT_CHECKS(eqcr);366ASSERT_COND(eqcr->pmode == e_QmPortalPVB);367#endif /* QM_CHECKING */368rmb();369eqcursor = eqcr->cursor;370eqcursor->__dont_write_directly__verb = (uint8_t)(myverb | eqcr->vbit);371dcbf_64(eqcursor);372EQCR_INC(eqcr);373eqcr->available--;374#ifdef QM_CHECKING375eqcr->busy = 0;376#endif /* QM_CHECKING */377}378379static __inline__ uint8_t qmPortalEqcrCciUpdate(struct qm_portal *portal)380{381register struct qm_eqcr *eqcr = &portal->eqcr;382uint8_t diff, old_ci = eqcr->ci;383#ifdef QM_CHECKING384ASSERT_COND(eqcr->cmode == e_QmPortalEqcrCCI);385#endif /* QM_CHECKING */386eqcr->ci = (uint8_t)(qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1));387diff = cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci);388eqcr->available += diff;389return diff;390}391392static __inline__ void qmPortalEqcrCcePrefetch(struct qm_portal *portal)393{394#ifdef QM_CHECKING395register struct qm_eqcr *eqcr = &portal->eqcr;396ASSERT_COND(eqcr->cmode == e_QmPortalEqcrCCE);397#endif /* QM_CHECKING */398qm_cl_touch_ro(EQCR_CI);399}400401static __inline__ uint8_t qmPortalEqcrCceUpdate(struct qm_portal *portal)402{403register struct qm_eqcr *eqcr = &portal->eqcr;404uint8_t diff, old_ci = eqcr->ci;405#ifdef QM_CHECKING406ASSERT_COND(eqcr->cmode == e_QmPortalEqcrCCE);407#endif /* QM_CHECKING */408eqcr->ci = (uint8_t)(qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1));409qm_cl_invalidate(EQCR_CI);410diff = cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci);411eqcr->available += diff;412return diff;413}414415static __inline__ uint8_t qm_eqcr_get_ithresh(struct qm_portal *portal)416{417register struct qm_eqcr *eqcr = &portal->eqcr;418return eqcr->ithresh;419}420421static __inline__ void qm_eqcr_set_ithresh(struct qm_portal *portal, uint8_t ithresh)422{423register struct qm_eqcr *eqcr = &portal->eqcr;424eqcr->ithresh = ithresh;425qm_out(EQCR_ITR, ithresh);426}427428static __inline__ uint8_t qm_eqcr_get_avail(struct qm_portal *portal)429{430register struct qm_eqcr *eqcr = &portal->eqcr;431return eqcr->available;432}433434static __inline__ uint8_t qm_eqcr_get_fill(struct qm_portal *portal)435{436register struct qm_eqcr *eqcr = &portal->eqcr;437return (uint8_t)(QM_EQCR_SIZE - 1 - eqcr->available);438}439440441442/* ---------------- */443/* --- DQRR API --- */444445/* TODO: many possible improvements;446* - look at changing the API to use pointer rather than index parameters now447* that 'cursor' is a pointer,448* - consider moving other parameters to pointer if it could help (ci)449*/450451/* It's safer to code in terms of the 'dqrr' object than the 'portal' object,452* because the latter runs the risk of copy-n-paste errors from other code where453* we could manipulate some other structure within 'portal'. */454/* #define DQRR_API_START() register struct qm_dqrr *dqrr = &portal->dqrr */455456#define DQRR_CARRYCLEAR(p) \457(void *)((uintptr_t)(p) & (~(uintptr_t)(QM_DQRR_SIZE << 6)))458459static __inline__ uint8_t DQRR_PTR2IDX(struct qm_dqrr_entry *e)460{461return (uint8_t)(((uintptr_t)e >> 6) & (QM_DQRR_SIZE - 1));462}463464static __inline__ struct qm_dqrr_entry *DQRR_INC(struct qm_dqrr_entry *e)465{466return DQRR_CARRYCLEAR(e + 1);467}468469static __inline__ void qm_dqrr_set_maxfill(struct qm_portal *portal, uint8_t mf)470{471qm_out(CFG, (qm_in(CFG) & 0xff0fffff) |472((mf & (QM_DQRR_SIZE - 1)) << 20));473}474475static __inline__ t_Error qm_dqrr_init(struct qm_portal *portal, e_QmPortalDequeueMode dmode,476e_QmPortalProduceMode pmode, e_QmPortalDqrrConsumeMode cmode,477uint8_t max_fill, int stash_ring, int stash_data)478{479register struct qm_dqrr *dqrr = &portal->dqrr;480const struct qm_portal_config *config = &portal->config;481uint32_t cfg;482483if (__qm_portal_bind(portal, QM_BIND_DQRR))484return ERROR_CODE(E_BUSY);485if ((stash_ring || stash_data) && (config->cpu == -1))486return ERROR_CODE(E_INVALID_STATE);487/* Make sure the DQRR will be idle when we enable */488qm_out(DQRR_SDQCR, 0);489qm_out(DQRR_VDQCR, 0);490qm_out(DQRR_PDQCR, 0);491dqrr->ring = ptr_ADD(portal->addr.addr_ce, CL_DQRR);492dqrr->pi = (uint8_t)(qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1));493dqrr->ci = (uint8_t)(qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1));494dqrr->cursor = dqrr->ring + dqrr->ci;495dqrr->fill = cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi);496dqrr->vbit = (uint8_t)((qm_in(DQRR_PI_CINH) & QM_DQRR_SIZE) ?497QM_DQRR_VERB_VBIT : 0);498dqrr->ithresh = (uint8_t)qm_in(DQRR_ITR);499500#ifdef QM_CHECKING501dqrr->dmode = dmode;502dqrr->pmode = pmode;503dqrr->cmode = cmode;504dqrr->flags = 0;505if (stash_ring)506dqrr->flags |= QM_DQRR_FLAG_RE;507if (stash_data)508dqrr->flags |= QM_DQRR_FLAG_SE;509#else510UNUSED(pmode);511#endif /* QM_CHECKING */512513cfg = (qm_in(CFG) & 0xff000f00) |514((max_fill & (QM_DQRR_SIZE - 1)) << 20) | /* DQRR_MF */515((dmode & 1) << 18) | /* DP */516((cmode & 3) << 16) | /* DCM */517(stash_ring ? 0x80 : 0) | /* RE */518(0 ? 0x40 : 0) | /* Ignore RP */519(stash_data ? 0x20 : 0) | /* SE */520(0 ? 0x10 : 0); /* Ignore SP */521qm_out(CFG, cfg);522return E_OK;523}524525526static __inline__ void qm_dqrr_finish(struct qm_portal *portal)527{528register struct qm_dqrr *dqrr = &portal->dqrr;529if (dqrr->ci != DQRR_PTR2IDX(dqrr->cursor))530REPORT_ERROR(WARNING, E_INVALID_STATE, ("Ignoring completed DQRR entries"));531__qm_portal_unbind(portal, QM_BIND_DQRR);532}533534static __inline__ struct qm_dqrr_entry *qm_dqrr_current(struct qm_portal *portal)535{536register struct qm_dqrr *dqrr = &portal->dqrr;537if (!dqrr->fill)538return NULL;539return dqrr->cursor;540}541542static __inline__ uint8_t qm_dqrr_cursor(struct qm_portal *portal)543{544register struct qm_dqrr *dqrr = &portal->dqrr;545return DQRR_PTR2IDX(dqrr->cursor);546}547548static __inline__ uint8_t qm_dqrr_next(struct qm_portal *portal)549{550register struct qm_dqrr *dqrr = &portal->dqrr;551#ifdef QM_CHECKING552ASSERT_COND(dqrr->fill);553#endif554dqrr->cursor = DQRR_INC(dqrr->cursor);555return --dqrr->fill;556}557558static __inline__ uint8_t qmPortalDqrrPciUpdate(struct qm_portal *portal)559{560register struct qm_dqrr *dqrr = &portal->dqrr;561uint8_t diff, old_pi = dqrr->pi;562#ifdef QM_CHECKING563ASSERT_COND(dqrr->pmode == e_QmPortalPCI);564#endif /* QM_CHECKING */565dqrr->pi = (uint8_t)(qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1));566diff = cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi);567dqrr->fill += diff;568return diff;569}570571static __inline__ void qmPortalDqrrPcePrefetch(struct qm_portal *portal)572{573#ifdef QM_CHECKING574register struct qm_dqrr *dqrr = &portal->dqrr;575ASSERT_COND(dqrr->pmode == e_QmPortalPCE);576#endif /* QM_CHECKING */577qm_cl_invalidate(DQRR_PI);578qm_cl_touch_ro(DQRR_PI);579}580581static __inline__ uint8_t qmPortalDqrrPceUpdate(struct qm_portal *portal)582{583register struct qm_dqrr *dqrr = &portal->dqrr;584uint8_t diff, old_pi = dqrr->pi;585#ifdef QM_CHECKING586ASSERT_COND(dqrr->pmode == e_QmPortalPCE);587#endif /* QM_CHECKING */588dqrr->pi = (uint8_t)(qm_cl_in(DQRR_PI) & (QM_DQRR_SIZE - 1));589diff = cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi);590dqrr->fill += diff;591return diff;592}593594static __inline__ void qmPortalDqrrPvbPrefetch(struct qm_portal *portal)595{596register struct qm_dqrr *dqrr = &portal->dqrr;597#ifdef QM_CHECKING598ASSERT_COND(dqrr->pmode == e_QmPortalPVB);599/* If ring entries get stashed, don't invalidate/prefetch */600if (!(dqrr->flags & QM_DQRR_FLAG_RE))601#endif /*QM_CHECKING */602dcbit_ro(ptr_ADD(dqrr->ring, qm_cl(dqrr->pi)));603}604605static __inline__ uint8_t qmPortalDqrrPvbUpdate(struct qm_portal *portal)606{607register struct qm_dqrr *dqrr = &portal->dqrr;608struct qm_dqrr_entry *res = ptr_ADD(dqrr->ring, qm_cl(dqrr->pi));609#ifdef QM_CHECKING610ASSERT_COND(dqrr->pmode == e_QmPortalPVB);611#endif /* QM_CHECKING */612if ((res->verb & QM_DQRR_VERB_VBIT) == dqrr->vbit) {613dqrr->pi = (uint8_t)((dqrr->pi + 1) & (QM_DQRR_SIZE - 1));614if (!dqrr->pi)615dqrr->vbit ^= QM_DQRR_VERB_VBIT;616dqrr->fill++;617return 1;618}619return 0;620}621622static __inline__ void qmPortalDqrrCciConsume(struct qm_portal *portal, uint8_t num)623{624register struct qm_dqrr *dqrr = &portal->dqrr;625#ifdef QM_CHECKING626ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCI);627#endif /* QM_CHECKING */628dqrr->ci = (uint8_t)((dqrr->ci + num) & (QM_DQRR_SIZE - 1));629qm_out(DQRR_CI_CINH, dqrr->ci);630}631632static __inline__ void qmPortalDqrrCciConsumeToCurrent(struct qm_portal *portal)633{634register struct qm_dqrr *dqrr = &portal->dqrr;635#ifdef QM_CHECKING636ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCI);637#endif /* QM_CHECKING */638dqrr->ci = DQRR_PTR2IDX(dqrr->cursor);639qm_out(DQRR_CI_CINH, dqrr->ci);640}641642static __inline__ void qmPortalDqrrCcePrefetch(struct qm_portal *portal)643{644#ifdef QM_CHECKING645register struct qm_dqrr *dqrr = &portal->dqrr;646ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCE);647#endif /* QM_CHECKING */648qm_cl_invalidate(DQRR_CI);649qm_cl_touch_rw(DQRR_CI);650}651652static __inline__ void qmPortalDqrrCceConsume(struct qm_portal *portal, uint8_t num)653{654register struct qm_dqrr *dqrr = &portal->dqrr;655#ifdef QM_CHECKING656ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCE);657#endif /* QM_CHECKING */658dqrr->ci = (uint8_t)((dqrr->ci + num) & (QM_DQRR_SIZE - 1));659qm_cl_out(DQRR_CI, dqrr->ci);660}661662static __inline__ void qmPortalDqrrCceConsume_to_current(struct qm_portal *portal)663{664register struct qm_dqrr *dqrr = &portal->dqrr;665#ifdef QM_CHECKING666ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCE);667#endif /* QM_CHECKING */668dqrr->ci = DQRR_PTR2IDX(dqrr->cursor);669qm_cl_out(DQRR_CI, dqrr->ci);670}671672static __inline__ void qmPortalDqrrDcaConsume1(struct qm_portal *portal, uint8_t idx, bool park)673{674#ifdef QM_CHECKING675register struct qm_dqrr *dqrr = &portal->dqrr;676ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA);677#endif /* QM_CHECKING */678ASSERT_COND(idx < QM_DQRR_SIZE);679qm_out(DQRR_DCAP, (0 << 8) | /* S */680((uint32_t)(park ? 1 : 0) << 6) | /* PK */681idx); /* DCAP_CI */682}683684static __inline__ void qmPortalDqrrDcaConsume1ptr(struct qm_portal *portal,685struct qm_dqrr_entry *dq,686bool park)687{688uint8_t idx = DQRR_PTR2IDX(dq);689#ifdef QM_CHECKING690register struct qm_dqrr *dqrr = &portal->dqrr;691692ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA);693ASSERT_COND((dqrr->ring + idx) == dq);694ASSERT_COND(idx < QM_DQRR_SIZE);695#endif /* QM_CHECKING */696qm_out(DQRR_DCAP, (0 << 8) | /* DQRR_DCAP::S */697((uint32_t)(park ? 1 : 0) << 6) | /* DQRR_DCAP::PK */698idx); /* DQRR_DCAP::DCAP_CI */699}700701static __inline__ void qmPortalDqrrDcaConsumeN(struct qm_portal *portal, uint16_t bitmask)702{703#ifdef QM_CHECKING704register struct qm_dqrr *dqrr = &portal->dqrr;705ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA);706#endif /* QM_CHECKING */707qm_out(DQRR_DCAP, (1 << 8) | /* DQRR_DCAP::S */708((uint32_t)bitmask << 16)); /* DQRR_DCAP::DCAP_CI */709}710711static __inline__ uint8_t qmPortalDqrrDcaCci(struct qm_portal *portal)712{713#ifdef QM_CHECKING714register struct qm_dqrr *dqrr = &portal->dqrr;715ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA);716#endif /* QM_CHECKING */717return (uint8_t)(qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1));718}719720static __inline__ void qmPortalDqrrDcaCcePrefetch(struct qm_portal *portal)721{722#ifdef QM_CHECKING723register struct qm_dqrr *dqrr = &portal->dqrr;724ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA);725#endif /* QM_CHECKING */726qm_cl_invalidate(DQRR_CI);727qm_cl_touch_ro(DQRR_CI);728}729730static __inline__ uint8_t qmPortalDqrrDcaCce(struct qm_portal *portal)731{732#ifdef QM_CHECKING733register struct qm_dqrr *dqrr = &portal->dqrr;734ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA);735#endif /* QM_CHECKING */736return (uint8_t)(qm_cl_in(DQRR_CI) & (QM_DQRR_SIZE - 1));737}738739static __inline__ uint8_t qm_dqrr_get_ci(struct qm_portal *portal)740{741register struct qm_dqrr *dqrr = &portal->dqrr;742#ifdef QM_CHECKING743ASSERT_COND(dqrr->cmode != e_QmPortalDqrrDCA);744#endif /* QM_CHECKING */745746return dqrr->ci;747}748749static __inline__ void qm_dqrr_park(struct qm_portal *portal, uint8_t idx)750{751#ifdef QM_CHECKING752register struct qm_dqrr *dqrr = &portal->dqrr;753ASSERT_COND(dqrr->cmode != e_QmPortalDqrrDCA);754#endif /* QM_CHECKING */755756qm_out(DQRR_DCAP, (0 << 8) | /* S */757(uint32_t)(1 << 6) | /* PK */758(idx & (QM_DQRR_SIZE - 1))); /* DCAP_CI */759}760761static __inline__ void qm_dqrr_park_ci(struct qm_portal *portal)762{763register struct qm_dqrr *dqrr = &portal->dqrr;764#ifdef QM_CHECKING765ASSERT_COND(dqrr->cmode != e_QmPortalDqrrDCA);766#endif /* QM_CHECKING */767qm_out(DQRR_DCAP, (0 << 8) | /* S */768(uint32_t)(1 << 6) | /* PK */769(dqrr->ci & (QM_DQRR_SIZE - 1)));/* DCAP_CI */770}771772static __inline__ void qm_dqrr_sdqcr_set(struct qm_portal *portal, uint32_t sdqcr)773{774qm_out(DQRR_SDQCR, sdqcr);775}776777static __inline__ uint32_t qm_dqrr_sdqcr_get(struct qm_portal *portal)778{779return qm_in(DQRR_SDQCR);780}781782static __inline__ void qm_dqrr_vdqcr_set(struct qm_portal *portal, uint32_t vdqcr)783{784qm_out(DQRR_VDQCR, vdqcr);785}786787static __inline__ uint32_t qm_dqrr_vdqcr_get(struct qm_portal *portal)788{789return qm_in(DQRR_VDQCR);790}791792static __inline__ void qm_dqrr_pdqcr_set(struct qm_portal *portal, uint32_t pdqcr)793{794qm_out(DQRR_PDQCR, pdqcr);795}796797static __inline__ uint32_t qm_dqrr_pdqcr_get(struct qm_portal *portal)798{799return qm_in(DQRR_PDQCR);800}801802static __inline__ uint8_t qm_dqrr_get_ithresh(struct qm_portal *portal)803{804register struct qm_dqrr *dqrr = &portal->dqrr;805return dqrr->ithresh;806}807808static __inline__ void qm_dqrr_set_ithresh(struct qm_portal *portal, uint8_t ithresh)809{810qm_out(DQRR_ITR, ithresh);811}812813static __inline__ uint8_t qm_dqrr_get_maxfill(struct qm_portal *portal)814{815return (uint8_t)((qm_in(CFG) & 0x00f00000) >> 20);816}817818/* -------------- */819/* --- MR API --- */820821/* It's safer to code in terms of the 'mr' object than the 'portal' object,822* because the latter runs the risk of copy-n-paste errors from other code where823* we could manipulate some other structure within 'portal'. */824/* #define MR_API_START() register struct qm_mr *mr = &portal->mr */825826#define MR_CARRYCLEAR(p) \827(void *)((uintptr_t)(p) & (~(uintptr_t)(QM_MR_SIZE << 6)))828829static __inline__ uint8_t MR_PTR2IDX(struct qm_mr_entry *e)830{831return (uint8_t)(((uintptr_t)e >> 6) & (QM_MR_SIZE - 1));832}833834static __inline__ struct qm_mr_entry *MR_INC(struct qm_mr_entry *e)835{836return MR_CARRYCLEAR(e + 1);837}838839static __inline__ t_Error qm_mr_init(struct qm_portal *portal, e_QmPortalProduceMode pmode,840e_QmPortalMrConsumeMode cmode)841{842register struct qm_mr *mr = &portal->mr;843uint32_t cfg;844845if (__qm_portal_bind(portal, QM_BIND_MR))846return ERROR_CODE(E_BUSY);847mr->ring = ptr_ADD(portal->addr.addr_ce, CL_MR);848mr->pi = (uint8_t)(qm_in(MR_PI_CINH) & (QM_MR_SIZE - 1));849mr->ci = (uint8_t)(qm_in(MR_CI_CINH) & (QM_MR_SIZE - 1));850mr->cursor = mr->ring + mr->ci;851mr->fill = cyc_diff(QM_MR_SIZE, mr->ci, mr->pi);852mr->vbit = (uint8_t)((qm_in(MR_PI_CINH) & QM_MR_SIZE) ?QM_MR_VERB_VBIT : 0);853mr->ithresh = (uint8_t)qm_in(MR_ITR);854855#ifdef QM_CHECKING856mr->pmode = pmode;857mr->cmode = cmode;858#else859UNUSED(pmode);860#endif /* QM_CHECKING */861cfg = (qm_in(CFG) & 0xfffff0ff) |862((cmode & 1) << 8); /* QCSP_CFG:MM */863qm_out(CFG, cfg);864return E_OK;865}866867868static __inline__ void qm_mr_finish(struct qm_portal *portal)869{870register struct qm_mr *mr = &portal->mr;871if (mr->ci != MR_PTR2IDX(mr->cursor))872REPORT_ERROR(WARNING, E_INVALID_STATE, ("Ignoring completed MR entries"));873__qm_portal_unbind(portal, QM_BIND_MR);874}875876static __inline__ void qm_mr_current_prefetch(struct qm_portal *portal)877{878register struct qm_mr *mr = &portal->mr;879dcbt_ro(mr->cursor);880}881882static __inline__ struct qm_mr_entry *qm_mr_current(struct qm_portal *portal)883{884register struct qm_mr *mr = &portal->mr;885if (!mr->fill)886return NULL;887return mr->cursor;888}889890static __inline__ uint8_t qm_mr_cursor(struct qm_portal *portal)891{892register struct qm_mr *mr = &portal->mr;893return MR_PTR2IDX(mr->cursor);894}895896static __inline__ uint8_t qm_mr_next(struct qm_portal *portal)897{898register struct qm_mr *mr = &portal->mr;899#ifdef QM_CHECKING900ASSERT_COND(mr->fill);901#endif /* QM_CHECKING */902mr->cursor = MR_INC(mr->cursor);903return --mr->fill;904}905906static __inline__ uint8_t qmPortalMrPciUpdate(struct qm_portal *portal)907{908register struct qm_mr *mr = &portal->mr;909uint8_t diff, old_pi = mr->pi;910#ifdef QM_CHECKING911ASSERT_COND(mr->pmode == e_QmPortalPCI);912#endif /* QM_CHECKING */913mr->pi = (uint8_t)qm_in(MR_PI_CINH);914diff = cyc_diff(QM_MR_SIZE, old_pi, mr->pi);915mr->fill += diff;916return diff;917}918919static __inline__ void qmPortalMrPcePrefetch(struct qm_portal *portal)920{921#ifdef QM_CHECKING922register struct qm_mr *mr = &portal->mr;923ASSERT_COND(mr->pmode == e_QmPortalPCE);924#endif /* QM_CHECKING */925qm_cl_invalidate(MR_PI);926qm_cl_touch_ro(MR_PI);927}928929static __inline__ uint8_t qmPortalMrPceUpdate(struct qm_portal *portal)930{931register struct qm_mr *mr = &portal->mr;932uint8_t diff, old_pi = mr->pi;933#ifdef QM_CHECKING934ASSERT_COND(mr->pmode == e_QmPortalPCE);935#endif /* QM_CHECKING */936mr->pi = (uint8_t)(qm_cl_in(MR_PI) & (QM_MR_SIZE - 1));937diff = cyc_diff(QM_MR_SIZE, old_pi, mr->pi);938mr->fill += diff;939return diff;940}941942static __inline__ void qmPortalMrPvbUpdate(struct qm_portal *portal)943{944register struct qm_mr *mr = &portal->mr;945struct qm_mr_entry *res = ptr_ADD(mr->ring, qm_cl(mr->pi));946#ifdef QM_CHECKING947ASSERT_COND(mr->pmode == e_QmPortalPVB);948#endif /* QM_CHECKING */949dcbit_ro(ptr_ADD(mr->ring, qm_cl(mr->pi)));950if ((res->verb & QM_MR_VERB_VBIT) == mr->vbit) {951mr->pi = (uint8_t)((mr->pi + 1) & (QM_MR_SIZE - 1));952if (!mr->pi)953mr->vbit ^= QM_MR_VERB_VBIT;954mr->fill++;955}956}957958static __inline__ void qmPortalMrCciConsume(struct qm_portal *portal, uint8_t num)959{960register struct qm_mr *mr = &portal->mr;961#ifdef QM_CHECKING962ASSERT_COND(mr->cmode == e_QmPortalMrCCI);963#endif /* QM_CHECKING */964mr->ci = (uint8_t)((mr->ci + num) & (QM_MR_SIZE - 1));965qm_out(MR_CI_CINH, mr->ci);966}967968static __inline__ void qmPortalMrCciConsumeToCurrent(struct qm_portal *portal)969{970register struct qm_mr *mr = &portal->mr;971#ifdef QM_CHECKING972ASSERT_COND(mr->cmode == e_QmPortalMrCCI);973#endif /* QM_CHECKING */974mr->ci = MR_PTR2IDX(mr->cursor);975qm_out(MR_CI_CINH, mr->ci);976}977978static __inline__ void qmPortalMrCcePrefetch(struct qm_portal *portal)979{980#ifdef QM_CHECKING981register struct qm_mr *mr = &portal->mr;982ASSERT_COND(mr->cmode == e_QmPortalMrCCE);983#endif /* QM_CHECKING */984qm_cl_invalidate(MR_CI);985qm_cl_touch_rw(MR_CI);986}987988static __inline__ void qmPortalMrCceConsume(struct qm_portal *portal, uint8_t num)989{990register struct qm_mr *mr = &portal->mr;991#ifdef QM_CHECKING992ASSERT_COND(mr->cmode == e_QmPortalMrCCE);993#endif /* QM_CHECKING */994mr->ci = (uint8_t)((mr->ci + num) & (QM_MR_SIZE - 1));995qm_cl_out(MR_CI, mr->ci);996}997998static __inline__ void qmPortalMrCceConsumeToCurrent(struct qm_portal *portal)999{1000register struct qm_mr *mr = &portal->mr;1001#ifdef QM_CHECKING1002ASSERT_COND(mr->cmode == e_QmPortalMrCCE);1003#endif /* QM_CHECKING */1004mr->ci = MR_PTR2IDX(mr->cursor);1005qm_cl_out(MR_CI, mr->ci);1006}10071008static __inline__ uint8_t qm_mr_get_ci(struct qm_portal *portal)1009{1010register struct qm_mr *mr = &portal->mr;1011return mr->ci;1012}10131014static __inline__ uint8_t qm_mr_get_ithresh(struct qm_portal *portal)1015{1016register struct qm_mr *mr = &portal->mr;1017return mr->ithresh;1018}10191020static __inline__ void qm_mr_set_ithresh(struct qm_portal *portal, uint8_t ithresh)1021{1022qm_out(MR_ITR, ithresh);1023}10241025/* ------------------------------ */1026/* --- Management command API --- */10271028/* It's safer to code in terms of the 'mc' object than the 'portal' object,1029* because the latter runs the risk of copy-n-paste errors from other code where1030* we could manipulate some other structure within 'portal'. */1031/* #define MC_API_START() register struct qm_mc *mc = &portal->mc */10321033static __inline__ t_Error qm_mc_init(struct qm_portal *portal)1034{1035register struct qm_mc *mc = &portal->mc;1036if (__qm_portal_bind(portal, QM_BIND_MC))1037return ERROR_CODE(E_BUSY);1038mc->cr = ptr_ADD(portal->addr.addr_ce, CL_CR);1039mc->rr = ptr_ADD(portal->addr.addr_ce, CL_RR0);1040mc->rridx = (uint8_t)((mc->cr->__dont_write_directly__verb & QM_MCC_VERB_VBIT) ?10410 : 1);1042mc->vbit = (uint8_t)(mc->rridx ? QM_MCC_VERB_VBIT : 0);1043#ifdef QM_CHECKING1044mc->state = mc_idle;1045#endif /* QM_CHECKING */1046return E_OK;1047}10481049static __inline__ void qm_mc_finish(struct qm_portal *portal)1050{1051#ifdef QM_CHECKING1052register struct qm_mc *mc = &portal->mc;1053ASSERT_COND(mc->state == mc_idle);1054if (mc->state != mc_idle)1055REPORT_ERROR(WARNING, E_INVALID_STATE, ("Losing incomplete MC command"));1056#endif /* QM_CHECKING */1057__qm_portal_unbind(portal, QM_BIND_MC);1058}10591060static __inline__ struct qm_mc_command *qm_mc_start(struct qm_portal *portal)1061{1062register struct qm_mc *mc = &portal->mc;1063#ifdef QM_CHECKING1064ASSERT_COND(mc->state == mc_idle);1065mc->state = mc_user;1066#endif /* QM_CHECKING */1067dcbz_64(mc->cr);1068return mc->cr;1069}10701071static __inline__ void qm_mc_abort(struct qm_portal *portal)1072{1073#ifdef QM_CHECKING1074register struct qm_mc *mc = &portal->mc;1075ASSERT_COND(mc->state == mc_user);1076mc->state = mc_idle;1077#else1078UNUSED(portal);1079#endif /* QM_CHECKING */1080}10811082static __inline__ void qm_mc_commit(struct qm_portal *portal, uint8_t myverb)1083{1084register struct qm_mc *mc = &portal->mc;1085#ifdef QM_CHECKING1086ASSERT_COND(mc->state == mc_user);1087#endif /* QM_CHECKING */1088rmb();1089mc->cr->__dont_write_directly__verb = (uint8_t)(myverb | mc->vbit);1090dcbf_64(mc->cr);1091dcbit_ro(mc->rr + mc->rridx);1092#ifdef QM_CHECKING1093mc->state = mc_hw;1094#endif /* QM_CHECKING */1095}10961097static __inline__ struct qm_mc_result *qm_mc_result(struct qm_portal *portal)1098{1099register struct qm_mc *mc = &portal->mc;1100struct qm_mc_result *rr = mc->rr + mc->rridx;1101#ifdef QM_CHECKING1102ASSERT_COND(mc->state == mc_hw);1103#endif /* QM_CHECKING */1104/* The inactive response register's verb byte always returns zero until1105* its command is submitted and completed. This includes the valid-bit,1106* in case you were wondering... */1107if (!rr->verb) {1108dcbit_ro(rr);1109return NULL;1110}1111mc->rridx ^= 1;1112mc->vbit ^= QM_MCC_VERB_VBIT;1113#ifdef QM_CHECKING1114mc->state = mc_idle;1115#endif /* QM_CHECKING */1116return rr;1117}11181119/* ------------------------------------- */1120/* --- Portal interrupt register API --- */11211122static __inline__ t_Error qm_isr_init(struct qm_portal *portal)1123{1124if (__qm_portal_bind(portal, QM_BIND_ISR))1125return ERROR_CODE(E_BUSY);1126return E_OK;1127}11281129static __inline__ void qm_isr_finish(struct qm_portal *portal)1130{1131__qm_portal_unbind(portal, QM_BIND_ISR);1132}11331134static __inline__ void qm_isr_set_iperiod(struct qm_portal *portal, uint16_t iperiod)1135{1136qm_out(ITPR, iperiod);1137}11381139static __inline__ uint32_t __qm_isr_read(struct qm_portal *portal, enum qm_isr_reg n)1140{1141return __qm_in(&portal->addr, REG_ISR + (n << 2));1142}11431144static __inline__ void __qm_isr_write(struct qm_portal *portal, enum qm_isr_reg n, uint32_t val)1145{1146__qm_out(&portal->addr, REG_ISR + (n << 2), val);1147}114811491150