[PATCH V7 RESEND 07/10] can: mcp25xxfd: optimize TEF reads reading multiple TEFs in one go

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Martin Sperl <kernel@xxxxxxxxxxxxxxxx>

To reduce the amount of spi_messages send this patch optimizes the
read TEF so that multiple TEFs are read together.

Statistics in debugfs show for 100000 DLC=0 can messages sent:
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_conservative_reads
0
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_optimized_reads
44691
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_optimized_reads_1
1862
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_optimized_reads_2
30349
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_optimized_reads_3
12480
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_optimized_reads_4
0
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_optimized_reads_5
0
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_optimized_reads_6
0
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_optimized_reads_7
0
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_optimized_reads_8+
0
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_reads
100000
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/tef_read_splits
0

So to read all of those 100000 TEF frames to read we formerly have
scheduled 100000 spi_messages.
While with this patch we have only scheduled 44691 spi_messages, so
only 44.6% of the former value.
This also means we have not been transferring 110618 (=2*30349+2*2*12480)
unnecessary command bytes over the SPI bus.

Signed-off-by: Martin Sperl <kernel@xxxxxxxxxxxxxxxx>
---
 .../net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c  | 18 +++++
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h |  7 ++
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c   | 85 +++++++++++++++++++---
 3 files changed, 101 insertions(+), 9 deletions(-)

diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c
index 4f7d5d8633c3..90034ea21c49 100644
--- a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c
@@ -43,6 +43,9 @@ static void mcp25xxfd_can_debugfs_stats(struct mcp25xxfd_can_priv *cpriv,
 					struct dentry *root)
 {
 	struct dentry *dir = debugfs_create_dir("stats", root);
+	char name[32];
+	u64 *data;
+	int i;

 # define DEBUGFS_CREATE(name, var) debugfs_create_u64(name, 0444, dir, \
 						      &cpriv->stats.var)
@@ -62,6 +65,21 @@ static void mcp25xxfd_can_debugfs_stats(struct mcp25xxfd_can_priv *cpriv,
 	DEBUGFS_CREATE("int_rx_invalid_message", int_ivm_count);
 	DEBUGFS_CREATE("int_crcerror",		 int_cerr_count);

+	DEBUGFS_CREATE("tef_reads",		 tef_reads);
+	DEBUGFS_CREATE("tef_conservative_reads", tef_conservative_reads);
+	DEBUGFS_CREATE("tef_optimized_reads",	 tef_optimized_reads);
+	DEBUGFS_CREATE("tef_read_splits",	 tef_read_splits);
+
+	for (i = 0; i < MCP25XXFD_CAN_TEF_READ_BINS - 1; i++) {
+		snprintf(name, sizeof(name),
+			 "tef_optimized_reads_%i", i + 1);
+		data = &cpriv->stats.tef_optimized_read_sizes[i];
+		debugfs_create_u64(name, 0444, dir, data);
+	}
+	snprintf(name, sizeof(name), "tef_optimized_reads_%i+", i + 1);
+	debugfs_create_u64(name, 0444, dir,
+			   &cpriv->stats.tef_optimized_read_sizes[i]);
+
 	DEBUGFS_CREATE("tx_frames_fd",		 tx_fd_count);
 	DEBUGFS_CREATE("tx_frames_brs",		 tx_brs_count);

diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h
index 5727d4608dfd..766bec350e1e 100644
--- a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h
@@ -155,6 +155,13 @@ struct mcp25xxfd_can_priv {
 		u64 tx_fd_count;
 		u64 tx_brs_count;

+		u64 tef_reads;
+		u64 tef_read_splits;
+		u64 tef_conservative_reads;
+		u64 tef_optimized_reads;
+#define MCP25XXFD_CAN_TEF_READ_BINS 8
+		u64 tef_optimized_read_sizes[MCP25XXFD_CAN_TEF_READ_BINS];
+
 		u64 rx_reads;
 		u64 rx_reads_prefetched_too_few;
 		u64 rx_reads_prefetched_too_few_bytes;
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c
index 0d08bc9768d9..13cb898247fe 100644
--- a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c
@@ -233,21 +233,62 @@ void mcp25xxfd_can_tx_queue_restart(struct mcp25xxfd_can_priv *cpriv)
 }

 static
-int mcp25xxfd_can_tx_handle_int_tefif_fifo(struct mcp25xxfd_can_priv *cpriv)
+int mcp25xxfd_can_tx_tef_read(struct mcp25xxfd_can_priv *cpriv,
+			      int start, int count)
 {
-	u32 tef_offset = cpriv->fifos.tef.index * cpriv->fifos.tef.size;
+	u32 tef_offset = start * cpriv->fifos.tef.size;
 	struct mcp25xxfd_can_obj_tef *tef =
 		(struct mcp25xxfd_can_obj_tef *)(cpriv->sram + tef_offset);
-	int fifo, ret;
-	unsigned long flags;
+	int last, read, ret;

-	/* read the next TEF entry to get the transmit timestamp and fifo */
+	/* compute how many we can read in one go */
+	last = start + count;
+	read = (last > cpriv->fifos.tef.count) ?
+		(cpriv->fifos.tef.count - start) :
+		count;
+
+	/* and read it */
 	ret = mcp25xxfd_cmd_read_regs(cpriv->priv->spi,
 				      MCP25XXFD_SRAM_ADDR(tef_offset),
-				      &tef->id, sizeof(*tef));
+				      &tef->id, sizeof(*tef) * read);
 	if (ret)
 		return ret;

+	/* and read a second part on wrap */
+	if (read != count) {
+		/* update stats */
+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_read_splits);
+		/* compute the addresses  */
+		read = count - read;
+		tef = (struct mcp25xxfd_can_obj_tef *)(cpriv->sram);
+		/* and read again */
+		ret = mcp25xxfd_cmd_read_regs(cpriv->priv->spi,
+					      MCP25XXFD_SRAM_ADDR(0),
+					      &tef->id,
+					      sizeof(*tef) * read);
+	}
+
+	return ret;
+}
+
+static
+int mcp25xxfd_can_tx_handle_int_tefif_fifo(struct mcp25xxfd_can_priv *cpriv,
+					   bool read_data)
+{
+	u32 tef_offset = cpriv->fifos.tef.index * cpriv->fifos.tef.size;
+	struct mcp25xxfd_can_obj_tef *tef =
+		(struct mcp25xxfd_can_obj_tef *)(cpriv->sram + tef_offset);
+	int fifo, ret;
+	unsigned long flags;
+
+	/* read the next TEF entry to get the transmit timestamp and fifo */
+	if (read_data) {
+		ret = mcp25xxfd_can_tx_tef_read(cpriv,
+						cpriv->fifos.tef.index, 1);
+		if (ret)
+			return ret;
+	}
+
 	/* get the fifo from tef */
 	fifo = (tef->flags & MCP25XXFD_CAN_OBJ_FLAGS_SEQ_MASK) >>
 		MCP25XXFD_CAN_OBJ_FLAGS_SEQ_SHIFT;
@@ -260,6 +301,9 @@ int mcp25xxfd_can_tx_handle_int_tefif_fifo(struct mcp25xxfd_can_priv *cpriv)
 			   fifo, tef->id, tef->flags, tef->ts);
 	spin_unlock_irqrestore(&cpriv->fifos.tx_queue->lock, flags);

+	/* update stats */
+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_reads);
+
 	/* now we can schedule the fifo for echo submission */
 	mcp25xxfd_can_queue_frame(cpriv, fifo, tef->ts, false);

@@ -296,10 +340,12 @@ mcp25xxfd_can_tx_handle_int_tefif_conservative(struct mcp25xxfd_can_priv *cpriv)
 	/* read the tef in an inefficient loop */
 	while (tefsta & MCP25XXFD_CAN_TEFSTA_TEFNEIF) {
 		/* read one tef */
-		ret = mcp25xxfd_can_tx_handle_int_tefif_fifo(cpriv);
+		ret = mcp25xxfd_can_tx_handle_int_tefif_fifo(cpriv, true);
 		if (ret)
 			return ret;

+		MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_conservative_reads);
+
 		/* read the TEF status */
 		ret = mcp25xxfd_cmd_read_mask(cpriv->priv->spi,
 					      MCP25XXFD_CAN_TEFSTA, &tefsta,
@@ -315,13 +361,34 @@ static int
 mcp25xxfd_can_tx_handle_int_tefif_optimized(struct mcp25xxfd_can_priv *cpriv,
 					    u32 finished)
 {
-	int i, fifo, ret;
+	int i, fifo, count, ret;
+
+	/* count the number of fifos that have terminated */
+	for (i = 0, fifo = cpriv->fifos.tx.start, count = 0;
+	     i < cpriv->fifos.tx.count; i++, fifo++)
+		if (finished & BIT(fifo))
+			count++;
+
+	/* read them in one go if possible
+	 * we also assume that we have count(TEF) >= count(TX-FIFOS)
+	 * this may require 2 reads when we wrap arround
+	 * (that is unless count(TEF) == count(TX-FIFOS))
+	 */
+	ret = mcp25xxfd_can_tx_tef_read(cpriv, cpriv->fifos.tef.index, count);
+	if (ret)
+		return ret;
+
+	/* update stats */
+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_optimized_reads);
+	i = min_t(int, MCP25XXFD_CAN_TEF_READ_BINS - 1, count - 1);
+	MCP25XXFD_DEBUGFS_STATS_INCR(cpriv, tef_optimized_read_sizes[i]);

 	/* now iterate those */
 	for (i = 0, fifo = cpriv->fifos.tx.start; i < cpriv->fifos.tx.count;
 	     i++, fifo++) {
 		if (finished & BIT(fifo)) {
-			ret = mcp25xxfd_can_tx_handle_int_tefif_fifo(cpriv);
+			ret = mcp25xxfd_can_tx_handle_int_tefif_fifo(cpriv,
+								     false);
 			if (ret)
 				return ret;
 		}
--
2.11.0




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux