162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. 462306a36Sopenharmony_ci * Copyright 2016-2019 NXP 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <asm/cacheflush.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/spinlock.h> 1262306a36Sopenharmony_ci#include <soc/fsl/dpaa2-global.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "qbman-portal.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* All QBMan command and result structures use this "valid bit" encoding */ 1762306a36Sopenharmony_ci#define QB_VALID_BIT ((u32)0x80) 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* QBMan portal management command codes */ 2062306a36Sopenharmony_ci#define QBMAN_MC_ACQUIRE 0x30 2162306a36Sopenharmony_ci#define QBMAN_WQCHAN_CONFIGURE 0x46 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* CINH register offsets */ 2462306a36Sopenharmony_ci#define QBMAN_CINH_SWP_EQCR_PI 0x800 2562306a36Sopenharmony_ci#define QBMAN_CINH_SWP_EQCR_CI 0x840 2662306a36Sopenharmony_ci#define QBMAN_CINH_SWP_EQAR 0x8c0 2762306a36Sopenharmony_ci#define QBMAN_CINH_SWP_CR_RT 0x900 2862306a36Sopenharmony_ci#define QBMAN_CINH_SWP_VDQCR_RT 0x940 2962306a36Sopenharmony_ci#define QBMAN_CINH_SWP_EQCR_AM_RT 0x980 3062306a36Sopenharmony_ci#define QBMAN_CINH_SWP_RCR_AM_RT 0x9c0 3162306a36Sopenharmony_ci#define QBMAN_CINH_SWP_DQPI 0xa00 3262306a36Sopenharmony_ci#define QBMAN_CINH_SWP_DQRR_ITR 0xa80 3362306a36Sopenharmony_ci#define QBMAN_CINH_SWP_DCAP 0xac0 3462306a36Sopenharmony_ci#define QBMAN_CINH_SWP_SDQCR 0xb00 3562306a36Sopenharmony_ci#define QBMAN_CINH_SWP_EQCR_AM_RT2 0xb40 3662306a36Sopenharmony_ci#define QBMAN_CINH_SWP_RCR_PI 0xc00 3762306a36Sopenharmony_ci#define QBMAN_CINH_SWP_RAR 0xcc0 3862306a36Sopenharmony_ci#define QBMAN_CINH_SWP_ISR 0xe00 3962306a36Sopenharmony_ci#define QBMAN_CINH_SWP_IER 0xe40 4062306a36Sopenharmony_ci#define QBMAN_CINH_SWP_ISDR 0xe80 4162306a36Sopenharmony_ci#define QBMAN_CINH_SWP_IIR 0xec0 4262306a36Sopenharmony_ci#define QBMAN_CINH_SWP_ITPR 0xf40 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* CENA register offsets */ 4562306a36Sopenharmony_ci#define QBMAN_CENA_SWP_EQCR(n) (0x000 + ((u32)(n) << 6)) 4662306a36Sopenharmony_ci#define QBMAN_CENA_SWP_DQRR(n) (0x200 + ((u32)(n) << 6)) 4762306a36Sopenharmony_ci#define QBMAN_CENA_SWP_RCR(n) (0x400 + ((u32)(n) << 6)) 4862306a36Sopenharmony_ci#define QBMAN_CENA_SWP_CR 0x600 4962306a36Sopenharmony_ci#define QBMAN_CENA_SWP_RR(vb) (0x700 + ((u32)(vb) >> 1)) 5062306a36Sopenharmony_ci#define QBMAN_CENA_SWP_VDQCR 0x780 5162306a36Sopenharmony_ci#define QBMAN_CENA_SWP_EQCR_CI 0x840 5262306a36Sopenharmony_ci#define QBMAN_CENA_SWP_EQCR_CI_MEMBACK 0x1840 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* CENA register offsets in memory-backed mode */ 5562306a36Sopenharmony_ci#define QBMAN_CENA_SWP_DQRR_MEM(n) (0x800 + ((u32)(n) << 6)) 5662306a36Sopenharmony_ci#define QBMAN_CENA_SWP_RCR_MEM(n) (0x1400 + ((u32)(n) << 6)) 5762306a36Sopenharmony_ci#define QBMAN_CENA_SWP_CR_MEM 0x1600 5862306a36Sopenharmony_ci#define QBMAN_CENA_SWP_RR_MEM 0x1680 5962306a36Sopenharmony_ci#define QBMAN_CENA_SWP_VDQCR_MEM 0x1780 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* Reverse mapping of QBMAN_CENA_SWP_DQRR() */ 6262306a36Sopenharmony_ci#define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)(p) & 0x1ff) >> 6) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Define token used to determine if response written to memory is valid */ 6562306a36Sopenharmony_ci#define QMAN_DQ_TOKEN_VALID 1 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* SDQCR attribute codes */ 6862306a36Sopenharmony_ci#define QB_SDQCR_FC_SHIFT 29 6962306a36Sopenharmony_ci#define QB_SDQCR_FC_MASK 0x1 7062306a36Sopenharmony_ci#define QB_SDQCR_DCT_SHIFT 24 7162306a36Sopenharmony_ci#define QB_SDQCR_DCT_MASK 0x3 7262306a36Sopenharmony_ci#define QB_SDQCR_TOK_SHIFT 16 7362306a36Sopenharmony_ci#define QB_SDQCR_TOK_MASK 0xff 7462306a36Sopenharmony_ci#define QB_SDQCR_SRC_SHIFT 0 7562306a36Sopenharmony_ci#define QB_SDQCR_SRC_MASK 0xffff 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* opaque token for static dequeues */ 7862306a36Sopenharmony_ci#define QMAN_SDQCR_TOKEN 0xbb 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define QBMAN_EQCR_DCA_IDXMASK 0x0f 8162306a36Sopenharmony_ci#define QBMAN_ENQUEUE_FLAG_DCA (1ULL << 31) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define EQ_DESC_SIZE_WITHOUT_FD 29 8462306a36Sopenharmony_ci#define EQ_DESC_SIZE_FD_START 32 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cienum qbman_sdqcr_dct { 8762306a36Sopenharmony_ci qbman_sdqcr_dct_null = 0, 8862306a36Sopenharmony_ci qbman_sdqcr_dct_prio_ics, 8962306a36Sopenharmony_ci qbman_sdqcr_dct_active_ics, 9062306a36Sopenharmony_ci qbman_sdqcr_dct_active 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cienum qbman_sdqcr_fc { 9462306a36Sopenharmony_ci qbman_sdqcr_fc_one = 0, 9562306a36Sopenharmony_ci qbman_sdqcr_fc_up_to_3 = 1 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* Internal Function declaration */ 9962306a36Sopenharmony_cistatic int qbman_swp_enqueue_direct(struct qbman_swp *s, 10062306a36Sopenharmony_ci const struct qbman_eq_desc *d, 10162306a36Sopenharmony_ci const struct dpaa2_fd *fd); 10262306a36Sopenharmony_cistatic int qbman_swp_enqueue_mem_back(struct qbman_swp *s, 10362306a36Sopenharmony_ci const struct qbman_eq_desc *d, 10462306a36Sopenharmony_ci const struct dpaa2_fd *fd); 10562306a36Sopenharmony_cistatic int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s, 10662306a36Sopenharmony_ci const struct qbman_eq_desc *d, 10762306a36Sopenharmony_ci const struct dpaa2_fd *fd, 10862306a36Sopenharmony_ci uint32_t *flags, 10962306a36Sopenharmony_ci int num_frames); 11062306a36Sopenharmony_cistatic int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s, 11162306a36Sopenharmony_ci const struct qbman_eq_desc *d, 11262306a36Sopenharmony_ci const struct dpaa2_fd *fd, 11362306a36Sopenharmony_ci uint32_t *flags, 11462306a36Sopenharmony_ci int num_frames); 11562306a36Sopenharmony_cistatic int 11662306a36Sopenharmony_ciqbman_swp_enqueue_multiple_desc_direct(struct qbman_swp *s, 11762306a36Sopenharmony_ci const struct qbman_eq_desc *d, 11862306a36Sopenharmony_ci const struct dpaa2_fd *fd, 11962306a36Sopenharmony_ci int num_frames); 12062306a36Sopenharmony_cistatic 12162306a36Sopenharmony_ciint qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s, 12262306a36Sopenharmony_ci const struct qbman_eq_desc *d, 12362306a36Sopenharmony_ci const struct dpaa2_fd *fd, 12462306a36Sopenharmony_ci int num_frames); 12562306a36Sopenharmony_cistatic int qbman_swp_pull_direct(struct qbman_swp *s, 12662306a36Sopenharmony_ci struct qbman_pull_desc *d); 12762306a36Sopenharmony_cistatic int qbman_swp_pull_mem_back(struct qbman_swp *s, 12862306a36Sopenharmony_ci struct qbman_pull_desc *d); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciconst struct dpaa2_dq *qbman_swp_dqrr_next_direct(struct qbman_swp *s); 13162306a36Sopenharmony_ciconst struct dpaa2_dq *qbman_swp_dqrr_next_mem_back(struct qbman_swp *s); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int qbman_swp_release_direct(struct qbman_swp *s, 13462306a36Sopenharmony_ci const struct qbman_release_desc *d, 13562306a36Sopenharmony_ci const u64 *buffers, 13662306a36Sopenharmony_ci unsigned int num_buffers); 13762306a36Sopenharmony_cistatic int qbman_swp_release_mem_back(struct qbman_swp *s, 13862306a36Sopenharmony_ci const struct qbman_release_desc *d, 13962306a36Sopenharmony_ci const u64 *buffers, 14062306a36Sopenharmony_ci unsigned int num_buffers); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* Function pointers */ 14362306a36Sopenharmony_ciint (*qbman_swp_enqueue_ptr)(struct qbman_swp *s, 14462306a36Sopenharmony_ci const struct qbman_eq_desc *d, 14562306a36Sopenharmony_ci const struct dpaa2_fd *fd) 14662306a36Sopenharmony_ci = qbman_swp_enqueue_direct; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ciint (*qbman_swp_enqueue_multiple_ptr)(struct qbman_swp *s, 14962306a36Sopenharmony_ci const struct qbman_eq_desc *d, 15062306a36Sopenharmony_ci const struct dpaa2_fd *fd, 15162306a36Sopenharmony_ci uint32_t *flags, 15262306a36Sopenharmony_ci int num_frames) 15362306a36Sopenharmony_ci = qbman_swp_enqueue_multiple_direct; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ciint 15662306a36Sopenharmony_ci(*qbman_swp_enqueue_multiple_desc_ptr)(struct qbman_swp *s, 15762306a36Sopenharmony_ci const struct qbman_eq_desc *d, 15862306a36Sopenharmony_ci const struct dpaa2_fd *fd, 15962306a36Sopenharmony_ci int num_frames) 16062306a36Sopenharmony_ci = qbman_swp_enqueue_multiple_desc_direct; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciint (*qbman_swp_pull_ptr)(struct qbman_swp *s, struct qbman_pull_desc *d) 16362306a36Sopenharmony_ci = qbman_swp_pull_direct; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ciconst struct dpaa2_dq *(*qbman_swp_dqrr_next_ptr)(struct qbman_swp *s) 16662306a36Sopenharmony_ci = qbman_swp_dqrr_next_direct; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciint (*qbman_swp_release_ptr)(struct qbman_swp *s, 16962306a36Sopenharmony_ci const struct qbman_release_desc *d, 17062306a36Sopenharmony_ci const u64 *buffers, 17162306a36Sopenharmony_ci unsigned int num_buffers) 17262306a36Sopenharmony_ci = qbman_swp_release_direct; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* Portal Access */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic inline u32 qbman_read_register(struct qbman_swp *p, u32 offset) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci return readl_relaxed(p->addr_cinh + offset); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic inline void qbman_write_register(struct qbman_swp *p, u32 offset, 18262306a36Sopenharmony_ci u32 value) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci writel_relaxed(value, p->addr_cinh + offset); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic inline void *qbman_get_cmd(struct qbman_swp *p, u32 offset) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci return p->addr_cena + offset; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci#define QBMAN_CINH_SWP_CFG 0xd00 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci#define SWP_CFG_DQRR_MF_SHIFT 20 19562306a36Sopenharmony_ci#define SWP_CFG_EST_SHIFT 16 19662306a36Sopenharmony_ci#define SWP_CFG_CPBS_SHIFT 15 19762306a36Sopenharmony_ci#define SWP_CFG_WN_SHIFT 14 19862306a36Sopenharmony_ci#define SWP_CFG_RPM_SHIFT 12 19962306a36Sopenharmony_ci#define SWP_CFG_DCM_SHIFT 10 20062306a36Sopenharmony_ci#define SWP_CFG_EPM_SHIFT 8 20162306a36Sopenharmony_ci#define SWP_CFG_VPM_SHIFT 7 20262306a36Sopenharmony_ci#define SWP_CFG_CPM_SHIFT 6 20362306a36Sopenharmony_ci#define SWP_CFG_SD_SHIFT 5 20462306a36Sopenharmony_ci#define SWP_CFG_SP_SHIFT 4 20562306a36Sopenharmony_ci#define SWP_CFG_SE_SHIFT 3 20662306a36Sopenharmony_ci#define SWP_CFG_DP_SHIFT 2 20762306a36Sopenharmony_ci#define SWP_CFG_DE_SHIFT 1 20862306a36Sopenharmony_ci#define SWP_CFG_EP_SHIFT 0 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn, u8 est, u8 rpm, u8 dcm, 21162306a36Sopenharmony_ci u8 epm, int sd, int sp, int se, 21262306a36Sopenharmony_ci int dp, int de, int ep) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci return (max_fill << SWP_CFG_DQRR_MF_SHIFT | 21562306a36Sopenharmony_ci est << SWP_CFG_EST_SHIFT | 21662306a36Sopenharmony_ci wn << SWP_CFG_WN_SHIFT | 21762306a36Sopenharmony_ci rpm << SWP_CFG_RPM_SHIFT | 21862306a36Sopenharmony_ci dcm << SWP_CFG_DCM_SHIFT | 21962306a36Sopenharmony_ci epm << SWP_CFG_EPM_SHIFT | 22062306a36Sopenharmony_ci sd << SWP_CFG_SD_SHIFT | 22162306a36Sopenharmony_ci sp << SWP_CFG_SP_SHIFT | 22262306a36Sopenharmony_ci se << SWP_CFG_SE_SHIFT | 22362306a36Sopenharmony_ci dp << SWP_CFG_DP_SHIFT | 22462306a36Sopenharmony_ci de << SWP_CFG_DE_SHIFT | 22562306a36Sopenharmony_ci ep << SWP_CFG_EP_SHIFT); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci#define QMAN_RT_MODE 0x00000100 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic inline u8 qm_cyc_diff(u8 ringsize, u8 first, u8 last) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci /* 'first' is included, 'last' is excluded */ 23362306a36Sopenharmony_ci if (first <= last) 23462306a36Sopenharmony_ci return last - first; 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci return (2 * ringsize) - (first - last); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/** 24062306a36Sopenharmony_ci * qbman_swp_init() - Create a functional object representing the given 24162306a36Sopenharmony_ci * QBMan portal descriptor. 24262306a36Sopenharmony_ci * @d: the given qbman swp descriptor 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci * Return qbman_swp portal for success, NULL if the object cannot 24562306a36Sopenharmony_ci * be created. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cistruct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct qbman_swp *p = kzalloc(sizeof(*p), GFP_KERNEL); 25062306a36Sopenharmony_ci u32 reg; 25162306a36Sopenharmony_ci u32 mask_size; 25262306a36Sopenharmony_ci u32 eqcr_pi; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (!p) 25562306a36Sopenharmony_ci return NULL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci spin_lock_init(&p->access_spinlock); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci p->desc = d; 26062306a36Sopenharmony_ci p->mc.valid_bit = QB_VALID_BIT; 26162306a36Sopenharmony_ci p->sdq = 0; 26262306a36Sopenharmony_ci p->sdq |= qbman_sdqcr_dct_prio_ics << QB_SDQCR_DCT_SHIFT; 26362306a36Sopenharmony_ci p->sdq |= qbman_sdqcr_fc_up_to_3 << QB_SDQCR_FC_SHIFT; 26462306a36Sopenharmony_ci p->sdq |= QMAN_SDQCR_TOKEN << QB_SDQCR_TOK_SHIFT; 26562306a36Sopenharmony_ci if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) 26662306a36Sopenharmony_ci p->mr.valid_bit = QB_VALID_BIT; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci atomic_set(&p->vdq.available, 1); 26962306a36Sopenharmony_ci p->vdq.valid_bit = QB_VALID_BIT; 27062306a36Sopenharmony_ci p->dqrr.next_idx = 0; 27162306a36Sopenharmony_ci p->dqrr.valid_bit = QB_VALID_BIT; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_4100) { 27462306a36Sopenharmony_ci p->dqrr.dqrr_size = 4; 27562306a36Sopenharmony_ci p->dqrr.reset_bug = 1; 27662306a36Sopenharmony_ci } else { 27762306a36Sopenharmony_ci p->dqrr.dqrr_size = 8; 27862306a36Sopenharmony_ci p->dqrr.reset_bug = 0; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci p->addr_cena = d->cena_bar; 28262306a36Sopenharmony_ci p->addr_cinh = d->cinh_bar; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci reg = qbman_set_swp_cfg(p->dqrr.dqrr_size, 28762306a36Sopenharmony_ci 1, /* Writes Non-cacheable */ 28862306a36Sopenharmony_ci 0, /* EQCR_CI stashing threshold */ 28962306a36Sopenharmony_ci 3, /* RPM: RCR in array mode */ 29062306a36Sopenharmony_ci 2, /* DCM: Discrete consumption ack */ 29162306a36Sopenharmony_ci 2, /* EPM: EQCR in ring mode */ 29262306a36Sopenharmony_ci 1, /* mem stashing drop enable enable */ 29362306a36Sopenharmony_ci 1, /* mem stashing priority enable */ 29462306a36Sopenharmony_ci 1, /* mem stashing enable */ 29562306a36Sopenharmony_ci 1, /* dequeue stashing priority enable */ 29662306a36Sopenharmony_ci 0, /* dequeue stashing enable enable */ 29762306a36Sopenharmony_ci 0); /* EQCR_CI stashing priority enable */ 29862306a36Sopenharmony_ci } else { 29962306a36Sopenharmony_ci memset(p->addr_cena, 0, 64 * 1024); 30062306a36Sopenharmony_ci reg = qbman_set_swp_cfg(p->dqrr.dqrr_size, 30162306a36Sopenharmony_ci 1, /* Writes Non-cacheable */ 30262306a36Sopenharmony_ci 1, /* EQCR_CI stashing threshold */ 30362306a36Sopenharmony_ci 3, /* RPM: RCR in array mode */ 30462306a36Sopenharmony_ci 2, /* DCM: Discrete consumption ack */ 30562306a36Sopenharmony_ci 0, /* EPM: EQCR in ring mode */ 30662306a36Sopenharmony_ci 1, /* mem stashing drop enable */ 30762306a36Sopenharmony_ci 1, /* mem stashing priority enable */ 30862306a36Sopenharmony_ci 1, /* mem stashing enable */ 30962306a36Sopenharmony_ci 1, /* dequeue stashing priority enable */ 31062306a36Sopenharmony_ci 0, /* dequeue stashing enable */ 31162306a36Sopenharmony_ci 0); /* EQCR_CI stashing priority enable */ 31262306a36Sopenharmony_ci reg |= 1 << SWP_CFG_CPBS_SHIFT | /* memory-backed mode */ 31362306a36Sopenharmony_ci 1 << SWP_CFG_VPM_SHIFT | /* VDQCR read triggered mode */ 31462306a36Sopenharmony_ci 1 << SWP_CFG_CPM_SHIFT; /* CR read triggered mode */ 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_CFG, reg); 31862306a36Sopenharmony_ci reg = qbman_read_register(p, QBMAN_CINH_SWP_CFG); 31962306a36Sopenharmony_ci if (!reg) { 32062306a36Sopenharmony_ci pr_err("qbman: the portal is not enabled!\n"); 32162306a36Sopenharmony_ci kfree(p); 32262306a36Sopenharmony_ci return NULL; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) { 32662306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_EQCR_PI, QMAN_RT_MODE); 32762306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_RCR_PI, QMAN_RT_MODE); 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci /* 33062306a36Sopenharmony_ci * SDQCR needs to be initialized to 0 when no channels are 33162306a36Sopenharmony_ci * being dequeued from or else the QMan HW will indicate an 33262306a36Sopenharmony_ci * error. The values that were calculated above will be 33362306a36Sopenharmony_ci * applied when dequeues from a specific channel are enabled. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_SDQCR, 0); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci p->eqcr.pi_ring_size = 8; 33862306a36Sopenharmony_ci if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) { 33962306a36Sopenharmony_ci p->eqcr.pi_ring_size = 32; 34062306a36Sopenharmony_ci qbman_swp_enqueue_ptr = 34162306a36Sopenharmony_ci qbman_swp_enqueue_mem_back; 34262306a36Sopenharmony_ci qbman_swp_enqueue_multiple_ptr = 34362306a36Sopenharmony_ci qbman_swp_enqueue_multiple_mem_back; 34462306a36Sopenharmony_ci qbman_swp_enqueue_multiple_desc_ptr = 34562306a36Sopenharmony_ci qbman_swp_enqueue_multiple_desc_mem_back; 34662306a36Sopenharmony_ci qbman_swp_pull_ptr = qbman_swp_pull_mem_back; 34762306a36Sopenharmony_ci qbman_swp_dqrr_next_ptr = qbman_swp_dqrr_next_mem_back; 34862306a36Sopenharmony_ci qbman_swp_release_ptr = qbman_swp_release_mem_back; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci for (mask_size = p->eqcr.pi_ring_size; mask_size > 0; mask_size >>= 1) 35262306a36Sopenharmony_ci p->eqcr.pi_ci_mask = (p->eqcr.pi_ci_mask << 1) + 1; 35362306a36Sopenharmony_ci eqcr_pi = qbman_read_register(p, QBMAN_CINH_SWP_EQCR_PI); 35462306a36Sopenharmony_ci p->eqcr.pi = eqcr_pi & p->eqcr.pi_ci_mask; 35562306a36Sopenharmony_ci p->eqcr.pi_vb = eqcr_pi & QB_VALID_BIT; 35662306a36Sopenharmony_ci p->eqcr.ci = qbman_read_register(p, QBMAN_CINH_SWP_EQCR_CI) 35762306a36Sopenharmony_ci & p->eqcr.pi_ci_mask; 35862306a36Sopenharmony_ci p->eqcr.available = p->eqcr.pi_ring_size; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Initialize the software portal with a irq timeout period of 0us */ 36162306a36Sopenharmony_ci qbman_swp_set_irq_coalescing(p, p->dqrr.dqrr_size - 1, 0); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return p; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/** 36762306a36Sopenharmony_ci * qbman_swp_finish() - Create and destroy a functional object representing 36862306a36Sopenharmony_ci * the given QBMan portal descriptor. 36962306a36Sopenharmony_ci * @p: the qbman_swp object to be destroyed 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_civoid qbman_swp_finish(struct qbman_swp *p) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci kfree(p); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/** 37762306a36Sopenharmony_ci * qbman_swp_interrupt_read_status() 37862306a36Sopenharmony_ci * @p: the given software portal 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci * Return the value in the SWP_ISR register. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ciu32 qbman_swp_interrupt_read_status(struct qbman_swp *p) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci return qbman_read_register(p, QBMAN_CINH_SWP_ISR); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/** 38862306a36Sopenharmony_ci * qbman_swp_interrupt_clear_status() 38962306a36Sopenharmony_ci * @p: the given software portal 39062306a36Sopenharmony_ci * @mask: The mask to clear in SWP_ISR register 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_civoid qbman_swp_interrupt_clear_status(struct qbman_swp *p, u32 mask) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_ISR, mask); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci/** 39862306a36Sopenharmony_ci * qbman_swp_interrupt_get_trigger() - read interrupt enable register 39962306a36Sopenharmony_ci * @p: the given software portal 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * Return the value in the SWP_IER register. 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_ciu32 qbman_swp_interrupt_get_trigger(struct qbman_swp *p) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci return qbman_read_register(p, QBMAN_CINH_SWP_IER); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/** 40962306a36Sopenharmony_ci * qbman_swp_interrupt_set_trigger() - enable interrupts for a swp 41062306a36Sopenharmony_ci * @p: the given software portal 41162306a36Sopenharmony_ci * @mask: The mask of bits to enable in SWP_IER 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_civoid qbman_swp_interrupt_set_trigger(struct qbman_swp *p, u32 mask) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_IER, mask); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/** 41962306a36Sopenharmony_ci * qbman_swp_interrupt_get_inhibit() - read interrupt mask register 42062306a36Sopenharmony_ci * @p: the given software portal object 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * Return the value in the SWP_IIR register. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ciint qbman_swp_interrupt_get_inhibit(struct qbman_swp *p) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci return qbman_read_register(p, QBMAN_CINH_SWP_IIR); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/** 43062306a36Sopenharmony_ci * qbman_swp_interrupt_set_inhibit() - write interrupt mask register 43162306a36Sopenharmony_ci * @p: the given software portal object 43262306a36Sopenharmony_ci * @inhibit: whether to inhibit the IRQs 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_civoid qbman_swp_interrupt_set_inhibit(struct qbman_swp *p, int inhibit) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_IIR, inhibit ? 0xffffffff : 0); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* 44062306a36Sopenharmony_ci * Different management commands all use this common base layer of code to issue 44162306a36Sopenharmony_ci * commands and poll for results. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci/* 44562306a36Sopenharmony_ci * Returns a pointer to where the caller should fill in their management command 44662306a36Sopenharmony_ci * (caller should ignore the verb byte) 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_civoid *qbman_swp_mc_start(struct qbman_swp *p) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) 45162306a36Sopenharmony_ci return qbman_get_cmd(p, QBMAN_CENA_SWP_CR); 45262306a36Sopenharmony_ci else 45362306a36Sopenharmony_ci return qbman_get_cmd(p, QBMAN_CENA_SWP_CR_MEM); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/* 45762306a36Sopenharmony_ci * Commits merges in the caller-supplied command verb (which should not include 45862306a36Sopenharmony_ci * the valid-bit) and submits the command to hardware 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_civoid qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci u8 *v = cmd; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { 46562306a36Sopenharmony_ci dma_wmb(); 46662306a36Sopenharmony_ci *v = cmd_verb | p->mc.valid_bit; 46762306a36Sopenharmony_ci } else { 46862306a36Sopenharmony_ci *v = cmd_verb | p->mc.valid_bit; 46962306a36Sopenharmony_ci dma_wmb(); 47062306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_CR_RT, QMAN_RT_MODE); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/* 47562306a36Sopenharmony_ci * Checks for a completed response (returns non-NULL if only if the response 47662306a36Sopenharmony_ci * is complete). 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_civoid *qbman_swp_mc_result(struct qbman_swp *p) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci u32 *ret, verb; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { 48362306a36Sopenharmony_ci ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit)); 48462306a36Sopenharmony_ci /* Remove the valid-bit - command completed if the rest 48562306a36Sopenharmony_ci * is non-zero. 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_ci verb = ret[0] & ~QB_VALID_BIT; 48862306a36Sopenharmony_ci if (!verb) 48962306a36Sopenharmony_ci return NULL; 49062306a36Sopenharmony_ci p->mc.valid_bit ^= QB_VALID_BIT; 49162306a36Sopenharmony_ci } else { 49262306a36Sopenharmony_ci ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR_MEM); 49362306a36Sopenharmony_ci /* Command completed if the valid bit is toggled */ 49462306a36Sopenharmony_ci if (p->mr.valid_bit != (ret[0] & QB_VALID_BIT)) 49562306a36Sopenharmony_ci return NULL; 49662306a36Sopenharmony_ci /* Command completed if the rest is non-zero */ 49762306a36Sopenharmony_ci verb = ret[0] & ~QB_VALID_BIT; 49862306a36Sopenharmony_ci if (!verb) 49962306a36Sopenharmony_ci return NULL; 50062306a36Sopenharmony_ci p->mr.valid_bit ^= QB_VALID_BIT; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return ret; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci#define QB_ENQUEUE_CMD_OPTIONS_SHIFT 0 50762306a36Sopenharmony_cienum qb_enqueue_commands { 50862306a36Sopenharmony_ci enqueue_empty = 0, 50962306a36Sopenharmony_ci enqueue_response_always = 1, 51062306a36Sopenharmony_ci enqueue_rejects_to_fq = 2 51162306a36Sopenharmony_ci}; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci#define QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT 2 51462306a36Sopenharmony_ci#define QB_ENQUEUE_CMD_IRQ_ON_DISPATCH_SHIFT 3 51562306a36Sopenharmony_ci#define QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT 4 51662306a36Sopenharmony_ci#define QB_ENQUEUE_CMD_DCA_EN_SHIFT 7 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci/* 51962306a36Sopenharmony_ci * qbman_eq_desc_clear() - Clear the contents of a descriptor to 52062306a36Sopenharmony_ci * default/starting state. 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_civoid qbman_eq_desc_clear(struct qbman_eq_desc *d) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci memset(d, 0, sizeof(*d)); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci/** 52862306a36Sopenharmony_ci * qbman_eq_desc_set_no_orp() - Set enqueue descriptor without orp 52962306a36Sopenharmony_ci * @d: the enqueue descriptor. 53062306a36Sopenharmony_ci * @respond_success: 1 = enqueue with response always; 0 = enqueue with 53162306a36Sopenharmony_ci * rejections returned on a FQ. 53262306a36Sopenharmony_ci */ 53362306a36Sopenharmony_civoid qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci d->verb &= ~(1 << QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT); 53662306a36Sopenharmony_ci if (respond_success) 53762306a36Sopenharmony_ci d->verb |= enqueue_response_always; 53862306a36Sopenharmony_ci else 53962306a36Sopenharmony_ci d->verb |= enqueue_rejects_to_fq; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_ci * Exactly one of the following descriptor "targets" should be set. (Calling any 54462306a36Sopenharmony_ci * one of these will replace the effect of any prior call to one of these.) 54562306a36Sopenharmony_ci * -enqueue to a frame queue 54662306a36Sopenharmony_ci * -enqueue to a queuing destination 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci/** 55062306a36Sopenharmony_ci * qbman_eq_desc_set_fq() - set the FQ for the enqueue command 55162306a36Sopenharmony_ci * @d: the enqueue descriptor 55262306a36Sopenharmony_ci * @fqid: the id of the frame queue to be enqueued 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_civoid qbman_eq_desc_set_fq(struct qbman_eq_desc *d, u32 fqid) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci d->verb &= ~(1 << QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT); 55762306a36Sopenharmony_ci d->tgtid = cpu_to_le32(fqid); 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/** 56162306a36Sopenharmony_ci * qbman_eq_desc_set_qd() - Set Queuing Destination for the enqueue command 56262306a36Sopenharmony_ci * @d: the enqueue descriptor 56362306a36Sopenharmony_ci * @qdid: the id of the queuing destination to be enqueued 56462306a36Sopenharmony_ci * @qd_bin: the queuing destination bin 56562306a36Sopenharmony_ci * @qd_prio: the queuing destination priority 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_civoid qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid, 56862306a36Sopenharmony_ci u32 qd_bin, u32 qd_prio) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci d->verb |= 1 << QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT; 57162306a36Sopenharmony_ci d->tgtid = cpu_to_le32(qdid); 57262306a36Sopenharmony_ci d->qdbin = cpu_to_le16(qd_bin); 57362306a36Sopenharmony_ci d->qpri = qd_prio; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci#define EQAR_IDX(eqar) ((eqar) & 0x7) 57762306a36Sopenharmony_ci#define EQAR_VB(eqar) ((eqar) & 0x80) 57862306a36Sopenharmony_ci#define EQAR_SUCCESS(eqar) ((eqar) & 0x100) 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci#define QB_RT_BIT ((u32)0x100) 58162306a36Sopenharmony_ci/** 58262306a36Sopenharmony_ci * qbman_swp_enqueue_direct() - Issue an enqueue command 58362306a36Sopenharmony_ci * @s: the software portal used for enqueue 58462306a36Sopenharmony_ci * @d: the enqueue descriptor 58562306a36Sopenharmony_ci * @fd: the frame descriptor to be enqueued 58662306a36Sopenharmony_ci * 58762306a36Sopenharmony_ci * Please note that 'fd' should only be NULL if the "action" of the 58862306a36Sopenharmony_ci * descriptor is "orp_hole" or "orp_nesn". 58962306a36Sopenharmony_ci * 59062306a36Sopenharmony_ci * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready. 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_cistatic 59362306a36Sopenharmony_ciint qbman_swp_enqueue_direct(struct qbman_swp *s, 59462306a36Sopenharmony_ci const struct qbman_eq_desc *d, 59562306a36Sopenharmony_ci const struct dpaa2_fd *fd) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci int flags = 0; 59862306a36Sopenharmony_ci int ret = qbman_swp_enqueue_multiple_direct(s, d, fd, &flags, 1); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (ret >= 0) 60162306a36Sopenharmony_ci ret = 0; 60262306a36Sopenharmony_ci else 60362306a36Sopenharmony_ci ret = -EBUSY; 60462306a36Sopenharmony_ci return ret; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci/** 60862306a36Sopenharmony_ci * qbman_swp_enqueue_mem_back() - Issue an enqueue command 60962306a36Sopenharmony_ci * @s: the software portal used for enqueue 61062306a36Sopenharmony_ci * @d: the enqueue descriptor 61162306a36Sopenharmony_ci * @fd: the frame descriptor to be enqueued 61262306a36Sopenharmony_ci * 61362306a36Sopenharmony_ci * Please note that 'fd' should only be NULL if the "action" of the 61462306a36Sopenharmony_ci * descriptor is "orp_hole" or "orp_nesn". 61562306a36Sopenharmony_ci * 61662306a36Sopenharmony_ci * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready. 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_cistatic 61962306a36Sopenharmony_ciint qbman_swp_enqueue_mem_back(struct qbman_swp *s, 62062306a36Sopenharmony_ci const struct qbman_eq_desc *d, 62162306a36Sopenharmony_ci const struct dpaa2_fd *fd) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci int flags = 0; 62462306a36Sopenharmony_ci int ret = qbman_swp_enqueue_multiple_mem_back(s, d, fd, &flags, 1); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (ret >= 0) 62762306a36Sopenharmony_ci ret = 0; 62862306a36Sopenharmony_ci else 62962306a36Sopenharmony_ci ret = -EBUSY; 63062306a36Sopenharmony_ci return ret; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci/** 63462306a36Sopenharmony_ci * qbman_swp_enqueue_multiple_direct() - Issue a multi enqueue command 63562306a36Sopenharmony_ci * using one enqueue descriptor 63662306a36Sopenharmony_ci * @s: the software portal used for enqueue 63762306a36Sopenharmony_ci * @d: the enqueue descriptor 63862306a36Sopenharmony_ci * @fd: table pointer of frame descriptor table to be enqueued 63962306a36Sopenharmony_ci * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL 64062306a36Sopenharmony_ci * @num_frames: number of fd to be enqueued 64162306a36Sopenharmony_ci * 64262306a36Sopenharmony_ci * Return the number of fd enqueued, or a negative error number. 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_cistatic 64562306a36Sopenharmony_ciint qbman_swp_enqueue_multiple_direct(struct qbman_swp *s, 64662306a36Sopenharmony_ci const struct qbman_eq_desc *d, 64762306a36Sopenharmony_ci const struct dpaa2_fd *fd, 64862306a36Sopenharmony_ci uint32_t *flags, 64962306a36Sopenharmony_ci int num_frames) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci uint32_t *p = NULL; 65262306a36Sopenharmony_ci const uint32_t *cl = (uint32_t *)d; 65362306a36Sopenharmony_ci uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask; 65462306a36Sopenharmony_ci int i, num_enqueued = 0; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci spin_lock(&s->access_spinlock); 65762306a36Sopenharmony_ci half_mask = (s->eqcr.pi_ci_mask>>1); 65862306a36Sopenharmony_ci full_mask = s->eqcr.pi_ci_mask; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (!s->eqcr.available) { 66162306a36Sopenharmony_ci eqcr_ci = s->eqcr.ci; 66262306a36Sopenharmony_ci p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI; 66362306a36Sopenharmony_ci s->eqcr.ci = qbman_read_register(s, QBMAN_CINH_SWP_EQCR_CI); 66462306a36Sopenharmony_ci s->eqcr.ci &= full_mask; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size, 66762306a36Sopenharmony_ci eqcr_ci, s->eqcr.ci); 66862306a36Sopenharmony_ci if (!s->eqcr.available) { 66962306a36Sopenharmony_ci spin_unlock(&s->access_spinlock); 67062306a36Sopenharmony_ci return 0; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 67562306a36Sopenharmony_ci num_enqueued = (s->eqcr.available < num_frames) ? 67662306a36Sopenharmony_ci s->eqcr.available : num_frames; 67762306a36Sopenharmony_ci s->eqcr.available -= num_enqueued; 67862306a36Sopenharmony_ci /* Fill in the EQCR ring */ 67962306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) { 68062306a36Sopenharmony_ci p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); 68162306a36Sopenharmony_ci /* Skip copying the verb */ 68262306a36Sopenharmony_ci memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1); 68362306a36Sopenharmony_ci memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)], 68462306a36Sopenharmony_ci &fd[i], sizeof(*fd)); 68562306a36Sopenharmony_ci eqcr_pi++; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci dma_wmb(); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* Set the verb byte, have to substitute in the valid-bit */ 69162306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 69262306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) { 69362306a36Sopenharmony_ci p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); 69462306a36Sopenharmony_ci p[0] = cl[0] | s->eqcr.pi_vb; 69562306a36Sopenharmony_ci if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) { 69662306a36Sopenharmony_ci struct qbman_eq_desc *eq_desc = (struct qbman_eq_desc *)p; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci eq_desc->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) | 69962306a36Sopenharmony_ci ((flags[i]) & QBMAN_EQCR_DCA_IDXMASK); 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci eqcr_pi++; 70262306a36Sopenharmony_ci if (!(eqcr_pi & half_mask)) 70362306a36Sopenharmony_ci s->eqcr.pi_vb ^= QB_VALID_BIT; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* Flush all the cacheline without load/store in between */ 70762306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 70862306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) 70962306a36Sopenharmony_ci eqcr_pi++; 71062306a36Sopenharmony_ci s->eqcr.pi = eqcr_pi & full_mask; 71162306a36Sopenharmony_ci spin_unlock(&s->access_spinlock); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci return num_enqueued; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci/** 71762306a36Sopenharmony_ci * qbman_swp_enqueue_multiple_mem_back() - Issue a multi enqueue command 71862306a36Sopenharmony_ci * using one enqueue descriptor 71962306a36Sopenharmony_ci * @s: the software portal used for enqueue 72062306a36Sopenharmony_ci * @d: the enqueue descriptor 72162306a36Sopenharmony_ci * @fd: table pointer of frame descriptor table to be enqueued 72262306a36Sopenharmony_ci * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL 72362306a36Sopenharmony_ci * @num_frames: number of fd to be enqueued 72462306a36Sopenharmony_ci * 72562306a36Sopenharmony_ci * Return the number of fd enqueued, or a negative error number. 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_cistatic 72862306a36Sopenharmony_ciint qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s, 72962306a36Sopenharmony_ci const struct qbman_eq_desc *d, 73062306a36Sopenharmony_ci const struct dpaa2_fd *fd, 73162306a36Sopenharmony_ci uint32_t *flags, 73262306a36Sopenharmony_ci int num_frames) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci uint32_t *p = NULL; 73562306a36Sopenharmony_ci const uint32_t *cl = (uint32_t *)(d); 73662306a36Sopenharmony_ci uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask; 73762306a36Sopenharmony_ci int i, num_enqueued = 0; 73862306a36Sopenharmony_ci unsigned long irq_flags; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci spin_lock_irqsave(&s->access_spinlock, irq_flags); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci half_mask = (s->eqcr.pi_ci_mask>>1); 74362306a36Sopenharmony_ci full_mask = s->eqcr.pi_ci_mask; 74462306a36Sopenharmony_ci if (!s->eqcr.available) { 74562306a36Sopenharmony_ci eqcr_ci = s->eqcr.ci; 74662306a36Sopenharmony_ci s->eqcr.ci = qbman_read_register(s, QBMAN_CINH_SWP_EQCR_CI); 74762306a36Sopenharmony_ci s->eqcr.ci &= full_mask; 74862306a36Sopenharmony_ci s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size, 74962306a36Sopenharmony_ci eqcr_ci, s->eqcr.ci); 75062306a36Sopenharmony_ci if (!s->eqcr.available) { 75162306a36Sopenharmony_ci spin_unlock_irqrestore(&s->access_spinlock, irq_flags); 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 75762306a36Sopenharmony_ci num_enqueued = (s->eqcr.available < num_frames) ? 75862306a36Sopenharmony_ci s->eqcr.available : num_frames; 75962306a36Sopenharmony_ci s->eqcr.available -= num_enqueued; 76062306a36Sopenharmony_ci /* Fill in the EQCR ring */ 76162306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) { 76262306a36Sopenharmony_ci p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); 76362306a36Sopenharmony_ci /* Skip copying the verb */ 76462306a36Sopenharmony_ci memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1); 76562306a36Sopenharmony_ci memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)], 76662306a36Sopenharmony_ci &fd[i], sizeof(*fd)); 76762306a36Sopenharmony_ci eqcr_pi++; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* Set the verb byte, have to substitute in the valid-bit */ 77162306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 77262306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) { 77362306a36Sopenharmony_ci p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); 77462306a36Sopenharmony_ci p[0] = cl[0] | s->eqcr.pi_vb; 77562306a36Sopenharmony_ci if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) { 77662306a36Sopenharmony_ci struct qbman_eq_desc *eq_desc = (struct qbman_eq_desc *)p; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci eq_desc->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) | 77962306a36Sopenharmony_ci ((flags[i]) & QBMAN_EQCR_DCA_IDXMASK); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci eqcr_pi++; 78262306a36Sopenharmony_ci if (!(eqcr_pi & half_mask)) 78362306a36Sopenharmony_ci s->eqcr.pi_vb ^= QB_VALID_BIT; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci s->eqcr.pi = eqcr_pi & full_mask; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci dma_wmb(); 78862306a36Sopenharmony_ci qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI, 78962306a36Sopenharmony_ci (QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb); 79062306a36Sopenharmony_ci spin_unlock_irqrestore(&s->access_spinlock, irq_flags); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci return num_enqueued; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci/** 79662306a36Sopenharmony_ci * qbman_swp_enqueue_multiple_desc_direct() - Issue a multi enqueue command 79762306a36Sopenharmony_ci * using multiple enqueue descriptor 79862306a36Sopenharmony_ci * @s: the software portal used for enqueue 79962306a36Sopenharmony_ci * @d: table of minimal enqueue descriptor 80062306a36Sopenharmony_ci * @fd: table pointer of frame descriptor table to be enqueued 80162306a36Sopenharmony_ci * @num_frames: number of fd to be enqueued 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci * Return the number of fd enqueued, or a negative error number. 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_cistatic 80662306a36Sopenharmony_ciint qbman_swp_enqueue_multiple_desc_direct(struct qbman_swp *s, 80762306a36Sopenharmony_ci const struct qbman_eq_desc *d, 80862306a36Sopenharmony_ci const struct dpaa2_fd *fd, 80962306a36Sopenharmony_ci int num_frames) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci uint32_t *p; 81262306a36Sopenharmony_ci const uint32_t *cl; 81362306a36Sopenharmony_ci uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask; 81462306a36Sopenharmony_ci int i, num_enqueued = 0; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci half_mask = (s->eqcr.pi_ci_mask>>1); 81762306a36Sopenharmony_ci full_mask = s->eqcr.pi_ci_mask; 81862306a36Sopenharmony_ci if (!s->eqcr.available) { 81962306a36Sopenharmony_ci eqcr_ci = s->eqcr.ci; 82062306a36Sopenharmony_ci p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI; 82162306a36Sopenharmony_ci s->eqcr.ci = qbman_read_register(s, QBMAN_CINH_SWP_EQCR_CI); 82262306a36Sopenharmony_ci s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size, 82362306a36Sopenharmony_ci eqcr_ci, s->eqcr.ci); 82462306a36Sopenharmony_ci if (!s->eqcr.available) 82562306a36Sopenharmony_ci return 0; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 82962306a36Sopenharmony_ci num_enqueued = (s->eqcr.available < num_frames) ? 83062306a36Sopenharmony_ci s->eqcr.available : num_frames; 83162306a36Sopenharmony_ci s->eqcr.available -= num_enqueued; 83262306a36Sopenharmony_ci /* Fill in the EQCR ring */ 83362306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) { 83462306a36Sopenharmony_ci p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); 83562306a36Sopenharmony_ci cl = (uint32_t *)(&d[i]); 83662306a36Sopenharmony_ci /* Skip copying the verb */ 83762306a36Sopenharmony_ci memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1); 83862306a36Sopenharmony_ci memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)], 83962306a36Sopenharmony_ci &fd[i], sizeof(*fd)); 84062306a36Sopenharmony_ci eqcr_pi++; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci dma_wmb(); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* Set the verb byte, have to substitute in the valid-bit */ 84662306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 84762306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) { 84862306a36Sopenharmony_ci p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); 84962306a36Sopenharmony_ci cl = (uint32_t *)(&d[i]); 85062306a36Sopenharmony_ci p[0] = cl[0] | s->eqcr.pi_vb; 85162306a36Sopenharmony_ci eqcr_pi++; 85262306a36Sopenharmony_ci if (!(eqcr_pi & half_mask)) 85362306a36Sopenharmony_ci s->eqcr.pi_vb ^= QB_VALID_BIT; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* Flush all the cacheline without load/store in between */ 85762306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 85862306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) 85962306a36Sopenharmony_ci eqcr_pi++; 86062306a36Sopenharmony_ci s->eqcr.pi = eqcr_pi & full_mask; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return num_enqueued; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/** 86662306a36Sopenharmony_ci * qbman_swp_enqueue_multiple_desc_mem_back() - Issue a multi enqueue command 86762306a36Sopenharmony_ci * using multiple enqueue descriptor 86862306a36Sopenharmony_ci * @s: the software portal used for enqueue 86962306a36Sopenharmony_ci * @d: table of minimal enqueue descriptor 87062306a36Sopenharmony_ci * @fd: table pointer of frame descriptor table to be enqueued 87162306a36Sopenharmony_ci * @num_frames: number of fd to be enqueued 87262306a36Sopenharmony_ci * 87362306a36Sopenharmony_ci * Return the number of fd enqueued, or a negative error number. 87462306a36Sopenharmony_ci */ 87562306a36Sopenharmony_cistatic 87662306a36Sopenharmony_ciint qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s, 87762306a36Sopenharmony_ci const struct qbman_eq_desc *d, 87862306a36Sopenharmony_ci const struct dpaa2_fd *fd, 87962306a36Sopenharmony_ci int num_frames) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci uint32_t *p; 88262306a36Sopenharmony_ci const uint32_t *cl; 88362306a36Sopenharmony_ci uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask; 88462306a36Sopenharmony_ci int i, num_enqueued = 0; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci half_mask = (s->eqcr.pi_ci_mask>>1); 88762306a36Sopenharmony_ci full_mask = s->eqcr.pi_ci_mask; 88862306a36Sopenharmony_ci if (!s->eqcr.available) { 88962306a36Sopenharmony_ci eqcr_ci = s->eqcr.ci; 89062306a36Sopenharmony_ci s->eqcr.ci = qbman_read_register(s, QBMAN_CINH_SWP_EQCR_CI); 89162306a36Sopenharmony_ci s->eqcr.ci &= full_mask; 89262306a36Sopenharmony_ci s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size, 89362306a36Sopenharmony_ci eqcr_ci, s->eqcr.ci); 89462306a36Sopenharmony_ci if (!s->eqcr.available) 89562306a36Sopenharmony_ci return 0; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 89962306a36Sopenharmony_ci num_enqueued = (s->eqcr.available < num_frames) ? 90062306a36Sopenharmony_ci s->eqcr.available : num_frames; 90162306a36Sopenharmony_ci s->eqcr.available -= num_enqueued; 90262306a36Sopenharmony_ci /* Fill in the EQCR ring */ 90362306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) { 90462306a36Sopenharmony_ci p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); 90562306a36Sopenharmony_ci cl = (uint32_t *)(&d[i]); 90662306a36Sopenharmony_ci /* Skip copying the verb */ 90762306a36Sopenharmony_ci memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1); 90862306a36Sopenharmony_ci memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)], 90962306a36Sopenharmony_ci &fd[i], sizeof(*fd)); 91062306a36Sopenharmony_ci eqcr_pi++; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* Set the verb byte, have to substitute in the valid-bit */ 91462306a36Sopenharmony_ci eqcr_pi = s->eqcr.pi; 91562306a36Sopenharmony_ci for (i = 0; i < num_enqueued; i++) { 91662306a36Sopenharmony_ci p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); 91762306a36Sopenharmony_ci cl = (uint32_t *)(&d[i]); 91862306a36Sopenharmony_ci p[0] = cl[0] | s->eqcr.pi_vb; 91962306a36Sopenharmony_ci eqcr_pi++; 92062306a36Sopenharmony_ci if (!(eqcr_pi & half_mask)) 92162306a36Sopenharmony_ci s->eqcr.pi_vb ^= QB_VALID_BIT; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci s->eqcr.pi = eqcr_pi & full_mask; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci dma_wmb(); 92762306a36Sopenharmony_ci qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI, 92862306a36Sopenharmony_ci (QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci return num_enqueued; 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci/* Static (push) dequeue */ 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci/** 93662306a36Sopenharmony_ci * qbman_swp_push_get() - Get the push dequeue setup 93762306a36Sopenharmony_ci * @s: the software portal object 93862306a36Sopenharmony_ci * @channel_idx: the channel index to query 93962306a36Sopenharmony_ci * @enabled: returned boolean to show whether the push dequeue is enabled 94062306a36Sopenharmony_ci * for the given channel 94162306a36Sopenharmony_ci */ 94262306a36Sopenharmony_civoid qbman_swp_push_get(struct qbman_swp *s, u8 channel_idx, int *enabled) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci u16 src = (s->sdq >> QB_SDQCR_SRC_SHIFT) & QB_SDQCR_SRC_MASK; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci WARN_ON(channel_idx > 15); 94762306a36Sopenharmony_ci *enabled = src | (1 << channel_idx); 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci/** 95162306a36Sopenharmony_ci * qbman_swp_push_set() - Enable or disable push dequeue 95262306a36Sopenharmony_ci * @s: the software portal object 95362306a36Sopenharmony_ci * @channel_idx: the channel index (0 to 15) 95462306a36Sopenharmony_ci * @enable: enable or disable push dequeue 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_civoid qbman_swp_push_set(struct qbman_swp *s, u8 channel_idx, int enable) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci u16 dqsrc; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci WARN_ON(channel_idx > 15); 96162306a36Sopenharmony_ci if (enable) 96262306a36Sopenharmony_ci s->sdq |= 1 << channel_idx; 96362306a36Sopenharmony_ci else 96462306a36Sopenharmony_ci s->sdq &= ~(1 << channel_idx); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci /* Read make the complete src map. If no channels are enabled 96762306a36Sopenharmony_ci * the SDQCR must be 0 or else QMan will assert errors 96862306a36Sopenharmony_ci */ 96962306a36Sopenharmony_ci dqsrc = (s->sdq >> QB_SDQCR_SRC_SHIFT) & QB_SDQCR_SRC_MASK; 97062306a36Sopenharmony_ci if (dqsrc != 0) 97162306a36Sopenharmony_ci qbman_write_register(s, QBMAN_CINH_SWP_SDQCR, s->sdq); 97262306a36Sopenharmony_ci else 97362306a36Sopenharmony_ci qbman_write_register(s, QBMAN_CINH_SWP_SDQCR, 0); 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci#define QB_VDQCR_VERB_DCT_SHIFT 0 97762306a36Sopenharmony_ci#define QB_VDQCR_VERB_DT_SHIFT 2 97862306a36Sopenharmony_ci#define QB_VDQCR_VERB_RLS_SHIFT 4 97962306a36Sopenharmony_ci#define QB_VDQCR_VERB_WAE_SHIFT 5 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cienum qb_pull_dt_e { 98262306a36Sopenharmony_ci qb_pull_dt_channel, 98362306a36Sopenharmony_ci qb_pull_dt_workqueue, 98462306a36Sopenharmony_ci qb_pull_dt_framequeue 98562306a36Sopenharmony_ci}; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci/** 98862306a36Sopenharmony_ci * qbman_pull_desc_clear() - Clear the contents of a descriptor to 98962306a36Sopenharmony_ci * default/starting state 99062306a36Sopenharmony_ci * @d: the pull dequeue descriptor to be cleared 99162306a36Sopenharmony_ci */ 99262306a36Sopenharmony_civoid qbman_pull_desc_clear(struct qbman_pull_desc *d) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci memset(d, 0, sizeof(*d)); 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci/** 99862306a36Sopenharmony_ci * qbman_pull_desc_set_storage()- Set the pull dequeue storage 99962306a36Sopenharmony_ci * @d: the pull dequeue descriptor to be set 100062306a36Sopenharmony_ci * @storage: the pointer of the memory to store the dequeue result 100162306a36Sopenharmony_ci * @storage_phys: the physical address of the storage memory 100262306a36Sopenharmony_ci * @stash: to indicate whether write allocate is enabled 100362306a36Sopenharmony_ci * 100462306a36Sopenharmony_ci * If not called, or if called with 'storage' as NULL, the result pull dequeues 100562306a36Sopenharmony_ci * will produce results to DQRR. If 'storage' is non-NULL, then results are 100662306a36Sopenharmony_ci * produced to the given memory location (using the DMA address which 100762306a36Sopenharmony_ci * the caller provides in 'storage_phys'), and 'stash' controls whether or not 100862306a36Sopenharmony_ci * those writes to main-memory express a cache-warming attribute. 100962306a36Sopenharmony_ci */ 101062306a36Sopenharmony_civoid qbman_pull_desc_set_storage(struct qbman_pull_desc *d, 101162306a36Sopenharmony_ci struct dpaa2_dq *storage, 101262306a36Sopenharmony_ci dma_addr_t storage_phys, 101362306a36Sopenharmony_ci int stash) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci /* save the virtual address */ 101662306a36Sopenharmony_ci d->rsp_addr_virt = (u64)(uintptr_t)storage; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (!storage) { 101962306a36Sopenharmony_ci d->verb &= ~(1 << QB_VDQCR_VERB_RLS_SHIFT); 102062306a36Sopenharmony_ci return; 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci d->verb |= 1 << QB_VDQCR_VERB_RLS_SHIFT; 102362306a36Sopenharmony_ci if (stash) 102462306a36Sopenharmony_ci d->verb |= 1 << QB_VDQCR_VERB_WAE_SHIFT; 102562306a36Sopenharmony_ci else 102662306a36Sopenharmony_ci d->verb &= ~(1 << QB_VDQCR_VERB_WAE_SHIFT); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci d->rsp_addr = cpu_to_le64(storage_phys); 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci/** 103262306a36Sopenharmony_ci * qbman_pull_desc_set_numframes() - Set the number of frames to be dequeued 103362306a36Sopenharmony_ci * @d: the pull dequeue descriptor to be set 103462306a36Sopenharmony_ci * @numframes: number of frames to be set, must be between 1 and 16, inclusive 103562306a36Sopenharmony_ci */ 103662306a36Sopenharmony_civoid qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, u8 numframes) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci d->numf = numframes - 1; 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci/* 104262306a36Sopenharmony_ci * Exactly one of the following descriptor "actions" should be set. (Calling any 104362306a36Sopenharmony_ci * one of these will replace the effect of any prior call to one of these.) 104462306a36Sopenharmony_ci * - pull dequeue from the given frame queue (FQ) 104562306a36Sopenharmony_ci * - pull dequeue from any FQ in the given work queue (WQ) 104662306a36Sopenharmony_ci * - pull dequeue from any FQ in any WQ in the given channel 104762306a36Sopenharmony_ci */ 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci/** 105062306a36Sopenharmony_ci * qbman_pull_desc_set_fq() - Set fqid from which the dequeue command dequeues 105162306a36Sopenharmony_ci * @d: the pull dequeue descriptor to be set 105262306a36Sopenharmony_ci * @fqid: the frame queue index of the given FQ 105362306a36Sopenharmony_ci */ 105462306a36Sopenharmony_civoid qbman_pull_desc_set_fq(struct qbman_pull_desc *d, u32 fqid) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci d->verb |= 1 << QB_VDQCR_VERB_DCT_SHIFT; 105762306a36Sopenharmony_ci d->verb |= qb_pull_dt_framequeue << QB_VDQCR_VERB_DT_SHIFT; 105862306a36Sopenharmony_ci d->dq_src = cpu_to_le32(fqid); 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci/** 106262306a36Sopenharmony_ci * qbman_pull_desc_set_wq() - Set wqid from which the dequeue command dequeues 106362306a36Sopenharmony_ci * @d: the pull dequeue descriptor to be set 106462306a36Sopenharmony_ci * @wqid: composed of channel id and wqid within the channel 106562306a36Sopenharmony_ci * @dct: the dequeue command type 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_civoid qbman_pull_desc_set_wq(struct qbman_pull_desc *d, u32 wqid, 106862306a36Sopenharmony_ci enum qbman_pull_type_e dct) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci d->verb |= dct << QB_VDQCR_VERB_DCT_SHIFT; 107162306a36Sopenharmony_ci d->verb |= qb_pull_dt_workqueue << QB_VDQCR_VERB_DT_SHIFT; 107262306a36Sopenharmony_ci d->dq_src = cpu_to_le32(wqid); 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci/** 107662306a36Sopenharmony_ci * qbman_pull_desc_set_channel() - Set channelid from which the dequeue command 107762306a36Sopenharmony_ci * dequeues 107862306a36Sopenharmony_ci * @d: the pull dequeue descriptor to be set 107962306a36Sopenharmony_ci * @chid: the channel id to be dequeued 108062306a36Sopenharmony_ci * @dct: the dequeue command type 108162306a36Sopenharmony_ci */ 108262306a36Sopenharmony_civoid qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid, 108362306a36Sopenharmony_ci enum qbman_pull_type_e dct) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci d->verb |= dct << QB_VDQCR_VERB_DCT_SHIFT; 108662306a36Sopenharmony_ci d->verb |= qb_pull_dt_channel << QB_VDQCR_VERB_DT_SHIFT; 108762306a36Sopenharmony_ci d->dq_src = cpu_to_le32(chid); 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci/** 109162306a36Sopenharmony_ci * qbman_swp_pull_direct() - Issue the pull dequeue command 109262306a36Sopenharmony_ci * @s: the software portal object 109362306a36Sopenharmony_ci * @d: the software portal descriptor which has been configured with 109462306a36Sopenharmony_ci * the set of qbman_pull_desc_set_*() calls 109562306a36Sopenharmony_ci * 109662306a36Sopenharmony_ci * Return 0 for success, and -EBUSY if the software portal is not ready 109762306a36Sopenharmony_ci * to do pull dequeue. 109862306a36Sopenharmony_ci */ 109962306a36Sopenharmony_cistatic 110062306a36Sopenharmony_ciint qbman_swp_pull_direct(struct qbman_swp *s, struct qbman_pull_desc *d) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci struct qbman_pull_desc *p; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci if (!atomic_dec_and_test(&s->vdq.available)) { 110562306a36Sopenharmony_ci atomic_inc(&s->vdq.available); 110662306a36Sopenharmony_ci return -EBUSY; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt; 110962306a36Sopenharmony_ci if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) 111062306a36Sopenharmony_ci p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR); 111162306a36Sopenharmony_ci else 111262306a36Sopenharmony_ci p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR_MEM); 111362306a36Sopenharmony_ci p->numf = d->numf; 111462306a36Sopenharmony_ci p->tok = QMAN_DQ_TOKEN_VALID; 111562306a36Sopenharmony_ci p->dq_src = d->dq_src; 111662306a36Sopenharmony_ci p->rsp_addr = d->rsp_addr; 111762306a36Sopenharmony_ci p->rsp_addr_virt = d->rsp_addr_virt; 111862306a36Sopenharmony_ci dma_wmb(); 111962306a36Sopenharmony_ci /* Set the verb byte, have to substitute in the valid-bit */ 112062306a36Sopenharmony_ci p->verb = d->verb | s->vdq.valid_bit; 112162306a36Sopenharmony_ci s->vdq.valid_bit ^= QB_VALID_BIT; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci return 0; 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci/** 112762306a36Sopenharmony_ci * qbman_swp_pull_mem_back() - Issue the pull dequeue command 112862306a36Sopenharmony_ci * @s: the software portal object 112962306a36Sopenharmony_ci * @d: the software portal descriptor which has been configured with 113062306a36Sopenharmony_ci * the set of qbman_pull_desc_set_*() calls 113162306a36Sopenharmony_ci * 113262306a36Sopenharmony_ci * Return 0 for success, and -EBUSY if the software portal is not ready 113362306a36Sopenharmony_ci * to do pull dequeue. 113462306a36Sopenharmony_ci */ 113562306a36Sopenharmony_cistatic 113662306a36Sopenharmony_ciint qbman_swp_pull_mem_back(struct qbman_swp *s, struct qbman_pull_desc *d) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct qbman_pull_desc *p; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci if (!atomic_dec_and_test(&s->vdq.available)) { 114162306a36Sopenharmony_ci atomic_inc(&s->vdq.available); 114262306a36Sopenharmony_ci return -EBUSY; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt; 114562306a36Sopenharmony_ci if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) 114662306a36Sopenharmony_ci p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR); 114762306a36Sopenharmony_ci else 114862306a36Sopenharmony_ci p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR_MEM); 114962306a36Sopenharmony_ci p->numf = d->numf; 115062306a36Sopenharmony_ci p->tok = QMAN_DQ_TOKEN_VALID; 115162306a36Sopenharmony_ci p->dq_src = d->dq_src; 115262306a36Sopenharmony_ci p->rsp_addr = d->rsp_addr; 115362306a36Sopenharmony_ci p->rsp_addr_virt = d->rsp_addr_virt; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* Set the verb byte, have to substitute in the valid-bit */ 115662306a36Sopenharmony_ci p->verb = d->verb | s->vdq.valid_bit; 115762306a36Sopenharmony_ci s->vdq.valid_bit ^= QB_VALID_BIT; 115862306a36Sopenharmony_ci dma_wmb(); 115962306a36Sopenharmony_ci qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci return 0; 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci#define QMAN_DQRR_PI_MASK 0xf 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci/** 116762306a36Sopenharmony_ci * qbman_swp_dqrr_next_direct() - Get an valid DQRR entry 116862306a36Sopenharmony_ci * @s: the software portal object 116962306a36Sopenharmony_ci * 117062306a36Sopenharmony_ci * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry 117162306a36Sopenharmony_ci * only once, so repeated calls can return a sequence of DQRR entries, without 117262306a36Sopenharmony_ci * requiring they be consumed immediately or in any particular order. 117362306a36Sopenharmony_ci */ 117462306a36Sopenharmony_ciconst struct dpaa2_dq *qbman_swp_dqrr_next_direct(struct qbman_swp *s) 117562306a36Sopenharmony_ci{ 117662306a36Sopenharmony_ci u32 verb; 117762306a36Sopenharmony_ci u32 response_verb; 117862306a36Sopenharmony_ci u32 flags; 117962306a36Sopenharmony_ci struct dpaa2_dq *p; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* Before using valid-bit to detect if something is there, we have to 118262306a36Sopenharmony_ci * handle the case of the DQRR reset bug... 118362306a36Sopenharmony_ci */ 118462306a36Sopenharmony_ci if (unlikely(s->dqrr.reset_bug)) { 118562306a36Sopenharmony_ci /* 118662306a36Sopenharmony_ci * We pick up new entries by cache-inhibited producer index, 118762306a36Sopenharmony_ci * which means that a non-coherent mapping would require us to 118862306a36Sopenharmony_ci * invalidate and read *only* once that PI has indicated that 118962306a36Sopenharmony_ci * there's an entry here. The first trip around the DQRR ring 119062306a36Sopenharmony_ci * will be much less efficient than all subsequent trips around 119162306a36Sopenharmony_ci * it... 119262306a36Sopenharmony_ci */ 119362306a36Sopenharmony_ci u8 pi = qbman_read_register(s, QBMAN_CINH_SWP_DQPI) & 119462306a36Sopenharmony_ci QMAN_DQRR_PI_MASK; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci /* there are new entries if pi != next_idx */ 119762306a36Sopenharmony_ci if (pi == s->dqrr.next_idx) 119862306a36Sopenharmony_ci return NULL; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* 120162306a36Sopenharmony_ci * if next_idx is/was the last ring index, and 'pi' is 120262306a36Sopenharmony_ci * different, we can disable the workaround as all the ring 120362306a36Sopenharmony_ci * entries have now been DMA'd to so valid-bit checking is 120462306a36Sopenharmony_ci * repaired. Note: this logic needs to be based on next_idx 120562306a36Sopenharmony_ci * (which increments one at a time), rather than on pi (which 120662306a36Sopenharmony_ci * can burst and wrap-around between our snapshots of it). 120762306a36Sopenharmony_ci */ 120862306a36Sopenharmony_ci if (s->dqrr.next_idx == (s->dqrr.dqrr_size - 1)) { 120962306a36Sopenharmony_ci pr_debug("next_idx=%d, pi=%d, clear reset bug\n", 121062306a36Sopenharmony_ci s->dqrr.next_idx, pi); 121162306a36Sopenharmony_ci s->dqrr.reset_bug = 0; 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci prefetch(qbman_get_cmd(s, 121462306a36Sopenharmony_ci QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); 121862306a36Sopenharmony_ci verb = p->dq.verb; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci /* 122162306a36Sopenharmony_ci * If the valid-bit isn't of the expected polarity, nothing there. Note, 122262306a36Sopenharmony_ci * in the DQRR reset bug workaround, we shouldn't need to skip these 122362306a36Sopenharmony_ci * check, because we've already determined that a new entry is available 122462306a36Sopenharmony_ci * and we've invalidated the cacheline before reading it, so the 122562306a36Sopenharmony_ci * valid-bit behaviour is repaired and should tell us what we already 122662306a36Sopenharmony_ci * knew from reading PI. 122762306a36Sopenharmony_ci */ 122862306a36Sopenharmony_ci if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) { 122962306a36Sopenharmony_ci prefetch(qbman_get_cmd(s, 123062306a36Sopenharmony_ci QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); 123162306a36Sopenharmony_ci return NULL; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci /* 123462306a36Sopenharmony_ci * There's something there. Move "next_idx" attention to the next ring 123562306a36Sopenharmony_ci * entry (and prefetch it) before returning what we found. 123662306a36Sopenharmony_ci */ 123762306a36Sopenharmony_ci s->dqrr.next_idx++; 123862306a36Sopenharmony_ci s->dqrr.next_idx &= s->dqrr.dqrr_size - 1; /* Wrap around */ 123962306a36Sopenharmony_ci if (!s->dqrr.next_idx) 124062306a36Sopenharmony_ci s->dqrr.valid_bit ^= QB_VALID_BIT; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci /* 124362306a36Sopenharmony_ci * If this is the final response to a volatile dequeue command 124462306a36Sopenharmony_ci * indicate that the vdq is available 124562306a36Sopenharmony_ci */ 124662306a36Sopenharmony_ci flags = p->dq.stat; 124762306a36Sopenharmony_ci response_verb = verb & QBMAN_RESULT_MASK; 124862306a36Sopenharmony_ci if ((response_verb == QBMAN_RESULT_DQ) && 124962306a36Sopenharmony_ci (flags & DPAA2_DQ_STAT_VOLATILE) && 125062306a36Sopenharmony_ci (flags & DPAA2_DQ_STAT_EXPIRED)) 125162306a36Sopenharmony_ci atomic_inc(&s->vdq.available); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci prefetch(qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci return p; 125662306a36Sopenharmony_ci} 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci/** 125962306a36Sopenharmony_ci * qbman_swp_dqrr_next_mem_back() - Get an valid DQRR entry 126062306a36Sopenharmony_ci * @s: the software portal object 126162306a36Sopenharmony_ci * 126262306a36Sopenharmony_ci * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry 126362306a36Sopenharmony_ci * only once, so repeated calls can return a sequence of DQRR entries, without 126462306a36Sopenharmony_ci * requiring they be consumed immediately or in any particular order. 126562306a36Sopenharmony_ci */ 126662306a36Sopenharmony_ciconst struct dpaa2_dq *qbman_swp_dqrr_next_mem_back(struct qbman_swp *s) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci u32 verb; 126962306a36Sopenharmony_ci u32 response_verb; 127062306a36Sopenharmony_ci u32 flags; 127162306a36Sopenharmony_ci struct dpaa2_dq *p; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci /* Before using valid-bit to detect if something is there, we have to 127462306a36Sopenharmony_ci * handle the case of the DQRR reset bug... 127562306a36Sopenharmony_ci */ 127662306a36Sopenharmony_ci if (unlikely(s->dqrr.reset_bug)) { 127762306a36Sopenharmony_ci /* 127862306a36Sopenharmony_ci * We pick up new entries by cache-inhibited producer index, 127962306a36Sopenharmony_ci * which means that a non-coherent mapping would require us to 128062306a36Sopenharmony_ci * invalidate and read *only* once that PI has indicated that 128162306a36Sopenharmony_ci * there's an entry here. The first trip around the DQRR ring 128262306a36Sopenharmony_ci * will be much less efficient than all subsequent trips around 128362306a36Sopenharmony_ci * it... 128462306a36Sopenharmony_ci */ 128562306a36Sopenharmony_ci u8 pi = qbman_read_register(s, QBMAN_CINH_SWP_DQPI) & 128662306a36Sopenharmony_ci QMAN_DQRR_PI_MASK; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci /* there are new entries if pi != next_idx */ 128962306a36Sopenharmony_ci if (pi == s->dqrr.next_idx) 129062306a36Sopenharmony_ci return NULL; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* 129362306a36Sopenharmony_ci * if next_idx is/was the last ring index, and 'pi' is 129462306a36Sopenharmony_ci * different, we can disable the workaround as all the ring 129562306a36Sopenharmony_ci * entries have now been DMA'd to so valid-bit checking is 129662306a36Sopenharmony_ci * repaired. Note: this logic needs to be based on next_idx 129762306a36Sopenharmony_ci * (which increments one at a time), rather than on pi (which 129862306a36Sopenharmony_ci * can burst and wrap-around between our snapshots of it). 129962306a36Sopenharmony_ci */ 130062306a36Sopenharmony_ci if (s->dqrr.next_idx == (s->dqrr.dqrr_size - 1)) { 130162306a36Sopenharmony_ci pr_debug("next_idx=%d, pi=%d, clear reset bug\n", 130262306a36Sopenharmony_ci s->dqrr.next_idx, pi); 130362306a36Sopenharmony_ci s->dqrr.reset_bug = 0; 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci prefetch(qbman_get_cmd(s, 130662306a36Sopenharmony_ci QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx)); 131062306a36Sopenharmony_ci verb = p->dq.verb; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* 131362306a36Sopenharmony_ci * If the valid-bit isn't of the expected polarity, nothing there. Note, 131462306a36Sopenharmony_ci * in the DQRR reset bug workaround, we shouldn't need to skip these 131562306a36Sopenharmony_ci * check, because we've already determined that a new entry is available 131662306a36Sopenharmony_ci * and we've invalidated the cacheline before reading it, so the 131762306a36Sopenharmony_ci * valid-bit behaviour is repaired and should tell us what we already 131862306a36Sopenharmony_ci * knew from reading PI. 131962306a36Sopenharmony_ci */ 132062306a36Sopenharmony_ci if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) { 132162306a36Sopenharmony_ci prefetch(qbman_get_cmd(s, 132262306a36Sopenharmony_ci QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); 132362306a36Sopenharmony_ci return NULL; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci /* 132662306a36Sopenharmony_ci * There's something there. Move "next_idx" attention to the next ring 132762306a36Sopenharmony_ci * entry (and prefetch it) before returning what we found. 132862306a36Sopenharmony_ci */ 132962306a36Sopenharmony_ci s->dqrr.next_idx++; 133062306a36Sopenharmony_ci s->dqrr.next_idx &= s->dqrr.dqrr_size - 1; /* Wrap around */ 133162306a36Sopenharmony_ci if (!s->dqrr.next_idx) 133262306a36Sopenharmony_ci s->dqrr.valid_bit ^= QB_VALID_BIT; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci /* 133562306a36Sopenharmony_ci * If this is the final response to a volatile dequeue command 133662306a36Sopenharmony_ci * indicate that the vdq is available 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_ci flags = p->dq.stat; 133962306a36Sopenharmony_ci response_verb = verb & QBMAN_RESULT_MASK; 134062306a36Sopenharmony_ci if ((response_verb == QBMAN_RESULT_DQ) && 134162306a36Sopenharmony_ci (flags & DPAA2_DQ_STAT_VOLATILE) && 134262306a36Sopenharmony_ci (flags & DPAA2_DQ_STAT_EXPIRED)) 134362306a36Sopenharmony_ci atomic_inc(&s->vdq.available); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci prefetch(qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci return p; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci/** 135162306a36Sopenharmony_ci * qbman_swp_dqrr_consume() - Consume DQRR entries previously returned from 135262306a36Sopenharmony_ci * qbman_swp_dqrr_next(). 135362306a36Sopenharmony_ci * @s: the software portal object 135462306a36Sopenharmony_ci * @dq: the DQRR entry to be consumed 135562306a36Sopenharmony_ci */ 135662306a36Sopenharmony_civoid qbman_swp_dqrr_consume(struct qbman_swp *s, const struct dpaa2_dq *dq) 135762306a36Sopenharmony_ci{ 135862306a36Sopenharmony_ci qbman_write_register(s, QBMAN_CINH_SWP_DCAP, QBMAN_IDX_FROM_DQRR(dq)); 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci/** 136262306a36Sopenharmony_ci * qbman_result_has_new_result() - Check and get the dequeue response from the 136362306a36Sopenharmony_ci * dq storage memory set in pull dequeue command 136462306a36Sopenharmony_ci * @s: the software portal object 136562306a36Sopenharmony_ci * @dq: the dequeue result read from the memory 136662306a36Sopenharmony_ci * 136762306a36Sopenharmony_ci * Return 1 for getting a valid dequeue result, or 0 for not getting a valid 136862306a36Sopenharmony_ci * dequeue result. 136962306a36Sopenharmony_ci * 137062306a36Sopenharmony_ci * Only used for user-provided storage of dequeue results, not DQRR. For 137162306a36Sopenharmony_ci * efficiency purposes, the driver will perform any required endianness 137262306a36Sopenharmony_ci * conversion to ensure that the user's dequeue result storage is in host-endian 137362306a36Sopenharmony_ci * format. As such, once the user has called qbman_result_has_new_result() and 137462306a36Sopenharmony_ci * been returned a valid dequeue result, they should not call it again on 137562306a36Sopenharmony_ci * the same memory location (except of course if another dequeue command has 137662306a36Sopenharmony_ci * been executed to produce a new result to that location). 137762306a36Sopenharmony_ci */ 137862306a36Sopenharmony_ciint qbman_result_has_new_result(struct qbman_swp *s, const struct dpaa2_dq *dq) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci if (dq->dq.tok != QMAN_DQ_TOKEN_VALID) 138162306a36Sopenharmony_ci return 0; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci /* 138462306a36Sopenharmony_ci * Set token to be 0 so we will detect change back to 1 138562306a36Sopenharmony_ci * next time the looping is traversed. Const is cast away here 138662306a36Sopenharmony_ci * as we want users to treat the dequeue responses as read only. 138762306a36Sopenharmony_ci */ 138862306a36Sopenharmony_ci ((struct dpaa2_dq *)dq)->dq.tok = 0; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* 139162306a36Sopenharmony_ci * Determine whether VDQCR is available based on whether the 139262306a36Sopenharmony_ci * current result is sitting in the first storage location of 139362306a36Sopenharmony_ci * the busy command. 139462306a36Sopenharmony_ci */ 139562306a36Sopenharmony_ci if (s->vdq.storage == dq) { 139662306a36Sopenharmony_ci s->vdq.storage = NULL; 139762306a36Sopenharmony_ci atomic_inc(&s->vdq.available); 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci return 1; 140162306a36Sopenharmony_ci} 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci/** 140462306a36Sopenharmony_ci * qbman_release_desc_clear() - Clear the contents of a descriptor to 140562306a36Sopenharmony_ci * default/starting state. 140662306a36Sopenharmony_ci * @d: the pull dequeue descriptor to be cleared 140762306a36Sopenharmony_ci */ 140862306a36Sopenharmony_civoid qbman_release_desc_clear(struct qbman_release_desc *d) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci memset(d, 0, sizeof(*d)); 141162306a36Sopenharmony_ci d->verb = 1 << 5; /* Release Command Valid */ 141262306a36Sopenharmony_ci} 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci/** 141562306a36Sopenharmony_ci * qbman_release_desc_set_bpid() - Set the ID of the buffer pool to release to 141662306a36Sopenharmony_ci * @d: the pull dequeue descriptor to be set 141762306a36Sopenharmony_ci * @bpid: the bpid value to be set 141862306a36Sopenharmony_ci */ 141962306a36Sopenharmony_civoid qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci d->bpid = cpu_to_le16(bpid); 142262306a36Sopenharmony_ci} 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci/** 142562306a36Sopenharmony_ci * qbman_release_desc_set_rcdi() - Determines whether or not the portal's RCDI 142662306a36Sopenharmony_ci * interrupt source should be asserted after the release command is completed. 142762306a36Sopenharmony_ci * @d: the pull dequeue descriptor to be set 142862306a36Sopenharmony_ci * @enable: enable (1) or disable (0) value 142962306a36Sopenharmony_ci */ 143062306a36Sopenharmony_civoid qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable) 143162306a36Sopenharmony_ci{ 143262306a36Sopenharmony_ci if (enable) 143362306a36Sopenharmony_ci d->verb |= 1 << 6; 143462306a36Sopenharmony_ci else 143562306a36Sopenharmony_ci d->verb &= ~(1 << 6); 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci#define RAR_IDX(rar) ((rar) & 0x7) 143962306a36Sopenharmony_ci#define RAR_VB(rar) ((rar) & 0x80) 144062306a36Sopenharmony_ci#define RAR_SUCCESS(rar) ((rar) & 0x100) 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci/** 144362306a36Sopenharmony_ci * qbman_swp_release_direct() - Issue a buffer release command 144462306a36Sopenharmony_ci * @s: the software portal object 144562306a36Sopenharmony_ci * @d: the release descriptor 144662306a36Sopenharmony_ci * @buffers: a pointer pointing to the buffer address to be released 144762306a36Sopenharmony_ci * @num_buffers: number of buffers to be released, must be less than 8 144862306a36Sopenharmony_ci * 144962306a36Sopenharmony_ci * Return 0 for success, -EBUSY if the release command ring is not ready. 145062306a36Sopenharmony_ci */ 145162306a36Sopenharmony_ciint qbman_swp_release_direct(struct qbman_swp *s, 145262306a36Sopenharmony_ci const struct qbman_release_desc *d, 145362306a36Sopenharmony_ci const u64 *buffers, unsigned int num_buffers) 145462306a36Sopenharmony_ci{ 145562306a36Sopenharmony_ci int i; 145662306a36Sopenharmony_ci struct qbman_release_desc *p; 145762306a36Sopenharmony_ci u32 rar; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci if (!num_buffers || (num_buffers > 7)) 146062306a36Sopenharmony_ci return -EINVAL; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci rar = qbman_read_register(s, QBMAN_CINH_SWP_RAR); 146362306a36Sopenharmony_ci if (!RAR_SUCCESS(rar)) 146462306a36Sopenharmony_ci return -EBUSY; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci /* Start the release command */ 146762306a36Sopenharmony_ci p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar))); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci /* Copy the caller's buffer pointers to the command */ 147062306a36Sopenharmony_ci for (i = 0; i < num_buffers; i++) 147162306a36Sopenharmony_ci p->buf[i] = cpu_to_le64(buffers[i]); 147262306a36Sopenharmony_ci p->bpid = d->bpid; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci /* 147562306a36Sopenharmony_ci * Set the verb byte, have to substitute in the valid-bit 147662306a36Sopenharmony_ci * and the number of buffers. 147762306a36Sopenharmony_ci */ 147862306a36Sopenharmony_ci dma_wmb(); 147962306a36Sopenharmony_ci p->verb = d->verb | RAR_VB(rar) | num_buffers; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci return 0; 148262306a36Sopenharmony_ci} 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci/** 148562306a36Sopenharmony_ci * qbman_swp_release_mem_back() - Issue a buffer release command 148662306a36Sopenharmony_ci * @s: the software portal object 148762306a36Sopenharmony_ci * @d: the release descriptor 148862306a36Sopenharmony_ci * @buffers: a pointer pointing to the buffer address to be released 148962306a36Sopenharmony_ci * @num_buffers: number of buffers to be released, must be less than 8 149062306a36Sopenharmony_ci * 149162306a36Sopenharmony_ci * Return 0 for success, -EBUSY if the release command ring is not ready. 149262306a36Sopenharmony_ci */ 149362306a36Sopenharmony_ciint qbman_swp_release_mem_back(struct qbman_swp *s, 149462306a36Sopenharmony_ci const struct qbman_release_desc *d, 149562306a36Sopenharmony_ci const u64 *buffers, unsigned int num_buffers) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci int i; 149862306a36Sopenharmony_ci struct qbman_release_desc *p; 149962306a36Sopenharmony_ci u32 rar; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (!num_buffers || (num_buffers > 7)) 150262306a36Sopenharmony_ci return -EINVAL; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci rar = qbman_read_register(s, QBMAN_CINH_SWP_RAR); 150562306a36Sopenharmony_ci if (!RAR_SUCCESS(rar)) 150662306a36Sopenharmony_ci return -EBUSY; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* Start the release command */ 150962306a36Sopenharmony_ci p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR_MEM(RAR_IDX(rar))); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci /* Copy the caller's buffer pointers to the command */ 151262306a36Sopenharmony_ci for (i = 0; i < num_buffers; i++) 151362306a36Sopenharmony_ci p->buf[i] = cpu_to_le64(buffers[i]); 151462306a36Sopenharmony_ci p->bpid = d->bpid; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci p->verb = d->verb | RAR_VB(rar) | num_buffers; 151762306a36Sopenharmony_ci dma_wmb(); 151862306a36Sopenharmony_ci qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT + 151962306a36Sopenharmony_ci RAR_IDX(rar) * 4, QMAN_RT_MODE); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci return 0; 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_cistruct qbman_acquire_desc { 152562306a36Sopenharmony_ci u8 verb; 152662306a36Sopenharmony_ci u8 reserved; 152762306a36Sopenharmony_ci __le16 bpid; 152862306a36Sopenharmony_ci u8 num; 152962306a36Sopenharmony_ci u8 reserved2[59]; 153062306a36Sopenharmony_ci}; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_cistruct qbman_acquire_rslt { 153362306a36Sopenharmony_ci u8 verb; 153462306a36Sopenharmony_ci u8 rslt; 153562306a36Sopenharmony_ci __le16 reserved; 153662306a36Sopenharmony_ci u8 num; 153762306a36Sopenharmony_ci u8 reserved2[3]; 153862306a36Sopenharmony_ci __le64 buf[7]; 153962306a36Sopenharmony_ci}; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci/** 154262306a36Sopenharmony_ci * qbman_swp_acquire() - Issue a buffer acquire command 154362306a36Sopenharmony_ci * @s: the software portal object 154462306a36Sopenharmony_ci * @bpid: the buffer pool index 154562306a36Sopenharmony_ci * @buffers: a pointer pointing to the acquired buffer addresses 154662306a36Sopenharmony_ci * @num_buffers: number of buffers to be acquired, must be less than 8 154762306a36Sopenharmony_ci * 154862306a36Sopenharmony_ci * Return 0 for success, or negative error code if the acquire command 154962306a36Sopenharmony_ci * fails. 155062306a36Sopenharmony_ci */ 155162306a36Sopenharmony_ciint qbman_swp_acquire(struct qbman_swp *s, u16 bpid, u64 *buffers, 155262306a36Sopenharmony_ci unsigned int num_buffers) 155362306a36Sopenharmony_ci{ 155462306a36Sopenharmony_ci struct qbman_acquire_desc *p; 155562306a36Sopenharmony_ci struct qbman_acquire_rslt *r; 155662306a36Sopenharmony_ci int i; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (!num_buffers || (num_buffers > 7)) 155962306a36Sopenharmony_ci return -EINVAL; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci /* Start the management command */ 156262306a36Sopenharmony_ci p = qbman_swp_mc_start(s); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci if (!p) 156562306a36Sopenharmony_ci return -EBUSY; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci /* Encode the caller-provided attributes */ 156862306a36Sopenharmony_ci p->bpid = cpu_to_le16(bpid); 156962306a36Sopenharmony_ci p->num = num_buffers; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci /* Complete the management command */ 157262306a36Sopenharmony_ci r = qbman_swp_mc_complete(s, p, QBMAN_MC_ACQUIRE); 157362306a36Sopenharmony_ci if (unlikely(!r)) { 157462306a36Sopenharmony_ci pr_err("qbman: acquire from BPID %d failed, no response\n", 157562306a36Sopenharmony_ci bpid); 157662306a36Sopenharmony_ci return -EIO; 157762306a36Sopenharmony_ci } 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci /* Decode the outcome */ 158062306a36Sopenharmony_ci WARN_ON((r->verb & 0x7f) != QBMAN_MC_ACQUIRE); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci /* Determine success or failure */ 158362306a36Sopenharmony_ci if (unlikely(r->rslt != QBMAN_MC_RSLT_OK)) { 158462306a36Sopenharmony_ci pr_err("qbman: acquire from BPID 0x%x failed, code=0x%02x\n", 158562306a36Sopenharmony_ci bpid, r->rslt); 158662306a36Sopenharmony_ci return -EIO; 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci WARN_ON(r->num > num_buffers); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci /* Copy the acquired buffers to the caller's array */ 159262306a36Sopenharmony_ci for (i = 0; i < r->num; i++) 159362306a36Sopenharmony_ci buffers[i] = le64_to_cpu(r->buf[i]); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci return (int)r->num; 159662306a36Sopenharmony_ci} 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cistruct qbman_alt_fq_state_desc { 159962306a36Sopenharmony_ci u8 verb; 160062306a36Sopenharmony_ci u8 reserved[3]; 160162306a36Sopenharmony_ci __le32 fqid; 160262306a36Sopenharmony_ci u8 reserved2[56]; 160362306a36Sopenharmony_ci}; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistruct qbman_alt_fq_state_rslt { 160662306a36Sopenharmony_ci u8 verb; 160762306a36Sopenharmony_ci u8 rslt; 160862306a36Sopenharmony_ci u8 reserved[62]; 160962306a36Sopenharmony_ci}; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci#define ALT_FQ_FQID_MASK 0x00FFFFFF 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ciint qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid, 161462306a36Sopenharmony_ci u8 alt_fq_verb) 161562306a36Sopenharmony_ci{ 161662306a36Sopenharmony_ci struct qbman_alt_fq_state_desc *p; 161762306a36Sopenharmony_ci struct qbman_alt_fq_state_rslt *r; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci /* Start the management command */ 162062306a36Sopenharmony_ci p = qbman_swp_mc_start(s); 162162306a36Sopenharmony_ci if (!p) 162262306a36Sopenharmony_ci return -EBUSY; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci p->fqid = cpu_to_le32(fqid & ALT_FQ_FQID_MASK); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci /* Complete the management command */ 162762306a36Sopenharmony_ci r = qbman_swp_mc_complete(s, p, alt_fq_verb); 162862306a36Sopenharmony_ci if (unlikely(!r)) { 162962306a36Sopenharmony_ci pr_err("qbman: mgmt cmd failed, no response (verb=0x%x)\n", 163062306a36Sopenharmony_ci alt_fq_verb); 163162306a36Sopenharmony_ci return -EIO; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci /* Decode the outcome */ 163562306a36Sopenharmony_ci WARN_ON((r->verb & QBMAN_RESULT_MASK) != alt_fq_verb); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci /* Determine success or failure */ 163862306a36Sopenharmony_ci if (unlikely(r->rslt != QBMAN_MC_RSLT_OK)) { 163962306a36Sopenharmony_ci pr_err("qbman: ALT FQID %d failed: verb = 0x%08x code = 0x%02x\n", 164062306a36Sopenharmony_ci fqid, r->verb, r->rslt); 164162306a36Sopenharmony_ci return -EIO; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci return 0; 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_cistruct qbman_cdan_ctrl_desc { 164862306a36Sopenharmony_ci u8 verb; 164962306a36Sopenharmony_ci u8 reserved; 165062306a36Sopenharmony_ci __le16 ch; 165162306a36Sopenharmony_ci u8 we; 165262306a36Sopenharmony_ci u8 ctrl; 165362306a36Sopenharmony_ci __le16 reserved2; 165462306a36Sopenharmony_ci __le64 cdan_ctx; 165562306a36Sopenharmony_ci u8 reserved3[48]; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci}; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_cistruct qbman_cdan_ctrl_rslt { 166062306a36Sopenharmony_ci u8 verb; 166162306a36Sopenharmony_ci u8 rslt; 166262306a36Sopenharmony_ci __le16 ch; 166362306a36Sopenharmony_ci u8 reserved[60]; 166462306a36Sopenharmony_ci}; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ciint qbman_swp_CDAN_set(struct qbman_swp *s, u16 channelid, 166762306a36Sopenharmony_ci u8 we_mask, u8 cdan_en, 166862306a36Sopenharmony_ci u64 ctx) 166962306a36Sopenharmony_ci{ 167062306a36Sopenharmony_ci struct qbman_cdan_ctrl_desc *p = NULL; 167162306a36Sopenharmony_ci struct qbman_cdan_ctrl_rslt *r = NULL; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci /* Start the management command */ 167462306a36Sopenharmony_ci p = qbman_swp_mc_start(s); 167562306a36Sopenharmony_ci if (!p) 167662306a36Sopenharmony_ci return -EBUSY; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci /* Encode the caller-provided attributes */ 167962306a36Sopenharmony_ci p->ch = cpu_to_le16(channelid); 168062306a36Sopenharmony_ci p->we = we_mask; 168162306a36Sopenharmony_ci if (cdan_en) 168262306a36Sopenharmony_ci p->ctrl = 1; 168362306a36Sopenharmony_ci else 168462306a36Sopenharmony_ci p->ctrl = 0; 168562306a36Sopenharmony_ci p->cdan_ctx = cpu_to_le64(ctx); 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci /* Complete the management command */ 168862306a36Sopenharmony_ci r = qbman_swp_mc_complete(s, p, QBMAN_WQCHAN_CONFIGURE); 168962306a36Sopenharmony_ci if (unlikely(!r)) { 169062306a36Sopenharmony_ci pr_err("qbman: wqchan config failed, no response\n"); 169162306a36Sopenharmony_ci return -EIO; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci WARN_ON((r->verb & 0x7f) != QBMAN_WQCHAN_CONFIGURE); 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci /* Determine success or failure */ 169762306a36Sopenharmony_ci if (unlikely(r->rslt != QBMAN_MC_RSLT_OK)) { 169862306a36Sopenharmony_ci pr_err("qbman: CDAN cQID %d failed: code = 0x%02x\n", 169962306a36Sopenharmony_ci channelid, r->rslt); 170062306a36Sopenharmony_ci return -EIO; 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci return 0; 170462306a36Sopenharmony_ci} 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci#define QBMAN_RESPONSE_VERB_MASK 0x7f 170762306a36Sopenharmony_ci#define QBMAN_FQ_QUERY_NP 0x45 170862306a36Sopenharmony_ci#define QBMAN_BP_QUERY 0x32 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_cistruct qbman_fq_query_desc { 171162306a36Sopenharmony_ci u8 verb; 171262306a36Sopenharmony_ci u8 reserved[3]; 171362306a36Sopenharmony_ci __le32 fqid; 171462306a36Sopenharmony_ci u8 reserved2[56]; 171562306a36Sopenharmony_ci}; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ciint qbman_fq_query_state(struct qbman_swp *s, u32 fqid, 171862306a36Sopenharmony_ci struct qbman_fq_query_np_rslt *r) 171962306a36Sopenharmony_ci{ 172062306a36Sopenharmony_ci struct qbman_fq_query_desc *p; 172162306a36Sopenharmony_ci void *resp; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci p = (struct qbman_fq_query_desc *)qbman_swp_mc_start(s); 172462306a36Sopenharmony_ci if (!p) 172562306a36Sopenharmony_ci return -EBUSY; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci /* FQID is a 24 bit value */ 172862306a36Sopenharmony_ci p->fqid = cpu_to_le32(fqid & 0x00FFFFFF); 172962306a36Sopenharmony_ci resp = qbman_swp_mc_complete(s, p, QBMAN_FQ_QUERY_NP); 173062306a36Sopenharmony_ci if (!resp) { 173162306a36Sopenharmony_ci pr_err("qbman: Query FQID %d NP fields failed, no response\n", 173262306a36Sopenharmony_ci fqid); 173362306a36Sopenharmony_ci return -EIO; 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci *r = *(struct qbman_fq_query_np_rslt *)resp; 173662306a36Sopenharmony_ci /* Decode the outcome */ 173762306a36Sopenharmony_ci WARN_ON((r->verb & QBMAN_RESPONSE_VERB_MASK) != QBMAN_FQ_QUERY_NP); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci /* Determine success or failure */ 174062306a36Sopenharmony_ci if (r->rslt != QBMAN_MC_RSLT_OK) { 174162306a36Sopenharmony_ci pr_err("Query NP fields of FQID 0x%x failed, code=0x%02x\n", 174262306a36Sopenharmony_ci p->fqid, r->rslt); 174362306a36Sopenharmony_ci return -EIO; 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci return 0; 174762306a36Sopenharmony_ci} 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ciu32 qbman_fq_state_frame_count(const struct qbman_fq_query_np_rslt *r) 175062306a36Sopenharmony_ci{ 175162306a36Sopenharmony_ci return (le32_to_cpu(r->frm_cnt) & 0x00FFFFFF); 175262306a36Sopenharmony_ci} 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ciu32 qbman_fq_state_byte_count(const struct qbman_fq_query_np_rslt *r) 175562306a36Sopenharmony_ci{ 175662306a36Sopenharmony_ci return le32_to_cpu(r->byte_cnt); 175762306a36Sopenharmony_ci} 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_cistruct qbman_bp_query_desc { 176062306a36Sopenharmony_ci u8 verb; 176162306a36Sopenharmony_ci u8 reserved; 176262306a36Sopenharmony_ci __le16 bpid; 176362306a36Sopenharmony_ci u8 reserved2[60]; 176462306a36Sopenharmony_ci}; 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ciint qbman_bp_query(struct qbman_swp *s, u16 bpid, 176762306a36Sopenharmony_ci struct qbman_bp_query_rslt *r) 176862306a36Sopenharmony_ci{ 176962306a36Sopenharmony_ci struct qbman_bp_query_desc *p; 177062306a36Sopenharmony_ci void *resp; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci p = (struct qbman_bp_query_desc *)qbman_swp_mc_start(s); 177362306a36Sopenharmony_ci if (!p) 177462306a36Sopenharmony_ci return -EBUSY; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci p->bpid = cpu_to_le16(bpid); 177762306a36Sopenharmony_ci resp = qbman_swp_mc_complete(s, p, QBMAN_BP_QUERY); 177862306a36Sopenharmony_ci if (!resp) { 177962306a36Sopenharmony_ci pr_err("qbman: Query BPID %d fields failed, no response\n", 178062306a36Sopenharmony_ci bpid); 178162306a36Sopenharmony_ci return -EIO; 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci *r = *(struct qbman_bp_query_rslt *)resp; 178462306a36Sopenharmony_ci /* Decode the outcome */ 178562306a36Sopenharmony_ci WARN_ON((r->verb & QBMAN_RESPONSE_VERB_MASK) != QBMAN_BP_QUERY); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci /* Determine success or failure */ 178862306a36Sopenharmony_ci if (r->rslt != QBMAN_MC_RSLT_OK) { 178962306a36Sopenharmony_ci pr_err("Query fields of BPID 0x%x failed, code=0x%02x\n", 179062306a36Sopenharmony_ci bpid, r->rslt); 179162306a36Sopenharmony_ci return -EIO; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci return 0; 179562306a36Sopenharmony_ci} 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ciu32 qbman_bp_info_num_free_bufs(struct qbman_bp_query_rslt *a) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci return le32_to_cpu(a->fill); 180062306a36Sopenharmony_ci} 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci/** 180362306a36Sopenharmony_ci * qbman_swp_set_irq_coalescing() - Set new IRQ coalescing values 180462306a36Sopenharmony_ci * @p: the software portal object 180562306a36Sopenharmony_ci * @irq_threshold: interrupt threshold 180662306a36Sopenharmony_ci * @irq_holdoff: interrupt holdoff (timeout) period in us 180762306a36Sopenharmony_ci * 180862306a36Sopenharmony_ci * Return 0 for success, or negative error code on error. 180962306a36Sopenharmony_ci */ 181062306a36Sopenharmony_ciint qbman_swp_set_irq_coalescing(struct qbman_swp *p, u32 irq_threshold, 181162306a36Sopenharmony_ci u32 irq_holdoff) 181262306a36Sopenharmony_ci{ 181362306a36Sopenharmony_ci u32 itp, max_holdoff; 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci /* Convert irq_holdoff value from usecs to 256 QBMAN clock cycles 181662306a36Sopenharmony_ci * increments. This depends on the QBMAN internal frequency. 181762306a36Sopenharmony_ci */ 181862306a36Sopenharmony_ci itp = (irq_holdoff * 1000) / p->desc->qman_256_cycles_per_ns; 181962306a36Sopenharmony_ci if (itp > 4096) { 182062306a36Sopenharmony_ci max_holdoff = (p->desc->qman_256_cycles_per_ns * 4096) / 1000; 182162306a36Sopenharmony_ci pr_err("irq_holdoff must be <= %uus\n", max_holdoff); 182262306a36Sopenharmony_ci return -EINVAL; 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci if (irq_threshold >= p->dqrr.dqrr_size) { 182662306a36Sopenharmony_ci pr_err("irq_threshold must be < %u\n", p->dqrr.dqrr_size - 1); 182762306a36Sopenharmony_ci return -EINVAL; 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci p->irq_threshold = irq_threshold; 183162306a36Sopenharmony_ci p->irq_holdoff = irq_holdoff; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_DQRR_ITR, irq_threshold); 183462306a36Sopenharmony_ci qbman_write_register(p, QBMAN_CINH_SWP_ITPR, itp); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci return 0; 183762306a36Sopenharmony_ci} 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci/** 184062306a36Sopenharmony_ci * qbman_swp_get_irq_coalescing() - Get the current IRQ coalescing parameters 184162306a36Sopenharmony_ci * @p: the software portal object 184262306a36Sopenharmony_ci * @irq_threshold: interrupt threshold (an IRQ is generated when there are more 184362306a36Sopenharmony_ci * DQRR entries in the portal than the threshold) 184462306a36Sopenharmony_ci * @irq_holdoff: interrupt holdoff (timeout) period in us 184562306a36Sopenharmony_ci */ 184662306a36Sopenharmony_civoid qbman_swp_get_irq_coalescing(struct qbman_swp *p, u32 *irq_threshold, 184762306a36Sopenharmony_ci u32 *irq_holdoff) 184862306a36Sopenharmony_ci{ 184962306a36Sopenharmony_ci if (irq_threshold) 185062306a36Sopenharmony_ci *irq_threshold = p->irq_threshold; 185162306a36Sopenharmony_ci if (irq_holdoff) 185262306a36Sopenharmony_ci *irq_holdoff = p->irq_holdoff; 185362306a36Sopenharmony_ci} 1854