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:
parent
2cf0b6fe9b
commit
ed1d2143fe
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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 */
|
||||||
|
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user