In case can frames are sent with local loop-back disabled, for instance doing a "cangen -x", tx_bytes stats are not updated properly in m_can_echo_tx_event(). More in details, if local loop-back is off, then echo skb is not set by can_put_echo_skb() at the time m_can_start_xmit() calls it. So later when tx event interrupt is raised and m_can_echo_tx_event() is called, can_get_echo_skb() returns 0 and stats->tx_bytes is not incremented. In m_can_echo_tx_event(), this patch checks whether message marker matches a valid skb and if not, data len is retrieved reading tx event fifo instead of relying on can_get_echo_skb(). This patch has been tested with the ST Accordo5 machine, not yet supported upstream but which relies on the m_can driver. Signed-off-by: Jean-Nicolas Graux <jean-nicolas.graux@xxxxxx> --- drivers/net/can/m_can/m_can.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 9b44940..791a5c6 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -346,6 +346,8 @@ enum m_can_mram_cfg { /* E1 */ #define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT #define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT) +#define TX_EVENT_DLC_SHIFT 16 +#define TX_EVENT_DLC_MASK (0xF << TX_EVENT_DLC_SHIFT) /* address offset and element number for each FIFO/Buffer in the Message RAM */ struct mram_cfg { @@ -847,7 +849,7 @@ static void m_can_echo_tx_event(struct net_device *dev) u32 m_can_txefs; u32 fgi = 0; int i = 0; - unsigned int msg_mark; + unsigned int msg_mark, txe; struct m_can_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; @@ -866,15 +868,21 @@ static void m_can_echo_tx_event(struct net_device *dev) >> TXEFS_EFGI_SHIFT; /* get message marker */ - msg_mark = (m_can_txe_fifo_read(priv, fgi, 4) & - TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT; + txe = m_can_txe_fifo_read(priv, fgi, 4); + msg_mark = (txe & TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT; /* ack txe element */ m_can_write(priv, M_CAN_TXEFA, (TXEFA_EFAI_MASK & (fgi << TXEFA_EFAI_SHIFT))); /* update stats */ - stats->tx_bytes += can_get_echo_skb(dev, msg_mark); + if (priv->can.echo_skb[msg_mark]) { + stats->tx_bytes += can_get_echo_skb(dev, msg_mark); + } else { + u32 dlc = (txe & TX_EVENT_DLC_MASK) >> + TX_EVENT_DLC_SHIFT; + stats->tx_bytes += can_dlc2len(dlc); + } stats->tx_packets++; } } -- 2.7.4