diff options
author | Martin Sperl <kernel@martin.sperl.org> | 2019-02-10 16:35:33 +0000 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2020-02-09 22:38:56 +0100 |
commit | 05bb6fe873e1d595780cf40e2e202f75fa770b23 (patch) | |
tree | 4c92a79a7b61ca4d62b36057b700f2367e7224cf | |
parent | b6cf9198f56f954c8cfee18918fb66df0a751307 (diff) |
can: mcp25xxfd: add prediction of CanFD frames sizes based on history
Allow prediction of can frame sizes based on the last 32 Can Frames
received.
Naive histogram approach hast been taken for now.
Some simple stats based on 1000 frames received with DLC=6:
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/rx_reads_prefetched_too_few
16
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/rx_reads_prefetched_too_few_bytes
96
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/rx_reads_prefetched_too_many
0
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/rx_reads_prefetched_too_many_bytes
0
==> /sys/kernel/debug/mcp25xxfd-spi0.0/can/stats/rx_reads_prefetch_predicted
6
The first 16 frames are predicted as 0, but after that the prediction is 6.
It should be possible to take this prediction to use bulk reads for CanFD
as well when we have a prediction of length of 48 or 64.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
(cherry picked from commit f355fdaa97c026ad70882a0cb11943cccefad81b)
-rw-r--r-- | drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c | 4 | ||||
-rw-r--r-- | drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h | 8 | ||||
-rw-r--r-- | drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c | 45 |
3 files changed, 53 insertions, 4 deletions
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c index 3a38570a83f5..013a1a30963a 100644 --- a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c +++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_debugfs.c @@ -104,6 +104,10 @@ static void mcp25xxfd_can_debugfs_stats(struct mcp25xxfd_can_priv *cpriv, snprintf(name, sizeof(name), "rx_bulk_reads_%i+", i + 1); debugfs_create_u64(name, 0444, dir, &cpriv->stats.rx_bulk_read_sizes[i]); + + if (cpriv->can.dev->mtu == CANFD_MTU) + debugfs_create_u32("rx_reads_prefetch_predicted_len", 0444, + dir, &cpriv->rx_history.predicted_len); #undef DEBUGFS_CREATE } diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h index cae22cc02795..1a48e801065d 100644 --- a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h +++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_priv.h @@ -174,6 +174,14 @@ struct mcp25xxfd_can_priv { } stats; #endif /* CONFIG_DEBUG_FS */ + /* history of rx-dlc */ + struct { +#define MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE 32 + u8 dlc[MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE]; + u8 index; + u32 predicted_len; + } rx_history; + /* bus state */ struct { u32 state; diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c index 5134a707b8df..39b59beb5234 100644 --- a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c +++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can_rx.c @@ -102,6 +102,12 @@ int mcp25xxfd_can_rx_submit_frame(struct mcp25xxfd_can_priv *cpriv, int fifo) if (rx->flags & MCP25XXFD_CAN_OBJ_FLAGS_FDF) MCP25XXFD_DEBUGFS_INCR(cpriv->fifos.rx.fd_count); + /* add to rx_history */ + cpriv->rx_history.dlc[cpriv->rx_history.index] = dlc; + cpriv->rx_history.index++; + if (cpriv->rx_history.index >= MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE) + cpriv->rx_history.index = 0; + /* allocate the skb buffer */ if (rx->flags & MCP25XXFD_CAN_OBJ_FLAGS_FDF) { flags = 0; @@ -237,6 +243,40 @@ static int mcp25xxfd_can_read_rx_frame_bulk(struct mcp25xxfd_can_priv *cpriv, return 0; } +/* predict dlc size based on historic behaviour */ +static int mcp25xxfd_can_rx_predict_prefetch(struct mcp25xxfd_can_priv *cpriv) +{ + int dlc, i, top; + u8 histo[16]; + + /* if we have a prfecth set then use that one */ + if (rx_prefetch_bytes != -1) + return min_t(int, rx_prefetch_bytes, + (cpriv->can.dev->mtu == CANFD_MTU) ? 64 : 8); + + /* memset */ + memset(histo, 0, sizeof(histo)); + + /* for all others compute the histogram */ + for (i = 0; i < MCP25XXFD_CAN_RX_DLC_HISTORY_SIZE; i++) + histo[cpriv->rx_history.dlc[i]]++; + + /* and now find the highest fit */ + for (i = (cpriv->can.dev->mtu == CANFD_MTU) ? 15 : 8, dlc = 8, top = 0; + i >= 0; i--) { + if (top < histo[i]) { + top = histo[i]; + dlc = i; + } + } + + /* compute length from dlc */ + cpriv->rx_history.predicted_len = can_dlc2len(dlc); + + /* return the predicted length */ + return cpriv->rx_history.predicted_len; +} + /* at least in can2.0 mode we can read multiple RX-fifos in one go * in case they are ajactent to each other and thus we can reduce * the number of spi messages produced and this improves spi-bus @@ -367,10 +407,7 @@ static int mcp25xxfd_can_rx_read_fd_frames(struct mcp25xxfd_can_priv *cpriv) int ret; /* calculate optimal prefetch to use */ - if (rx_prefetch_bytes != -1) - prefetch = min_t(int, rx_prefetch_bytes, 64); - else - prefetch = 8; + prefetch = mcp25xxfd_can_rx_predict_prefetch(cpriv); /* loop all frames */ for (i = 0, f = cpriv->fifos.rx.start; i < cpriv->fifos.rx.count; |