Commit ed1d2143 authored by Ioana Ciornei's avatar Ioana Ciornei Committed by David S. Miller
Browse files

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: default avatarIoana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2cf0b6fe
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc,
				 struct device *dev)
{
	struct dpaa2_io *obj = kmalloc(sizeof(*obj), GFP_KERNEL);
	u32 qman_256_cycles_per_ns;

	if (!obj)
		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.qman_clk = obj->dpio_desc.qman_clk;
	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);

	if (!obj->swp) {
@@ -780,3 +788,32 @@ int dpaa2_io_query_bp_count(struct dpaa2_io *d, u16 bpid, u32 *num)
	return 0;
}
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);
+59 −0
Original line number Diff line number Diff line
@@ -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;
}

@@ -1796,3 +1801,57 @@ 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 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;
}
+11 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ struct qbman_swp_desc {
	void __iomem *cinh_bar; /* Cache-inhibited portal base address */
	u32 qman_version;
	u32 qman_clk;
	u32 qman_256_cycles_per_ns;
};

#define QBMAN_SWP_INTERRUPT_EQRI 0x01
@@ -157,6 +158,10 @@ struct qbman_swp {
	} eqcr;

	spinlock_t access_spinlock;

	/* Interrupt coalescing */
	u32 irq_threshold;
	u32 irq_holdoff;
};

/* 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);
}

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 */
+4 −0
Original line number Diff line number Diff line
@@ -131,4 +131,8 @@ int dpaa2_io_query_fq_count(struct dpaa2_io *d, u32 fqid,
			    u32 *fcnt, u32 *bcnt);
int dpaa2_io_query_bp_count(struct dpaa2_io *d, u16 bpid,
			    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 */