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

soc: fsl: dpio: add Net DIM integration



Use the generic dynamic interrupt moderation (dim) framework to
implement adaptive interrupt coalescing on Rx. With the per-packet
interrupt scheme, a high interrupt rate has been noted for moderate
traffic flows leading to high CPU utilization.

The dpio driver exports new functions to enable/disable adaptive IRQ
coalescing on a DPIO object, to query the state or to update Net DIM
with a new set of bytes and frames dequeued.

Signed-off-by: default avatarIoana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a64b4421
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ config FSL_MC_DPIO
        tristate "QorIQ DPAA2 DPIO driver"
        depends on FSL_MC_BUS
        select SOC_BUS
        select DIMLIB
        help
	  Driver for the DPAA2 DPIO object.  A DPIO provides queue and
	  buffer management facilities for software to interact with
+79 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/dim.h>
#include <linux/slab.h>

#include "dpio.h"
@@ -28,6 +29,14 @@ struct dpaa2_io {
	spinlock_t lock_notifications;
	struct list_head notifications;
	struct device *dev;

	/* Net DIM */
	struct dim rx_dim;
	/* protect against concurrent Net DIM updates */
	spinlock_t dim_lock;
	u16 event_ctr;
	u64 bytes;
	u64 frames;
};

struct dpaa2_io_store {
@@ -100,6 +109,17 @@ struct dpaa2_io *dpaa2_io_service_select(int cpu)
}
EXPORT_SYMBOL_GPL(dpaa2_io_service_select);

static void dpaa2_io_dim_work(struct work_struct *w)
{
	struct dim *dim = container_of(w, struct dim, work);
	struct dim_cq_moder moder =
		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
	struct dpaa2_io *d = container_of(dim, struct dpaa2_io, rx_dim);

	dpaa2_io_set_irq_coalescing(d, moder.usec);
	dim->state = DIM_START_MEASURE;
}

/**
 * dpaa2_io_create() - create a dpaa2_io object.
 * @desc: the dpaa2_io descriptor
@@ -147,6 +167,7 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc,
	INIT_LIST_HEAD(&obj->node);
	spin_lock_init(&obj->lock_mgmt_cmd);
	spin_lock_init(&obj->lock_notifications);
	spin_lock_init(&obj->dim_lock);
	INIT_LIST_HEAD(&obj->notifications);

	/* For now only enable DQRR interrupts */
@@ -164,6 +185,12 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc,

	obj->dev = dev;

	memset(&obj->rx_dim, 0, sizeof(obj->rx_dim));
	INIT_WORK(&obj->rx_dim.work, dpaa2_io_dim_work);
	obj->event_ctr = 0;
	obj->bytes = 0;
	obj->frames = 0;

	return obj;
}

@@ -203,6 +230,8 @@ irqreturn_t dpaa2_io_irq(struct dpaa2_io *obj)
	struct qbman_swp *swp;
	u32 status;

	obj->event_ctr++;

	swp = obj->swp;
	status = qbman_swp_interrupt_read_status(swp);
	if (!status)
@@ -817,3 +846,53 @@ void dpaa2_io_get_irq_coalescing(struct dpaa2_io *d, u32 *irq_holdoff)
	qbman_swp_get_irq_coalescing(swp, NULL, irq_holdoff);
}
EXPORT_SYMBOL(dpaa2_io_get_irq_coalescing);

/**
 * dpaa2_io_set_adaptive_coalescing() - Enable/disable adaptive coalescing
 * @d: the given DPIO object
 * @use_adaptive_rx_coalesce: adaptive coalescing state
 */
void dpaa2_io_set_adaptive_coalescing(struct dpaa2_io *d,
				      int use_adaptive_rx_coalesce)
{
	d->swp->use_adaptive_rx_coalesce = use_adaptive_rx_coalesce;
}
EXPORT_SYMBOL(dpaa2_io_set_adaptive_coalescing);

/**
 * dpaa2_io_get_adaptive_coalescing() - Query adaptive coalescing state
 * @d: the given DPIO object
 *
 * Return 1 when adaptive coalescing is enabled on the DPIO object and 0
 * otherwise.
 */
int dpaa2_io_get_adaptive_coalescing(struct dpaa2_io *d)
{
	return d->swp->use_adaptive_rx_coalesce;
}
EXPORT_SYMBOL(dpaa2_io_get_adaptive_coalescing);

/**
 * dpaa2_io_update_net_dim() - Update Net DIM
 * @d: the given DPIO object
 * @frames: how many frames have been dequeued by the user since the last call
 * @bytes: how many bytes have been dequeued by the user since the last call
 */
void dpaa2_io_update_net_dim(struct dpaa2_io *d, __u64 frames, __u64 bytes)
{
	struct dim_sample dim_sample = {};

	if (!d->swp->use_adaptive_rx_coalesce)
		return;

	spin_lock(&d->dim_lock);

	d->bytes += bytes;
	d->frames += frames;

	dim_update_sample(d->event_ctr, d->frames, d->bytes, &dim_sample);
	net_dim(&d->rx_dim, dim_sample);

	spin_unlock(&d->dim_lock);
}
EXPORT_SYMBOL(dpaa2_io_update_net_dim);
+1 −0
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ struct qbman_swp {
	/* Interrupt coalescing */
	u32 irq_threshold;
	u32 irq_holdoff;
	int use_adaptive_rx_coalesce;
};

/* Function pointers */
+4 −1
Original line number Diff line number Diff line
@@ -134,5 +134,8 @@ int dpaa2_io_query_bp_count(struct dpaa2_io *d, u16 bpid,

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);

void dpaa2_io_set_adaptive_coalescing(struct dpaa2_io *d,
				      int use_adaptive_rx_coalesce);
int dpaa2_io_get_adaptive_coalescing(struct dpaa2_io *d);
void dpaa2_io_update_net_dim(struct dpaa2_io *d, __u64 frames, __u64 bytes);
#endif /* __FSL_DPAA2_IO_H */