]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
can: c_can: don't cache TX messages for C_CAN cores
authorMarc Kleine-Budde <mkl@pengutronix.de>
Fri, 23 Sep 2022 11:42:23 +0000 (13:42 +0200)
committerStefan Bader <stefan.bader@canonical.com>
Mon, 14 Nov 2022 10:25:23 +0000 (11:25 +0100)
BugLink: https://bugs.launchpad.net/bugs/1995517
commit 81d192c2ce74157e717e1fc4b68791f82f7499d4 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
drivers/net/can/c_can/c_can.h
drivers/net/can/c_can/c_can_main.c

index 08b6efa7a1a77fe47b33d1a41d276c1a8f2e2b38..ae55eaca7b5e1f4c9ef0f95c21d6a8293aaefc7f 100644 (file)
@@ -236,9 +236,22 @@ static inline u8 c_can_get_tx_tail(const struct c_can_tx_ring *ring)
        return ring->tail & (ring->obj_num - 1);
 }
 
-static inline u8 c_can_get_tx_free(const struct c_can_tx_ring *ring)
+static inline u8 c_can_get_tx_free(const struct c_can_priv *priv,
+                                  const struct c_can_tx_ring *ring)
 {
-       return ring->obj_num - (ring->head - ring->tail);
+       u8 head = c_can_get_tx_head(ring);
+       u8 tail = c_can_get_tx_tail(ring);
+
+       if (priv->type == BOSCH_D_CAN)
+               return ring->obj_num - (ring->head - ring->tail);
+
+       /* This is not a FIFO. C/D_CAN sends out the buffers
+        * prioritized. The lowest buffer number wins.
+        */
+       if (head < tail)
+               return 0;
+
+       return ring->obj_num - head;
 }
 
 #endif /* C_CAN_H */
index 52671d1ea17d57f5ccdfcbab1054c2ce03739eb0..e04d4e7cc8683217d87950821afda49ea4c253c1 100644 (file)
@@ -430,7 +430,7 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface,
 static bool c_can_tx_busy(const struct c_can_priv *priv,
                          const struct c_can_tx_ring *tx_ring)
 {
-       if (c_can_get_tx_free(tx_ring) > 0)
+       if (c_can_get_tx_free(priv, tx_ring) > 0)
                return false;
 
        netif_stop_queue(priv->dev);
@@ -438,7 +438,7 @@ static bool c_can_tx_busy(const struct c_can_priv *priv,
        /* Memory barrier before checking tx_free (head and tail) */
        smp_mb();
 
-       if (c_can_get_tx_free(tx_ring) == 0) {
+       if (c_can_get_tx_free(priv, tx_ring) == 0) {
                netdev_dbg(priv->dev,
                           "Stopping tx-queue (tx_head=0x%08x, tx_tail=0x%08x, len=%d).\n",
                           tx_ring->head, tx_ring->tail,
@@ -466,7 +466,7 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
 
        idx = c_can_get_tx_head(tx_ring);
        tx_ring->head++;
-       if (c_can_get_tx_free(tx_ring) == 0)
+       if (c_can_get_tx_free(priv, tx_ring) == 0)
                netif_stop_queue(dev);
 
        if (idx < c_can_get_tx_tail(tx_ring))
@@ -751,7 +751,7 @@ static void c_can_do_tx(struct net_device *dev)
                return;
 
        tx_ring->tail += pkts;
-       if (c_can_get_tx_free(tx_ring)) {
+       if (c_can_get_tx_free(priv, tx_ring)) {
                /* Make sure that anybody stopping the queue after
                 * this sees the new tx_ring->tail.
                 */
@@ -764,8 +764,7 @@ static void c_can_do_tx(struct net_device *dev)
        can_led_event(dev, CAN_LED_EVENT_TX);
 
        tail = c_can_get_tx_tail(tx_ring);
-
-       if (tail == 0) {
+       if (priv->type == BOSCH_D_CAN && tail == 0) {
                u8 head = c_can_get_tx_head(tx_ring);
 
                /* Start transmission for all cached messages */