summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Sperl <kernel@martin.sperl.org>2019-01-06 10:37:14 +0000
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2020-02-09 22:38:56 +0100
commit8d5988f9144260f900ff9f8320decb5dc82eddc2 (patch)
tree9ac41e06a16bb4d9a778521973b49e7ca2ee9f5b
parent04baad38c49aa256ebfd820b75cea8c2091d4537 (diff)
can: mcp25xxfd: optimize TEF reads reading multiple TEFs in one go
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@martin.sperl.org> (cherry picked from commit 345593580ee21f51fee1eb410905641379dcb329)
-rw-r--r--drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c18
-rw-r--r--drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h7
-rw-r--r--drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_tx.c85
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 714069385f8a..3be9ba17bae2 100644
--- a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c
@@ -44,6 +44,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)
@@ -63,6 +66,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 ca0dce6a43a7..50252d530725 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 @@ out:
}
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;
}