diff options
Diffstat (limited to 'drivers/soc/fsl/dpio/qbman-portal.c')
-rw-r--r-- | drivers/soc/fsl/dpio/qbman-portal.c | 75 |
1 files changed, 65 insertions, 10 deletions
diff --git a/drivers/soc/fsl/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c index f13da4d7d1c5..058b78fac5e3 100644 --- a/drivers/soc/fsl/dpio/qbman-portal.c +++ b/drivers/soc/fsl/dpio/qbman-portal.c @@ -29,6 +29,7 @@ #define QBMAN_CINH_SWP_EQCR_AM_RT 0x980 #define QBMAN_CINH_SWP_RCR_AM_RT 0x9c0 #define QBMAN_CINH_SWP_DQPI 0xa00 +#define QBMAN_CINH_SWP_DQRR_ITR 0xa80 #define QBMAN_CINH_SWP_DCAP 0xac0 #define QBMAN_CINH_SWP_SDQCR 0xb00 #define QBMAN_CINH_SWP_EQCR_AM_RT2 0xb40 @@ -38,6 +39,7 @@ #define QBMAN_CINH_SWP_IER 0xe40 #define QBMAN_CINH_SWP_ISDR 0xe80 #define QBMAN_CINH_SWP_IIR 0xec0 +#define QBMAN_CINH_SWP_ITPR 0xf40 /* CENA register offsets */ #define QBMAN_CENA_SWP_EQCR(n) (0x000 + ((u32)(n) << 6)) @@ -355,6 +357,9 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) & p->eqcr.pi_ci_mask; p->eqcr.available = p->eqcr.pi_ring_size; + /* Initialize the software portal with a irq timeout period of 0us */ + qbman_swp_set_irq_coalescing(p, p->dqrr.dqrr_size - 1, 0); + return p; } @@ -688,9 +693,9 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s, p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); p[0] = cl[0] | s->eqcr.pi_vb; if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) { - struct qbman_eq_desc *d = (struct qbman_eq_desc *)p; + struct qbman_eq_desc *eq_desc = (struct qbman_eq_desc *)p; - d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) | + eq_desc->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) | ((flags[i]) & QBMAN_EQCR_DCA_IDXMASK); } eqcr_pi++; @@ -732,8 +737,7 @@ int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s, int i, num_enqueued = 0; unsigned long irq_flags; - spin_lock(&s->access_spinlock); - local_irq_save(irq_flags); + spin_lock_irqsave(&s->access_spinlock, irq_flags); half_mask = (s->eqcr.pi_ci_mask>>1); full_mask = s->eqcr.pi_ci_mask; @@ -744,8 +748,7 @@ int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s, s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size, eqcr_ci, s->eqcr.ci); if (!s->eqcr.available) { - local_irq_restore(irq_flags); - spin_unlock(&s->access_spinlock); + spin_unlock_irqrestore(&s->access_spinlock, irq_flags); return 0; } } @@ -770,9 +773,9 @@ int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s, p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); p[0] = cl[0] | s->eqcr.pi_vb; if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) { - struct qbman_eq_desc *d = (struct qbman_eq_desc *)p; + struct qbman_eq_desc *eq_desc = (struct qbman_eq_desc *)p; - d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) | + eq_desc->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) | ((flags[i]) & QBMAN_EQCR_DCA_IDXMASK); } eqcr_pi++; @@ -784,8 +787,7 @@ int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s, dma_wmb(); qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI, (QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb); - local_irq_restore(irq_flags); - spin_unlock(&s->access_spinlock); + spin_unlock_irqrestore(&s->access_spinlock, irq_flags); return num_enqueued; } @@ -1796,3 +1798,56 @@ u32 qbman_bp_info_num_free_bufs(struct qbman_bp_query_rslt *a) { return le32_to_cpu(a->fill); } + +/** + * qbman_swp_set_irq_coalescing() - Set new IRQ coalescing values + * @p: the software portal object + * @irq_threshold: interrupt threshold + * @irq_holdoff: interrupt holdoff (timeout) period in us + * + * Return 0 for success, or negative error code on error. + */ +int qbman_swp_set_irq_coalescing(struct qbman_swp *p, u32 irq_threshold, + u32 irq_holdoff) +{ + u32 itp, max_holdoff; + + /* Convert irq_holdoff value from usecs to 256 QBMAN clock cycles + * increments. This depends on the QBMAN internal frequency. + */ + itp = (irq_holdoff * 1000) / p->desc->qman_256_cycles_per_ns; + if (itp > 4096) { + max_holdoff = (p->desc->qman_256_cycles_per_ns * 4096) / 1000; + pr_err("irq_holdoff must be <= %uus\n", max_holdoff); + return -EINVAL; + } + + if (irq_threshold >= p->dqrr.dqrr_size) { + pr_err("irq_threshold must be < %u\n", p->dqrr.dqrr_size - 1); + return -EINVAL; + } + + p->irq_threshold = irq_threshold; + p->irq_holdoff = irq_holdoff; + + qbman_write_register(p, QBMAN_CINH_SWP_DQRR_ITR, irq_threshold); + qbman_write_register(p, QBMAN_CINH_SWP_ITPR, itp); + + return 0; +} + +/** + * qbman_swp_get_irq_coalescing() - Get the current IRQ coalescing parameters + * @p: the software portal object + * @irq_threshold: interrupt threshold (an IRQ is generated when there are more + * DQRR entries in the portal than the threshold) + * @irq_holdoff: interrupt holdoff (timeout) period in us + */ +void qbman_swp_get_irq_coalescing(struct qbman_swp *p, u32 *irq_threshold, + u32 *irq_holdoff) +{ + if (irq_threshold) + *irq_threshold = p->irq_threshold; + if (irq_holdoff) + *irq_holdoff = p->irq_holdoff; +} |