diff options
Diffstat (limited to 'sys/contrib/ncsw/Peripherals/QM/qman_low.h')
-rw-r--r-- | sys/contrib/ncsw/Peripherals/QM/qman_low.h | 1148 |
1 files changed, 1148 insertions, 0 deletions
diff --git a/sys/contrib/ncsw/Peripherals/QM/qman_low.h b/sys/contrib/ncsw/Peripherals/QM/qman_low.h new file mode 100644 index 0000000..ea00514 --- /dev/null +++ b/sys/contrib/ncsw/Peripherals/QM/qman_low.h @@ -0,0 +1,1148 @@ +/****************************************************************************** + + © 1995-2003, 2004, 2005-2011 Freescale Semiconductor, Inc. + All rights reserved. + + This is proprietary source code of Freescale Semiconductor Inc., + and its use is subject to the NetComm Device Drivers EULA. + The copyright notice above does not evidence any actual or intended + publication of such source code. + + ALTERNATIVELY, redistribution and use in source and binary forms, with + or without modification, are permitted provided that the following + conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Freescale Semiconductor nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + + **************************************************************************/ +/****************************************************************************** + @File qman_low.c + + @Description QM Low-level implementation +*//***************************************************************************/ +#include "std_ext.h" +#include "core_ext.h" +#include "xx_ext.h" +#include "error_ext.h" + +#include "qman_private.h" + + +/***************************/ +/* Portal register assists */ +/***************************/ + +/* Cache-inhibited register offsets */ +#define REG_EQCR_PI_CINH (void *)0x0000 +#define REG_EQCR_CI_CINH (void *)0x0004 +#define REG_EQCR_ITR (void *)0x0008 +#define REG_DQRR_PI_CINH (void *)0x0040 +#define REG_DQRR_CI_CINH (void *)0x0044 +#define REG_DQRR_ITR (void *)0x0048 +#define REG_DQRR_DCAP (void *)0x0050 +#define REG_DQRR_SDQCR (void *)0x0054 +#define REG_DQRR_VDQCR (void *)0x0058 +#define REG_DQRR_PDQCR (void *)0x005c +#define REG_MR_PI_CINH (void *)0x0080 +#define REG_MR_CI_CINH (void *)0x0084 +#define REG_MR_ITR (void *)0x0088 +#define REG_CFG (void *)0x0100 +#define REG_ISR (void *)0x0e00 +#define REG_IER (void *)0x0e04 +#define REG_ISDR (void *)0x0e08 +#define REG_IIR (void *)0x0e0c +#define REG_ITPR (void *)0x0e14 + +/* Cache-enabled register offsets */ +#define CL_EQCR (void *)0x0000 +#define CL_DQRR (void *)0x1000 +#define CL_MR (void *)0x2000 +#define CL_EQCR_PI_CENA (void *)0x3000 +#define CL_EQCR_CI_CENA (void *)0x3100 +#define CL_DQRR_PI_CENA (void *)0x3200 +#define CL_DQRR_CI_CENA (void *)0x3300 +#define CL_MR_PI_CENA (void *)0x3400 +#define CL_MR_CI_CENA (void *)0x3500 +#define CL_RORI_CENA (void *)0x3600 +#define CL_CR (void *)0x3800 +#define CL_RR0 (void *)0x3900 +#define CL_RR1 (void *)0x3940 + +static __inline__ void *ptr_ADD(void *a, void *b) +{ + return (void *)((uintptr_t)a + (uintptr_t)b); +} + +/* The h/w design requires mappings to be size-aligned so that "add"s can be + * reduced to "or"s. The primitives below do the same for s/w. */ +/* Bitwise-OR two pointers */ +static __inline__ void *ptr_OR(void *a, void *b) +{ + return (void *)((uintptr_t)a + (uintptr_t)b); +} + +/* Cache-inhibited register access */ +static __inline__ uint32_t __qm_in(struct qm_addr *qm, void *offset) +{ + uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ci, offset); + return GET_UINT32(*tmp); +} +static __inline__ void __qm_out(struct qm_addr *qm, void *offset, uint32_t val) +{ + uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ci, offset); + WRITE_UINT32(*tmp, val); +} +#define qm_in(reg) __qm_in(&portal->addr, REG_##reg) +#define qm_out(reg, val) __qm_out(&portal->addr, REG_##reg, (uint32_t)val) + +/* Convert 'n' cachelines to a pointer value for bitwise OR */ +#define qm_cl(n) (void *)((n) << 6) + +/* Cache-enabled (index) register access */ +static __inline__ void __qm_cl_touch_ro(struct qm_addr *qm, void *offset) +{ + dcbt_ro(ptr_ADD(qm->addr_ce, offset)); +} +static __inline__ void __qm_cl_touch_rw(struct qm_addr *qm, void *offset) +{ + dcbt_rw(ptr_ADD(qm->addr_ce, offset)); +} +static __inline__ uint32_t __qm_cl_in(struct qm_addr *qm, void *offset) +{ + uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ce, offset); + return GET_UINT32(*tmp); +} +static __inline__ void __qm_cl_out(struct qm_addr *qm, void *offset, uint32_t val) +{ + uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ce, offset); + WRITE_UINT32(*tmp, val); + dcbf(tmp); +} +static __inline__ void __qm_cl_invalidate(struct qm_addr *qm, void *offset) +{ + dcbi(ptr_ADD(qm->addr_ce, offset)); +} +#define qm_cl_touch_ro(reg) __qm_cl_touch_ro(&portal->addr, CL_##reg##_CENA) +#define qm_cl_touch_rw(reg) __qm_cl_touch_rw(&portal->addr, CL_##reg##_CENA) +#define qm_cl_in(reg) __qm_cl_in(&portal->addr, CL_##reg##_CENA) +#define qm_cl_out(reg, val) __qm_cl_out(&portal->addr, CL_##reg##_CENA, val) +#define qm_cl_invalidate(reg) __qm_cl_invalidate(&portal->addr, CL_##reg##_CENA) + +/* Cyclic helper for rings. TODO: once we are able to do fine-grain perf + * analysis, look at using the "extra" bit in the ring index registers to avoid + * cyclic issues. */ +static __inline__ uint8_t cyc_diff(uint8_t ringsize, uint8_t first, uint8_t last) +{ + /* 'first' is included, 'last' is excluded */ + if (first <= last) + return (uint8_t)(last - first); + return (uint8_t)(ringsize + last - first); +} + +static __inline__ t_Error __qm_portal_bind(struct qm_portal *portal, uint8_t iface) +{ + t_Error ret = E_BUSY; + if (!(portal->config.bound & iface)) { + portal->config.bound |= iface; + ret = E_OK; + } + return ret; +} + +static __inline__ void __qm_portal_unbind(struct qm_portal *portal, uint8_t iface) +{ +#ifdef QM_CHECKING + ASSERT_COND(portal->config.bound & iface); +#endif /* QM_CHECKING */ + portal->config.bound &= ~iface; +} + +/* ---------------- */ +/* --- EQCR API --- */ + +/* It's safer to code in terms of the 'eqcr' object than the 'portal' object, + * because the latter runs the risk of copy-n-paste errors from other code where + * we could manipulate some other structure within 'portal'. */ +/* #define EQCR_API_START() register struct qm_eqcr *eqcr = &portal->eqcr */ + +/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */ +#define EQCR_CARRYCLEAR(p) \ + (void *)((uintptr_t)(p) & (~(uintptr_t)(QM_EQCR_SIZE << 6))) + +/* Bit-wise logic to convert a ring pointer to a ring index */ +static __inline__ uint8_t EQCR_PTR2IDX(struct qm_eqcr_entry *e) +{ + return (uint8_t)(((uint32_t)e >> 6) & (QM_EQCR_SIZE - 1)); +} + +/* Increment the 'cursor' ring pointer, taking 'vbit' into account */ +static __inline__ void EQCR_INC(struct qm_eqcr *eqcr) +{ + /* NB: this is odd-looking, but experiments show that it generates fast + * code with essentially no branching overheads. We increment to the + * next EQCR pointer and handle overflow and 'vbit'. */ + struct qm_eqcr_entry *partial = eqcr->cursor + 1; + eqcr->cursor = EQCR_CARRYCLEAR(partial); + if (partial != eqcr->cursor) + eqcr->vbit ^= QM_EQCR_VERB_VBIT; +} + +static __inline__ t_Error qm_eqcr_init(struct qm_portal *portal, e_QmPortalProduceMode pmode, + e_QmPortalEqcrConsumeMode cmode) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + uint32_t cfg; + uint8_t pi; + + if (__qm_portal_bind(portal, QM_BIND_EQCR)) + return ERROR_CODE(E_BUSY); + eqcr->ring = ptr_ADD(portal->addr.addr_ce, CL_EQCR); + eqcr->ci = (uint8_t)(qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1)); + qm_cl_invalidate(EQCR_CI); + pi = (uint8_t)(qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1)); + eqcr->cursor = eqcr->ring + pi; + eqcr->vbit = (uint8_t)((qm_in(EQCR_PI_CINH) & QM_EQCR_SIZE) ? + QM_EQCR_VERB_VBIT : 0); + eqcr->available = (uint8_t)(QM_EQCR_SIZE - 1 - + cyc_diff(QM_EQCR_SIZE, eqcr->ci, pi)); + eqcr->ithresh = (uint8_t)qm_in(EQCR_ITR); + +#ifdef QM_CHECKING + eqcr->busy = 0; + eqcr->pmode = pmode; + eqcr->cmode = cmode; +#else + UNUSED(cmode); +#endif /* QM_CHECKING */ + cfg = (qm_in(CFG) & 0x00ffffff) | + ((pmode & 0x3) << 24); /* QCSP_CFG::EPM */ + qm_out(CFG, cfg); + return 0; +} + +static __inline__ void qm_eqcr_finish(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + uint8_t pi = (uint8_t)(qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1)); + uint8_t ci = (uint8_t)(qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1)); + +#ifdef QM_CHECKING + ASSERT_COND(!eqcr->busy); +#endif /* QM_CHECKING */ + if (pi != EQCR_PTR2IDX(eqcr->cursor)) + REPORT_ERROR(WARNING, E_INVALID_STATE, ("losing uncommitted EQCR entries")); + if (ci != eqcr->ci) + REPORT_ERROR(WARNING, E_INVALID_STATE, ("missing existing EQCR completions")); + if (eqcr->ci != EQCR_PTR2IDX(eqcr->cursor)) + REPORT_ERROR(WARNING, E_INVALID_STATE, ("EQCR destroyed unquiesced")); + __qm_portal_unbind(portal, QM_BIND_EQCR); +} + +static __inline__ struct qm_eqcr_entry *qm_eqcr_start(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; +#ifdef QM_CHECKING + ASSERT_COND(!eqcr->busy); +#endif /* QM_CHECKING */ + if (!eqcr->available) + return NULL; +#ifdef QM_CHECKING + eqcr->busy = 1; +#endif /* QM_CHECKING */ + dcbz_64(eqcr->cursor); + return eqcr->cursor; +} + +static __inline__ void qm_eqcr_abort(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_eqcr *eqcr = &portal->eqcr; + ASSERT_COND(eqcr->busy); + eqcr->busy = 0; +#else + UNUSED(portal); +#endif /* QM_CHECKING */ +} + +static __inline__ struct qm_eqcr_entry *qm_eqcr_pend_and_next(struct qm_portal *portal, uint8_t myverb) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; +#ifdef QM_CHECKING + ASSERT_COND(eqcr->busy); + ASSERT_COND(eqcr->pmode != e_QmPortalPVB); +#endif /* QM_CHECKING */ + if (eqcr->available == 1) + return NULL; + eqcr->cursor->__dont_write_directly__verb = (uint8_t)(myverb | eqcr->vbit); + dcbf_64(eqcr->cursor); + EQCR_INC(eqcr); + eqcr->available--; + dcbz_64(eqcr->cursor); + return eqcr->cursor; +} + +#ifdef QM_CHECKING +#define EQCR_COMMIT_CHECKS(eqcr) \ +do { \ + ASSERT_COND(eqcr->busy); \ + ASSERT_COND(eqcr->cursor->orp == (eqcr->cursor->orp & 0x00ffffff)); \ + ASSERT_COND(eqcr->cursor->fqid == (eqcr->cursor->fqid & 0x00ffffff)); \ +} while(0) + +#else +#define EQCR_COMMIT_CHECKS(eqcr) +#endif /* QM_CHECKING */ + + +static __inline__ void qmPortalEqcrPciCommit(struct qm_portal *portal, uint8_t myverb) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; +#ifdef QM_CHECKING + EQCR_COMMIT_CHECKS(eqcr); + ASSERT_COND(eqcr->pmode == e_QmPortalPCI); +#endif /* QM_CHECKING */ + eqcr->cursor->__dont_write_directly__verb = (uint8_t)(myverb | eqcr->vbit); + EQCR_INC(eqcr); + eqcr->available--; + dcbf_64(eqcr->cursor); + hwsync(); + qm_out(EQCR_PI_CINH, EQCR_PTR2IDX(eqcr->cursor)); +#ifdef QM_CHECKING + eqcr->busy = 0; +#endif /* QM_CHECKING */ +} + +static __inline__ void qmPortalEqcrPcePrefetch(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_eqcr *eqcr = &portal->eqcr; + ASSERT_COND(eqcr->pmode == e_QmPortalPCE); +#endif /* QM_CHECKING */ + qm_cl_invalidate(EQCR_PI); + qm_cl_touch_rw(EQCR_PI); +} + +static __inline__ void qmPortalEqcrPceCommit(struct qm_portal *portal, uint8_t myverb) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; +#ifdef QM_CHECKING + EQCR_COMMIT_CHECKS(eqcr); + ASSERT_COND(eqcr->pmode == e_QmPortalPCE); +#endif /* QM_CHECKING */ + eqcr->cursor->__dont_write_directly__verb = (uint8_t)(myverb | eqcr->vbit); + EQCR_INC(eqcr); + eqcr->available--; + dcbf_64(eqcr->cursor); + lwsync(); + qm_cl_out(EQCR_PI, EQCR_PTR2IDX(eqcr->cursor)); +#ifdef QM_CHECKING + eqcr->busy = 0; +#endif /* QM_CHECKING */ +} + +static __inline__ void qmPortalEqcrPvbCommit(struct qm_portal *portal, uint8_t myverb) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + struct qm_eqcr_entry *eqcursor; +#ifdef QM_CHECKING + EQCR_COMMIT_CHECKS(eqcr); + ASSERT_COND(eqcr->pmode == e_QmPortalPVB); +#endif /* QM_CHECKING */ + lwsync(); + eqcursor = eqcr->cursor; + eqcursor->__dont_write_directly__verb = (uint8_t)(myverb | eqcr->vbit); + dcbf_64(eqcursor); + EQCR_INC(eqcr); + eqcr->available--; +#ifdef QM_CHECKING + eqcr->busy = 0; +#endif /* QM_CHECKING */ +} + +static __inline__ uint8_t qmPortalEqcrCciUpdate(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + uint8_t diff, old_ci = eqcr->ci; +#ifdef QM_CHECKING + ASSERT_COND(eqcr->cmode == e_QmPortalEqcrCCI); +#endif /* QM_CHECKING */ + eqcr->ci = (uint8_t)(qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1)); + diff = cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci); + eqcr->available += diff; + return diff; +} + +static __inline__ void qmPortalEqcrCcePrefetch(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_eqcr *eqcr = &portal->eqcr; + ASSERT_COND(eqcr->cmode == e_QmPortalEqcrCCE); +#endif /* QM_CHECKING */ + qm_cl_touch_ro(EQCR_CI); +} + +static __inline__ uint8_t qmPortalEqcrCceUpdate(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + uint8_t diff, old_ci = eqcr->ci; +#ifdef QM_CHECKING + ASSERT_COND(eqcr->cmode == e_QmPortalEqcrCCE); +#endif /* QM_CHECKING */ + eqcr->ci = (uint8_t)(qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1)); + qm_cl_invalidate(EQCR_CI); + diff = cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci); + eqcr->available += diff; + return diff; +} + +static __inline__ uint8_t qm_eqcr_get_ithresh(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + return eqcr->ithresh; +} + +static __inline__ void qm_eqcr_set_ithresh(struct qm_portal *portal, uint8_t ithresh) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + eqcr->ithresh = ithresh; + qm_out(EQCR_ITR, ithresh); +} + +static __inline__ uint8_t qm_eqcr_get_avail(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + return eqcr->available; +} + +static __inline__ uint8_t qm_eqcr_get_fill(struct qm_portal *portal) +{ + register struct qm_eqcr *eqcr = &portal->eqcr; + return (uint8_t)(QM_EQCR_SIZE - 1 - eqcr->available); +} + + + +/* ---------------- */ +/* --- DQRR API --- */ + +/* TODO: many possible improvements; + * - look at changing the API to use pointer rather than index parameters now + * that 'cursor' is a pointer, + * - consider moving other parameters to pointer if it could help (ci) + */ + +/* It's safer to code in terms of the 'dqrr' object than the 'portal' object, + * because the latter runs the risk of copy-n-paste errors from other code where + * we could manipulate some other structure within 'portal'. */ +/* #define DQRR_API_START() register struct qm_dqrr *dqrr = &portal->dqrr */ + +#define DQRR_CARRYCLEAR(p) \ + (void *)((uintptr_t)(p) & (~(uintptr_t)(QM_DQRR_SIZE << 6))) + +static __inline__ uint8_t DQRR_PTR2IDX(struct qm_dqrr_entry *e) +{ + return (uint8_t)(((uint32_t)e >> 6) & (QM_DQRR_SIZE - 1)); +} + +static __inline__ struct qm_dqrr_entry *DQRR_INC(struct qm_dqrr_entry *e) +{ + return DQRR_CARRYCLEAR(e + 1); +} + +static __inline__ void qm_dqrr_set_maxfill(struct qm_portal *portal, uint8_t mf) +{ + qm_out(CFG, (qm_in(CFG) & 0xff0fffff) | + ((mf & (QM_DQRR_SIZE - 1)) << 20)); +} + +static __inline__ t_Error qm_dqrr_init(struct qm_portal *portal, e_QmPortalDequeueMode dmode, + e_QmPortalProduceMode pmode, e_QmPortalDqrrConsumeMode cmode, + uint8_t max_fill, int stash_ring, int stash_data) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + const struct qm_portal_config *config = &portal->config; + uint32_t cfg; + + if (__qm_portal_bind(portal, QM_BIND_DQRR)) + return ERROR_CODE(E_BUSY); + if ((stash_ring || stash_data) && (config->cpu == -1)) + return ERROR_CODE(E_INVALID_STATE); + /* Make sure the DQRR will be idle when we enable */ + qm_out(DQRR_SDQCR, 0); + qm_out(DQRR_VDQCR, 0); + qm_out(DQRR_PDQCR, 0); + dqrr->ring = ptr_ADD(portal->addr.addr_ce, CL_DQRR); + dqrr->pi = (uint8_t)(qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1)); + dqrr->ci = (uint8_t)(qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1)); + dqrr->cursor = dqrr->ring + dqrr->ci; + dqrr->fill = cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi); + dqrr->vbit = (uint8_t)((qm_in(DQRR_PI_CINH) & QM_DQRR_SIZE) ? + QM_DQRR_VERB_VBIT : 0); + dqrr->ithresh = (uint8_t)qm_in(DQRR_ITR); + +#ifdef QM_CHECKING + dqrr->dmode = dmode; + dqrr->pmode = pmode; + dqrr->cmode = cmode; + dqrr->flags = 0; + if (stash_ring) + dqrr->flags |= QM_DQRR_FLAG_RE; + if (stash_data) + dqrr->flags |= QM_DQRR_FLAG_SE; +#else + UNUSED(pmode); +#endif /* QM_CHECKING */ + + cfg = (qm_in(CFG) & 0xff000f00) | + ((max_fill & (QM_DQRR_SIZE - 1)) << 20) | /* DQRR_MF */ + ((dmode & 1) << 18) | /* DP */ + ((cmode & 3) << 16) | /* DCM */ + (stash_ring ? 0x80 : 0) | /* RE */ + (0 ? 0x40 : 0) | /* Ignore RP */ + (stash_data ? 0x20 : 0) | /* SE */ + (0 ? 0x10 : 0); /* Ignore SP */ + qm_out(CFG, cfg); + return E_OK; +} + + +static __inline__ void qm_dqrr_finish(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + if (dqrr->ci != DQRR_PTR2IDX(dqrr->cursor)) + REPORT_ERROR(WARNING, E_INVALID_STATE, ("Ignoring completed DQRR entries")); + __qm_portal_unbind(portal, QM_BIND_DQRR); +} + +static __inline__ struct qm_dqrr_entry *qm_dqrr_current(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + if (!dqrr->fill) + return NULL; + return dqrr->cursor; +} + +static __inline__ uint8_t qm_dqrr_cursor(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + return DQRR_PTR2IDX(dqrr->cursor); +} + +static __inline__ uint8_t qm_dqrr_next(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->fill); +#endif + dqrr->cursor = DQRR_INC(dqrr->cursor); + return --dqrr->fill; +} + +static __inline__ uint8_t qmPortalDqrrPciUpdate(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + uint8_t diff, old_pi = dqrr->pi; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->pmode == e_QmPortalPCI); +#endif /* QM_CHECKING */ + dqrr->pi = (uint8_t)(qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1)); + diff = cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi); + dqrr->fill += diff; + return diff; +} + +static __inline__ void qmPortalDqrrPcePrefetch(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_dqrr *dqrr = &portal->dqrr; + ASSERT_COND(dqrr->pmode == e_QmPortalPCE); +#endif /* QM_CHECKING */ + qm_cl_invalidate(DQRR_PI); + qm_cl_touch_ro(DQRR_PI); +} + +static __inline__ uint8_t qmPortalDqrrPceUpdate(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + uint8_t diff, old_pi = dqrr->pi; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->pmode == e_QmPortalPCE); +#endif /* QM_CHECKING */ + dqrr->pi = (uint8_t)(qm_cl_in(DQRR_PI) & (QM_DQRR_SIZE - 1)); + diff = cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi); + dqrr->fill += diff; + return diff; +} + +static __inline__ void qmPortalDqrrPvbPrefetch(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->pmode == e_QmPortalPVB); + /* If ring entries get stashed, don't invalidate/prefetch */ + if (!(dqrr->flags & QM_DQRR_FLAG_RE)) +#endif /*QM_CHECKING */ + dcbit_ro(ptr_ADD(dqrr->ring, qm_cl(dqrr->pi))); +} + +static __inline__ uint8_t qmPortalDqrrPvbUpdate(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + struct qm_dqrr_entry *res = ptr_ADD(dqrr->ring, qm_cl(dqrr->pi)); +#ifdef QM_CHECKING + ASSERT_COND(dqrr->pmode == e_QmPortalPVB); +#endif /* QM_CHECKING */ + if ((res->verb & QM_DQRR_VERB_VBIT) == dqrr->vbit) { + dqrr->pi = (uint8_t)((dqrr->pi + 1) & (QM_DQRR_SIZE - 1)); + if (!dqrr->pi) + dqrr->vbit ^= QM_DQRR_VERB_VBIT; + dqrr->fill++; + return 1; + } + return 0; +} + +static __inline__ void qmPortalDqrrCciConsume(struct qm_portal *portal, uint8_t num) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCI); +#endif /* QM_CHECKING */ + dqrr->ci = (uint8_t)((dqrr->ci + num) & (QM_DQRR_SIZE - 1)); + qm_out(DQRR_CI_CINH, dqrr->ci); +} + +static __inline__ void qmPortalDqrrCciConsumeToCurrent(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCI); +#endif /* QM_CHECKING */ + dqrr->ci = DQRR_PTR2IDX(dqrr->cursor); + qm_out(DQRR_CI_CINH, dqrr->ci); +} + +static __inline__ void qmPortalDqrrCcePrefetch(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_dqrr *dqrr = &portal->dqrr; + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCE); +#endif /* QM_CHECKING */ + qm_cl_invalidate(DQRR_CI); + qm_cl_touch_rw(DQRR_CI); +} + +static __inline__ void qmPortalDqrrCceConsume(struct qm_portal *portal, uint8_t num) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCE); +#endif /* QM_CHECKING */ + dqrr->ci = (uint8_t)((dqrr->ci + num) & (QM_DQRR_SIZE - 1)); + qm_cl_out(DQRR_CI, dqrr->ci); +} + +static __inline__ void qmPortalDqrrCceConsume_to_current(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrCCE); +#endif /* QM_CHECKING */ + dqrr->ci = DQRR_PTR2IDX(dqrr->cursor); + qm_cl_out(DQRR_CI, dqrr->ci); +} + +static __inline__ void qmPortalDqrrDcaConsume1(struct qm_portal *portal, uint8_t idx, bool park) +{ +#ifdef QM_CHECKING + register struct qm_dqrr *dqrr = &portal->dqrr; + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA); +#endif /* QM_CHECKING */ + ASSERT_COND(idx < QM_DQRR_SIZE); + qm_out(DQRR_DCAP, (0 << 8) | /* S */ + ((uint32_t)(park ? 1 : 0) << 6) | /* PK */ + idx); /* DCAP_CI */ +} + +static __inline__ void qmPortalDqrrDcaConsume1ptr(struct qm_portal *portal, + struct qm_dqrr_entry *dq, + bool park) +{ + uint8_t idx = DQRR_PTR2IDX(dq); +#ifdef QM_CHECKING + register struct qm_dqrr *dqrr = &portal->dqrr; + + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA); + ASSERT_COND((dqrr->ring + idx) == dq); + ASSERT_COND(idx < QM_DQRR_SIZE); +#endif /* QM_CHECKING */ + qm_out(DQRR_DCAP, (0 << 8) | /* DQRR_DCAP::S */ + ((uint32_t)(park ? 1 : 0) << 6) | /* DQRR_DCAP::PK */ + idx); /* DQRR_DCAP::DCAP_CI */ +} + +static __inline__ void qmPortalDqrrDcaConsumeN(struct qm_portal *portal, uint16_t bitmask) +{ +#ifdef QM_CHECKING + register struct qm_dqrr *dqrr = &portal->dqrr; + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA); +#endif /* QM_CHECKING */ + qm_out(DQRR_DCAP, (1 << 8) | /* DQRR_DCAP::S */ + ((uint32_t)bitmask << 16)); /* DQRR_DCAP::DCAP_CI */ +} + +static __inline__ uint8_t qmPortalDqrrDcaCci(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_dqrr *dqrr = &portal->dqrr; + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA); +#endif /* QM_CHECKING */ + return (uint8_t)(qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1)); +} + +static __inline__ void qmPortalDqrrDcaCcePrefetch(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_dqrr *dqrr = &portal->dqrr; + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA); +#endif /* QM_CHECKING */ + qm_cl_invalidate(DQRR_CI); + qm_cl_touch_ro(DQRR_CI); +} + +static __inline__ uint8_t qmPortalDqrrDcaCce(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_dqrr *dqrr = &portal->dqrr; + ASSERT_COND(dqrr->cmode == e_QmPortalDqrrDCA); +#endif /* QM_CHECKING */ + return (uint8_t)(qm_cl_in(DQRR_CI) & (QM_DQRR_SIZE - 1)); +} + +static __inline__ uint8_t qm_dqrr_get_ci(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->cmode != e_QmPortalDqrrDCA); +#endif /* QM_CHECKING */ + + return dqrr->ci; +} + +static __inline__ void qm_dqrr_park(struct qm_portal *portal, uint8_t idx) +{ +#ifdef QM_CHECKING + register struct qm_dqrr *dqrr = &portal->dqrr; + ASSERT_COND(dqrr->cmode != e_QmPortalDqrrDCA); +#endif /* QM_CHECKING */ + + qm_out(DQRR_DCAP, (0 << 8) | /* S */ + (uint32_t)(1 << 6) | /* PK */ + (idx & (QM_DQRR_SIZE - 1))); /* DCAP_CI */ +} + +static __inline__ void qm_dqrr_park_ci(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; +#ifdef QM_CHECKING + ASSERT_COND(dqrr->cmode != e_QmPortalDqrrDCA); +#endif /* QM_CHECKING */ + qm_out(DQRR_DCAP, (0 << 8) | /* S */ + (uint32_t)(1 << 6) | /* PK */ + (dqrr->ci & (QM_DQRR_SIZE - 1)));/* DCAP_CI */ +} + +static __inline__ void qm_dqrr_sdqcr_set(struct qm_portal *portal, uint32_t sdqcr) +{ + qm_out(DQRR_SDQCR, sdqcr); +} + +static __inline__ uint32_t qm_dqrr_sdqcr_get(struct qm_portal *portal) +{ + return qm_in(DQRR_SDQCR); +} + +static __inline__ void qm_dqrr_vdqcr_set(struct qm_portal *portal, uint32_t vdqcr) +{ + qm_out(DQRR_VDQCR, vdqcr); +} + +static __inline__ uint32_t qm_dqrr_vdqcr_get(struct qm_portal *portal) +{ + return qm_in(DQRR_VDQCR); +} + +static __inline__ void qm_dqrr_pdqcr_set(struct qm_portal *portal, uint32_t pdqcr) +{ + qm_out(DQRR_PDQCR, pdqcr); +} + +static __inline__ uint32_t qm_dqrr_pdqcr_get(struct qm_portal *portal) +{ + return qm_in(DQRR_PDQCR); +} + +static __inline__ uint8_t qm_dqrr_get_ithresh(struct qm_portal *portal) +{ + register struct qm_dqrr *dqrr = &portal->dqrr; + return dqrr->ithresh; +} + +static __inline__ void qm_dqrr_set_ithresh(struct qm_portal *portal, uint8_t ithresh) +{ + qm_out(DQRR_ITR, ithresh); +} + +static __inline__ uint8_t qm_dqrr_get_maxfill(struct qm_portal *portal) +{ + return (uint8_t)((qm_in(CFG) & 0x00f00000) >> 20); +} + +/* -------------- */ +/* --- MR API --- */ + +/* It's safer to code in terms of the 'mr' object than the 'portal' object, + * because the latter runs the risk of copy-n-paste errors from other code where + * we could manipulate some other structure within 'portal'. */ +/* #define MR_API_START() register struct qm_mr *mr = &portal->mr */ + +#define MR_CARRYCLEAR(p) \ + (void *)((uintptr_t)(p) & (~(uintptr_t)(QM_MR_SIZE << 6))) + +static __inline__ uint8_t MR_PTR2IDX(struct qm_mr_entry *e) +{ + return (uint8_t)(((uint32_t)e >> 6) & (QM_MR_SIZE - 1)); +} + +static __inline__ struct qm_mr_entry *MR_INC(struct qm_mr_entry *e) +{ + return MR_CARRYCLEAR(e + 1); +} + +static __inline__ t_Error qm_mr_init(struct qm_portal *portal, e_QmPortalProduceMode pmode, + e_QmPortalMrConsumeMode cmode) +{ + register struct qm_mr *mr = &portal->mr; + uint32_t cfg; + + if (__qm_portal_bind(portal, QM_BIND_MR)) + return ERROR_CODE(E_BUSY); + mr->ring = ptr_ADD(portal->addr.addr_ce, CL_MR); + mr->pi = (uint8_t)(qm_in(MR_PI_CINH) & (QM_MR_SIZE - 1)); + mr->ci = (uint8_t)(qm_in(MR_CI_CINH) & (QM_MR_SIZE - 1)); + mr->cursor = mr->ring + mr->ci; + mr->fill = cyc_diff(QM_MR_SIZE, mr->ci, mr->pi); + mr->vbit = (uint8_t)((qm_in(MR_PI_CINH) & QM_MR_SIZE) ?QM_MR_VERB_VBIT : 0); + mr->ithresh = (uint8_t)qm_in(MR_ITR); + +#ifdef QM_CHECKING + mr->pmode = pmode; + mr->cmode = cmode; +#else + UNUSED(pmode); +#endif /* QM_CHECKING */ + cfg = (qm_in(CFG) & 0xfffff0ff) | + ((cmode & 1) << 8); /* QCSP_CFG:MM */ + qm_out(CFG, cfg); + return E_OK; +} + + +static __inline__ void qm_mr_finish(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + if (mr->ci != MR_PTR2IDX(mr->cursor)) + REPORT_ERROR(WARNING, E_INVALID_STATE, ("Ignoring completed MR entries")); + __qm_portal_unbind(portal, QM_BIND_MR); +} + +static __inline__ void qm_mr_current_prefetch(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + dcbt_ro(mr->cursor); +} + +static __inline__ struct qm_mr_entry *qm_mr_current(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + if (!mr->fill) + return NULL; + return mr->cursor; +} + +static __inline__ uint8_t qm_mr_cursor(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + return MR_PTR2IDX(mr->cursor); +} + +static __inline__ uint8_t qm_mr_next(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; +#ifdef QM_CHECKING + ASSERT_COND(mr->fill); +#endif /* QM_CHECKING */ + mr->cursor = MR_INC(mr->cursor); + return --mr->fill; +} + +static __inline__ uint8_t qmPortalMrPciUpdate(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + uint8_t diff, old_pi = mr->pi; +#ifdef QM_CHECKING + ASSERT_COND(mr->pmode == e_QmPortalPCI); +#endif /* QM_CHECKING */ + mr->pi = (uint8_t)qm_in(MR_PI_CINH); + diff = cyc_diff(QM_MR_SIZE, old_pi, mr->pi); + mr->fill += diff; + return diff; +} + +static __inline__ void qmPortalMrPcePrefetch(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_mr *mr = &portal->mr; + ASSERT_COND(mr->pmode == e_QmPortalPCE); +#endif /* QM_CHECKING */ + qm_cl_invalidate(MR_PI); + qm_cl_touch_ro(MR_PI); +} + +static __inline__ uint8_t qmPortalMrPceUpdate(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + uint8_t diff, old_pi = mr->pi; +#ifdef QM_CHECKING + ASSERT_COND(mr->pmode == e_QmPortalPCE); +#endif /* QM_CHECKING */ + mr->pi = (uint8_t)(qm_cl_in(MR_PI) & (QM_MR_SIZE - 1)); + diff = cyc_diff(QM_MR_SIZE, old_pi, mr->pi); + mr->fill += diff; + return diff; +} + +static __inline__ void qmPortalMrPvbUpdate(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + struct qm_mr_entry *res = ptr_ADD(mr->ring, qm_cl(mr->pi)); +#ifdef QM_CHECKING + ASSERT_COND(mr->pmode == e_QmPortalPVB); +#endif /* QM_CHECKING */ + dcbit_ro(ptr_ADD(mr->ring, qm_cl(mr->pi))); + if ((res->verb & QM_MR_VERB_VBIT) == mr->vbit) { + mr->pi = (uint8_t)((mr->pi + 1) & (QM_MR_SIZE - 1)); + if (!mr->pi) + mr->vbit ^= QM_MR_VERB_VBIT; + mr->fill++; + } +} + +static __inline__ void qmPortalMrCciConsume(struct qm_portal *portal, uint8_t num) +{ + register struct qm_mr *mr = &portal->mr; +#ifdef QM_CHECKING + ASSERT_COND(mr->cmode == e_QmPortalMrCCI); +#endif /* QM_CHECKING */ + mr->ci = (uint8_t)((mr->ci + num) & (QM_MR_SIZE - 1)); + qm_out(MR_CI_CINH, mr->ci); +} + +static __inline__ void qmPortalMrCciConsumeToCurrent(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; +#ifdef QM_CHECKING + ASSERT_COND(mr->cmode == e_QmPortalMrCCI); +#endif /* QM_CHECKING */ + mr->ci = MR_PTR2IDX(mr->cursor); + qm_out(MR_CI_CINH, mr->ci); +} + +static __inline__ void qmPortalMrCcePrefetch(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_mr *mr = &portal->mr; + ASSERT_COND(mr->cmode == e_QmPortalMrCCE); +#endif /* QM_CHECKING */ + qm_cl_invalidate(MR_CI); + qm_cl_touch_rw(MR_CI); +} + +static __inline__ void qmPortalMrCceConsume(struct qm_portal *portal, uint8_t num) +{ + register struct qm_mr *mr = &portal->mr; +#ifdef QM_CHECKING + ASSERT_COND(mr->cmode == e_QmPortalMrCCE); +#endif /* QM_CHECKING */ + mr->ci = (uint8_t)((mr->ci + num) & (QM_MR_SIZE - 1)); + qm_cl_out(MR_CI, mr->ci); +} + +static __inline__ void qmPortalMrCceConsumeToCurrent(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; +#ifdef QM_CHECKING + ASSERT_COND(mr->cmode == e_QmPortalMrCCE); +#endif /* QM_CHECKING */ + mr->ci = MR_PTR2IDX(mr->cursor); + qm_cl_out(MR_CI, mr->ci); +} + +static __inline__ uint8_t qm_mr_get_ci(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + return mr->ci; +} + +static __inline__ uint8_t qm_mr_get_ithresh(struct qm_portal *portal) +{ + register struct qm_mr *mr = &portal->mr; + return mr->ithresh; +} + +static __inline__ void qm_mr_set_ithresh(struct qm_portal *portal, uint8_t ithresh) +{ + qm_out(MR_ITR, ithresh); +} + +/* ------------------------------ */ +/* --- Management command API --- */ + +/* It's safer to code in terms of the 'mc' object than the 'portal' object, + * because the latter runs the risk of copy-n-paste errors from other code where + * we could manipulate some other structure within 'portal'. */ +/* #define MC_API_START() register struct qm_mc *mc = &portal->mc */ + +static __inline__ t_Error qm_mc_init(struct qm_portal *portal) +{ + register struct qm_mc *mc = &portal->mc; + if (__qm_portal_bind(portal, QM_BIND_MC)) + return ERROR_CODE(E_BUSY); + mc->cr = ptr_ADD(portal->addr.addr_ce, CL_CR); + mc->rr = ptr_ADD(portal->addr.addr_ce, CL_RR0); + mc->rridx = (uint8_t)((mc->cr->__dont_write_directly__verb & QM_MCC_VERB_VBIT) ? + 0 : 1); + mc->vbit = (uint8_t)(mc->rridx ? QM_MCC_VERB_VBIT : 0); +#ifdef QM_CHECKING + mc->state = mc_idle; +#endif /* QM_CHECKING */ + return E_OK; +} + +static __inline__ void qm_mc_finish(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_mc *mc = &portal->mc; + ASSERT_COND(mc->state == mc_idle); + if (mc->state != mc_idle) + REPORT_ERROR(WARNING, E_INVALID_STATE, ("Losing incomplete MC command")); +#endif /* QM_CHECKING */ + __qm_portal_unbind(portal, QM_BIND_MC); +} + +static __inline__ struct qm_mc_command *qm_mc_start(struct qm_portal *portal) +{ + register struct qm_mc *mc = &portal->mc; +#ifdef QM_CHECKING + ASSERT_COND(mc->state == mc_idle); + mc->state = mc_user; +#endif /* QM_CHECKING */ + dcbz_64(mc->cr); + return mc->cr; +} + +static __inline__ void qm_mc_abort(struct qm_portal *portal) +{ +#ifdef QM_CHECKING + register struct qm_mc *mc = &portal->mc; + ASSERT_COND(mc->state == mc_user); + mc->state = mc_idle; +#else + UNUSED(portal); +#endif /* QM_CHECKING */ +} + +static __inline__ void qm_mc_commit(struct qm_portal *portal, uint8_t myverb) +{ + register struct qm_mc *mc = &portal->mc; +#ifdef QM_CHECKING + ASSERT_COND(mc->state == mc_user); +#endif /* QM_CHECKING */ + lwsync(); + mc->cr->__dont_write_directly__verb = (uint8_t)(myverb | mc->vbit); + dcbf_64(mc->cr); + dcbit_ro(mc->rr + mc->rridx); +#ifdef QM_CHECKING + mc->state = mc_hw; +#endif /* QM_CHECKING */ +} + +static __inline__ struct qm_mc_result *qm_mc_result(struct qm_portal *portal) +{ + register struct qm_mc *mc = &portal->mc; + struct qm_mc_result *rr = mc->rr + mc->rridx; +#ifdef QM_CHECKING + ASSERT_COND(mc->state == mc_hw); +#endif /* QM_CHECKING */ + /* The inactive response register's verb byte always returns zero until + * its command is submitted and completed. This includes the valid-bit, + * in case you were wondering... */ + if (!rr->verb) { + dcbit_ro(rr); + return NULL; + } + mc->rridx ^= 1; + mc->vbit ^= QM_MCC_VERB_VBIT; +#ifdef QM_CHECKING + mc->state = mc_idle; +#endif /* QM_CHECKING */ + return rr; +} + +/* ------------------------------------- */ +/* --- Portal interrupt register API --- */ + +static __inline__ t_Error qm_isr_init(struct qm_portal *portal) +{ + if (__qm_portal_bind(portal, QM_BIND_ISR)) + return ERROR_CODE(E_BUSY); + return E_OK; +} + +static __inline__ void qm_isr_finish(struct qm_portal *portal) +{ + __qm_portal_unbind(portal, QM_BIND_ISR); +} + +static __inline__ void qm_isr_set_iperiod(struct qm_portal *portal, uint16_t iperiod) +{ + qm_out(ITPR, iperiod); +} + +static __inline__ uint32_t __qm_isr_read(struct qm_portal *portal, enum qm_isr_reg n) +{ + return __qm_in(&portal->addr, PTR_MOVE(REG_ISR, (n << 2))); +} + +static __inline__ void __qm_isr_write(struct qm_portal *portal, enum qm_isr_reg n, uint32_t val) +{ + __qm_out(&portal->addr, PTR_MOVE(REG_ISR, (n << 2)), val); +} |