Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: c_can: don't cache TX messages for C_CAN cores

As Jacob noticed, the optimization introduced in 387da6bc7a82 ("can:
c_can: cache frames to operate as a true FIFO") doesn't properly work
on C_CAN, but on D_CAN IP cores. The exact reasons are still unknown.

For now disable caching if CAN frames in the TX path for C_CAN cores.

Fixes: 387da6bc7a82 ("can: c_can: cache frames to operate as a true FIFO")
Link: https://lore.kernel.org/all/20220928083354.1062321-1-mkl@pengutronix.de
Link: https://lore.kernel.org/all/15a8084b-9617-2da1-6704-d7e39d60643b@gmail.com
Reported-by: Jacob Kroon <jacob.kroon@gmail.com>
Tested-by: Jacob Kroon <jacob.kroon@gmail.com>
Cc: stable@vger.kernel.org # v5.15
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

+20 -8
+15 -2
drivers/net/can/c_can/c_can.h
··· 235 235 return ring->tail & (ring->obj_num - 1); 236 236 } 237 237 238 - static inline u8 c_can_get_tx_free(const struct c_can_tx_ring *ring) 238 + static inline u8 c_can_get_tx_free(const struct c_can_priv *priv, 239 + const struct c_can_tx_ring *ring) 239 240 { 240 - return ring->obj_num - (ring->head - ring->tail); 241 + u8 head = c_can_get_tx_head(ring); 242 + u8 tail = c_can_get_tx_tail(ring); 243 + 244 + if (priv->type == BOSCH_D_CAN) 245 + return ring->obj_num - (ring->head - ring->tail); 246 + 247 + /* This is not a FIFO. C/D_CAN sends out the buffers 248 + * prioritized. The lowest buffer number wins. 249 + */ 250 + if (head < tail) 251 + return 0; 252 + 253 + return ring->obj_num - head; 241 254 } 242 255 243 256 #endif /* C_CAN_H */
+5 -6
drivers/net/can/c_can/c_can_main.c
··· 429 429 static bool c_can_tx_busy(const struct c_can_priv *priv, 430 430 const struct c_can_tx_ring *tx_ring) 431 431 { 432 - if (c_can_get_tx_free(tx_ring) > 0) 432 + if (c_can_get_tx_free(priv, tx_ring) > 0) 433 433 return false; 434 434 435 435 netif_stop_queue(priv->dev); ··· 437 437 /* Memory barrier before checking tx_free (head and tail) */ 438 438 smp_mb(); 439 439 440 - if (c_can_get_tx_free(tx_ring) == 0) { 440 + if (c_can_get_tx_free(priv, tx_ring) == 0) { 441 441 netdev_dbg(priv->dev, 442 442 "Stopping tx-queue (tx_head=0x%08x, tx_tail=0x%08x, len=%d).\n", 443 443 tx_ring->head, tx_ring->tail, ··· 465 465 466 466 idx = c_can_get_tx_head(tx_ring); 467 467 tx_ring->head++; 468 - if (c_can_get_tx_free(tx_ring) == 0) 468 + if (c_can_get_tx_free(priv, tx_ring) == 0) 469 469 netif_stop_queue(dev); 470 470 471 471 if (idx < c_can_get_tx_tail(tx_ring)) ··· 748 748 return; 749 749 750 750 tx_ring->tail += pkts; 751 - if (c_can_get_tx_free(tx_ring)) { 751 + if (c_can_get_tx_free(priv, tx_ring)) { 752 752 /* Make sure that anybody stopping the queue after 753 753 * this sees the new tx_ring->tail. 754 754 */ ··· 760 760 stats->tx_packets += pkts; 761 761 762 762 tail = c_can_get_tx_tail(tx_ring); 763 - 764 - if (tail == 0) { 763 + if (priv->type == BOSCH_D_CAN && tail == 0) { 765 764 u8 head = c_can_get_tx_head(tx_ring); 766 765 767 766 /* Start transmission for all cached messages */