soc: fsl: dpio: add support for irq coalescing per software portal

In DPAA2 based SoCs, the IRQ coalesing support per software portal has 2
configurable parameters:
 - the IRQ timeout period (QBMAN_CINH_SWP_ITPR): how many 256 QBMAN
   cycles need to pass until a dequeue interrupt is asserted.
 - the IRQ threshold (QBMAN_CINH_SWP_DQRR_ITR): how many dequeue
   responses in the DQRR ring would generate an IRQ.

Add support for setting up and querying these IRQ coalescing related
parameters.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Ioana Ciornei 2021-10-15 12:01:24 +03:00 committed by David S. Miller
parent 2cf0b6fe9b
commit ed1d2143fe
4 changed files with 111 additions and 0 deletions

View File

@ -114,6 +114,7 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc,
struct device *dev) struct device *dev)
{ {
struct dpaa2_io *obj = kmalloc(sizeof(*obj), GFP_KERNEL); struct dpaa2_io *obj = kmalloc(sizeof(*obj), GFP_KERNEL);
u32 qman_256_cycles_per_ns;
if (!obj) if (!obj)
return NULL; return NULL;
@ -129,6 +130,13 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc,
obj->swp_desc.cinh_bar = obj->dpio_desc.regs_cinh; obj->swp_desc.cinh_bar = obj->dpio_desc.regs_cinh;
obj->swp_desc.qman_clk = obj->dpio_desc.qman_clk; obj->swp_desc.qman_clk = obj->dpio_desc.qman_clk;
obj->swp_desc.qman_version = obj->dpio_desc.qman_version; obj->swp_desc.qman_version = obj->dpio_desc.qman_version;
/* Compute how many 256 QBMAN cycles fit into one ns. This is because
* the interrupt timeout period register needs to be specified in QBMAN
* clock cycles in increments of 256.
*/
qman_256_cycles_per_ns = 256000 / (obj->swp_desc.qman_clk / 1000000);
obj->swp_desc.qman_256_cycles_per_ns = qman_256_cycles_per_ns;
obj->swp = qbman_swp_init(&obj->swp_desc); obj->swp = qbman_swp_init(&obj->swp_desc);
if (!obj->swp) { if (!obj->swp) {
@ -780,3 +788,32 @@ int dpaa2_io_query_bp_count(struct dpaa2_io *d, u16 bpid, u32 *num)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(dpaa2_io_query_bp_count); EXPORT_SYMBOL_GPL(dpaa2_io_query_bp_count);
/**
* dpaa2_io_set_irq_coalescing() - Set new IRQ coalescing values
* @d: the given DPIO object
* @irq_holdoff: interrupt holdoff (timeout) period in us
*
* Return 0 for success, or negative error code on error.
*/
int dpaa2_io_set_irq_coalescing(struct dpaa2_io *d, u32 irq_holdoff)
{
struct qbman_swp *swp = d->swp;
return qbman_swp_set_irq_coalescing(swp, swp->dqrr.dqrr_size - 1,
irq_holdoff);
}
EXPORT_SYMBOL(dpaa2_io_set_irq_coalescing);
/**
* dpaa2_io_get_irq_coalescing() - Get the current IRQ coalescing parameters
* @d: the given DPIO object
* @irq_holdoff: interrupt holdoff (timeout) period in us
*/
void dpaa2_io_get_irq_coalescing(struct dpaa2_io *d, u32 *irq_holdoff)
{
struct qbman_swp *swp = d->swp;
qbman_swp_get_irq_coalescing(swp, NULL, irq_holdoff);
}
EXPORT_SYMBOL(dpaa2_io_get_irq_coalescing);

View File

@ -29,6 +29,7 @@
#define QBMAN_CINH_SWP_EQCR_AM_RT 0x980 #define QBMAN_CINH_SWP_EQCR_AM_RT 0x980
#define QBMAN_CINH_SWP_RCR_AM_RT 0x9c0 #define QBMAN_CINH_SWP_RCR_AM_RT 0x9c0
#define QBMAN_CINH_SWP_DQPI 0xa00 #define QBMAN_CINH_SWP_DQPI 0xa00
#define QBMAN_CINH_SWP_DQRR_ITR 0xa80
#define QBMAN_CINH_SWP_DCAP 0xac0 #define QBMAN_CINH_SWP_DCAP 0xac0
#define QBMAN_CINH_SWP_SDQCR 0xb00 #define QBMAN_CINH_SWP_SDQCR 0xb00
#define QBMAN_CINH_SWP_EQCR_AM_RT2 0xb40 #define QBMAN_CINH_SWP_EQCR_AM_RT2 0xb40
@ -38,6 +39,7 @@
#define QBMAN_CINH_SWP_IER 0xe40 #define QBMAN_CINH_SWP_IER 0xe40
#define QBMAN_CINH_SWP_ISDR 0xe80 #define QBMAN_CINH_SWP_ISDR 0xe80
#define QBMAN_CINH_SWP_IIR 0xec0 #define QBMAN_CINH_SWP_IIR 0xec0
#define QBMAN_CINH_SWP_ITPR 0xf40
/* CENA register offsets */ /* CENA register offsets */
#define QBMAN_CENA_SWP_EQCR(n) (0x000 + ((u32)(n) << 6)) #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.pi_ci_mask;
p->eqcr.available = p->eqcr.pi_ring_size; 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; return p;
} }
@ -1796,3 +1801,57 @@ u32 qbman_bp_info_num_free_bufs(struct qbman_bp_query_rslt *a)
{ {
return le32_to_cpu(a->fill); 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 to the QBMAN internal frequency.
*/
itp = (irq_holdoff * 1000) / p->desc->qman_256_cycles_per_ns;
if (itp < 0 || itp > 4096) {
max_holdoff = (p->desc->qman_256_cycles_per_ns * 4096) / 1000;
pr_err("irq_holdoff must be between 0..%dus\n", max_holdoff);
return -EINVAL;
}
if (irq_threshold >= p->dqrr.dqrr_size || irq_threshold < 0) {
pr_err("irq_threshold must be between 0..%d\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;
}

View File

@ -25,6 +25,7 @@ struct qbman_swp_desc {
void __iomem *cinh_bar; /* Cache-inhibited portal base address */ void __iomem *cinh_bar; /* Cache-inhibited portal base address */
u32 qman_version; u32 qman_version;
u32 qman_clk; u32 qman_clk;
u32 qman_256_cycles_per_ns;
}; };
#define QBMAN_SWP_INTERRUPT_EQRI 0x01 #define QBMAN_SWP_INTERRUPT_EQRI 0x01
@ -157,6 +158,10 @@ struct qbman_swp {
} eqcr; } eqcr;
spinlock_t access_spinlock; spinlock_t access_spinlock;
/* Interrupt coalescing */
u32 irq_threshold;
u32 irq_holdoff;
}; };
/* Function pointers */ /* Function pointers */
@ -649,4 +654,10 @@ static inline const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
return qbman_swp_dqrr_next_ptr(s); return qbman_swp_dqrr_next_ptr(s);
} }
int qbman_swp_set_irq_coalescing(struct qbman_swp *p, u32 irq_threshold,
u32 irq_holdoff);
void qbman_swp_get_irq_coalescing(struct qbman_swp *p, u32 *irq_threshold,
u32 *irq_holdoff);
#endif /* __FSL_QBMAN_PORTAL_H */ #endif /* __FSL_QBMAN_PORTAL_H */

View File

@ -131,4 +131,8 @@ int dpaa2_io_query_fq_count(struct dpaa2_io *d, u32 fqid,
u32 *fcnt, u32 *bcnt); u32 *fcnt, u32 *bcnt);
int dpaa2_io_query_bp_count(struct dpaa2_io *d, u16 bpid, int dpaa2_io_query_bp_count(struct dpaa2_io *d, u16 bpid,
u32 *num); u32 *num);
int dpaa2_io_set_irq_coalescing(struct dpaa2_io *d, u32 irq_holdoff);
void dpaa2_io_get_irq_coalescing(struct dpaa2_io *d, u32 *irq_holdoff);
#endif /* __FSL_DPAA2_IO_H */ #endif /* __FSL_DPAA2_IO_H */