[PATCH 03/15] can: m_can: Cache tx putidx and transmits in flight
From: Markus Schneider-Pargmann
Date: Wed Nov 16 2022 - 15:54:28 EST
On peripheral chips every read/write can be costly. Avoid reading easily
trackable information and cache them internally. This saves multiple
reads.
Transmit FIFO put index is cached, this is increased for every time we
enqueue a transmit request.
The transmits in flight is cached as well. With each transmit request it
is increased when reading the finished transmit event it is decreased.
A submit limit is cached to avoid submitting too many transmits at once,
either because the TX FIFO or the TXE FIFO is limited. This is currently
done very conservatively as the minimum of the fifo sizes. This means we
can reach FIFO full events but won't drop anything.
Signed-off-by: Markus Schneider-Pargmann <msp@xxxxxxxxxxxx>
---
drivers/net/can/m_can/m_can.c | 21 +++++++++++++++------
drivers/net/can/m_can/m_can.h | 5 +++++
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 4adf03111782..f5bba848bd56 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -1041,6 +1041,7 @@ static int m_can_echo_tx_event(struct net_device *dev)
/* ack txe element */
m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK,
fgi));
+ --cdev->tx_fifo_in_flight;
/* update stats */
m_can_tx_update_stats(cdev, msg_mark, timestamp);
@@ -1376,6 +1377,14 @@ static void m_can_start(struct net_device *dev)
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
m_can_enable_all_interrupts(cdev);
+
+ if (cdev->version > 30) {
+ cdev->tx_fifo_putidx = FIELD_GET(TXFQS_TFQPI_MASK,
+ m_can_read(cdev, M_CAN_TXFQS));
+ cdev->tx_fifo_in_flight = 0;
+ cdev->tx_fifo_submit_limit = min(cdev->mcfg[MRAM_TXE].num,
+ cdev->mcfg[MRAM_TXB].num);
+ }
}
static int m_can_set_mode(struct net_device *dev, enum can_mode mode)
@@ -1589,7 +1598,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
struct sk_buff *skb = cdev->tx_skb;
struct id_and_dlc fifo_header;
u32 cccr, fdflags;
- u32 txfqs;
int err;
int putidx;
@@ -1646,10 +1654,8 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
} else {
/* Transmit routine for version >= v3.1.x */
- txfqs = m_can_read(cdev, M_CAN_TXFQS);
-
/* Check if FIFO full */
- if (_m_can_tx_fifo_full(txfqs)) {
+ if (cdev->tx_fifo_in_flight >= cdev->tx_fifo_submit_limit) {
/* This shouldn't happen */
netif_stop_queue(dev);
netdev_warn(dev,
@@ -1665,7 +1671,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
}
/* get put index for frame */
- putidx = FIELD_GET(TXFQS_TFQPI_MASK, txfqs);
+ putidx = cdev->tx_fifo_putidx;
/* Construct DLC Field, with CAN-FD configuration.
* Use the put index of the fifo as the message marker,
@@ -1699,9 +1705,12 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
/* Enable TX FIFO element to start transfer */
m_can_write(cdev, M_CAN_TXBAR, (1 << putidx));
+ ++cdev->tx_fifo_in_flight;
+ cdev->tx_fifo_putidx = (++cdev->tx_fifo_putidx >= cdev->can.echo_skb_max ?
+ 0 : cdev->tx_fifo_putidx);
/* stop network queue if fifo full */
- if (m_can_tx_fifo_full(cdev) ||
+ if (cdev->tx_fifo_in_flight >= cdev->tx_fifo_submit_limit ||
m_can_next_echo_skb_occupied(dev, putidx))
netif_stop_queue(dev);
else if (cdev->is_peripheral && !cdev->tx_skb && netif_queue_stopped(dev))
diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h
index 4c0267f9f297..7464ce56753a 100644
--- a/drivers/net/can/m_can/m_can.h
+++ b/drivers/net/can/m_can/m_can.h
@@ -92,6 +92,11 @@ struct m_can_classdev {
int pm_clock_support;
int is_peripheral;
+ // Store this internally to avoid fetch delays on peripheral chips
+ int tx_fifo_putidx;
+ int tx_fifo_in_flight;
+ int tx_fifo_submit_limit;
+
struct mram_cfg mcfg[MRAM_CFG_NUM];
};
--
2.38.1