diff options
author | Martin Sperl <kernel@martin.sperl.org> | 2019-01-06 10:37:14 +0000 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2020-02-09 22:38:56 +0100 |
commit | 8d5988f9144260f900ff9f8320decb5dc82eddc2 (patch) | |
tree | 9ac41e06a16bb4d9a778521973b49e7ca2ee9f5b | |
parent | 04baad38c49aa256ebfd820b75cea8c2091d4537 (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.c | 18 | ||||
-rw-r--r-- | drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h | 7 | ||||
-rw-r--r-- | 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 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; } |