]> git.baikalelectronics.ru Git - kernel.git/commitdiff
can: mcp251xfd: move TEF handling into separate file
authorMarc Kleine-Budde <mkl@pengutronix.de>
Fri, 21 May 2021 17:51:32 +0000 (19:51 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Sat, 8 Jan 2022 19:17:42 +0000 (20:17 +0100)
This patch moves the TEF handling from the mcp251xfd core file into a
separate one to make the driver a bit more orderly.

Link: https://lore.kernel.org/all/20220105154300.1258636-11-mkl@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/spi/mcp251xfd/Makefile
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c [new file with mode: 0644]
drivers/net/can/spi/mcp251xfd/mcp251xfd.h

index 397595dd505c5ac37fbeaedc47c8bcc653006834..801367e98c54923f49add0ca14e44651a22758d2 100644 (file)
@@ -7,6 +7,7 @@ mcp251xfd-objs += mcp251xfd-core.o
 mcp251xfd-objs += mcp251xfd-crc16.o
 mcp251xfd-objs += mcp251xfd-regmap.o
 mcp251xfd-objs += mcp251xfd-rx.o
+mcp251xfd-objs += mcp251xfd-tef.o
 mcp251xfd-objs += mcp251xfd-timestamp.o
 mcp251xfd-objs += mcp251xfd-tx.o
 
index 4445653e7743d869aae36853447091a67439e7f4..65803b9fe2a25517e3df05829ac8ed5e7f2fbae2 100644 (file)
@@ -216,40 +216,6 @@ mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv,
        return len;
 }
 
-static inline int
-mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,
-                                u8 *tef_tail)
-{
-       u32 tef_ua;
-       int err;
-
-       err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFUA, &tef_ua);
-       if (err)
-               return err;
-
-       *tef_tail = tef_ua / sizeof(struct mcp251xfd_hw_tef_obj);
-
-       return 0;
-}
-
-static inline int
-mcp251xfd_tx_tail_get_from_chip(const struct mcp251xfd_priv *priv,
-                               u8 *tx_tail)
-{
-       u32 fifo_sta;
-       int err;
-
-       err = regmap_read(priv->map_reg,
-                         MCP251XFD_REG_FIFOSTA(MCP251XFD_TX_FIFO),
-                         &fifo_sta);
-       if (err)
-               return err;
-
-       *tx_tail = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
-
-       return 0;
-}
-
 static void
 mcp251xfd_tx_ring_init_tx_obj(const struct mcp251xfd_priv *priv,
                              const struct mcp251xfd_tx_ring *ring,
@@ -931,13 +897,6 @@ static int mcp251xfd_chip_ecc_init(struct mcp251xfd_priv *priv)
        return err;
 }
 
-static inline void mcp251xfd_ecc_tefif_successful(struct mcp251xfd_priv *priv)
-{
-       struct mcp251xfd_ecc *ecc = &priv->ecc;
-
-       ecc->ecc_stat = 0;
-}
-
 static u8 mcp251xfd_get_normal_mode(const struct mcp251xfd_priv *priv)
 {
        u8 mode;
@@ -1148,226 +1107,6 @@ static int mcp251xfd_get_berr_counter(const struct net_device *ndev,
        return __mcp251xfd_get_berr_counter(ndev, bec);
 }
 
-static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv)
-{
-       u8 tef_tail_chip, tef_tail;
-       int err;
-
-       if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))
-               return 0;
-
-       err = mcp251xfd_tef_tail_get_from_chip(priv, &tef_tail_chip);
-       if (err)
-               return err;
-
-       tef_tail = mcp251xfd_get_tef_tail(priv);
-       if (tef_tail_chip != tef_tail) {
-               netdev_err(priv->ndev,
-                          "TEF tail of chip (0x%02x) and ours (0x%08x) inconsistent.\n",
-                          tef_tail_chip, tef_tail);
-               return -EILSEQ;
-       }
-
-       return 0;
-}
-
-static int
-mcp251xfd_handle_tefif_recover(const struct mcp251xfd_priv *priv, const u32 seq)
-{
-       const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
-       u32 tef_sta;
-       int err;
-
-       err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFSTA, &tef_sta);
-       if (err)
-               return err;
-
-       if (tef_sta & MCP251XFD_REG_TEFSTA_TEFOVIF) {
-               netdev_err(priv->ndev,
-                          "Transmit Event FIFO buffer overflow.\n");
-               return -ENOBUFS;
-       }
-
-       netdev_info(priv->ndev,
-                   "Transmit Event FIFO buffer %s. (seq=0x%08x, tef_tail=0x%08x, tef_head=0x%08x, tx_head=0x%08x).\n",
-                   tef_sta & MCP251XFD_REG_TEFSTA_TEFFIF ?
-                   "full" : tef_sta & MCP251XFD_REG_TEFSTA_TEFNEIF ?
-                   "not empty" : "empty",
-                   seq, priv->tef->tail, priv->tef->head, tx_ring->head);
-
-       /* The Sequence Number in the TEF doesn't match our tef_tail. */
-       return -EAGAIN;
-}
-
-static int
-mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
-                          const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
-                          unsigned int *frame_len_ptr)
-{
-       struct net_device_stats *stats = &priv->ndev->stats;
-       struct sk_buff *skb;
-       u32 seq, seq_masked, tef_tail_masked, tef_tail;
-
-       seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK,
-                       hw_tef_obj->flags);
-
-       /* Use the MCP2517FD mask on the MCP2518FD, too. We only
-        * compare 7 bits, this should be enough to detect
-        * net-yet-completed, i.e. old TEF objects.
-        */
-       seq_masked = seq &
-               field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
-       tef_tail_masked = priv->tef->tail &
-               field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
-       if (seq_masked != tef_tail_masked)
-               return mcp251xfd_handle_tefif_recover(priv, seq);
-
-       tef_tail = mcp251xfd_get_tef_tail(priv);
-       skb = priv->can.echo_skb[tef_tail];
-       if (skb)
-               mcp251xfd_skb_set_timestamp(priv, skb, hw_tef_obj->ts);
-       stats->tx_bytes +=
-               can_rx_offload_get_echo_skb(&priv->offload,
-                                           tef_tail, hw_tef_obj->ts,
-                                           frame_len_ptr);
-       stats->tx_packets++;
-       priv->tef->tail++;
-
-       return 0;
-}
-
-static int mcp251xfd_tef_ring_update(struct mcp251xfd_priv *priv)
-{
-       const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
-       unsigned int new_head;
-       u8 chip_tx_tail;
-       int err;
-
-       err = mcp251xfd_tx_tail_get_from_chip(priv, &chip_tx_tail);
-       if (err)
-               return err;
-
-       /* chip_tx_tail, is the next TX-Object send by the HW.
-        * The new TEF head must be >= the old head, ...
-        */
-       new_head = round_down(priv->tef->head, tx_ring->obj_num) + chip_tx_tail;
-       if (new_head <= priv->tef->head)
-               new_head += tx_ring->obj_num;
-
-       /* ... but it cannot exceed the TX head. */
-       priv->tef->head = min(new_head, tx_ring->head);
-
-       return mcp251xfd_check_tef_tail(priv);
-}
-
-static inline int
-mcp251xfd_tef_obj_read(const struct mcp251xfd_priv *priv,
-                      struct mcp251xfd_hw_tef_obj *hw_tef_obj,
-                      const u8 offset, const u8 len)
-{
-       const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
-       const int val_bytes = regmap_get_val_bytes(priv->map_rx);
-
-       if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
-           (offset > tx_ring->obj_num ||
-            len > tx_ring->obj_num ||
-            offset + len > tx_ring->obj_num)) {
-               netdev_err(priv->ndev,
-                          "Trying to read too many TEF objects (max=%d, offset=%d, len=%d).\n",
-                          tx_ring->obj_num, offset, len);
-               return -ERANGE;
-       }
-
-       return regmap_bulk_read(priv->map_rx,
-                               mcp251xfd_get_tef_obj_addr(offset),
-                               hw_tef_obj,
-                               sizeof(*hw_tef_obj) / val_bytes * len);
-}
-
-static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
-{
-       struct mcp251xfd_hw_tef_obj hw_tef_obj[MCP251XFD_TX_OBJ_NUM_MAX];
-       unsigned int total_frame_len = 0;
-       u8 tef_tail, len, l;
-       int err, i;
-
-       err = mcp251xfd_tef_ring_update(priv);
-       if (err)
-               return err;
-
-       tef_tail = mcp251xfd_get_tef_tail(priv);
-       len = mcp251xfd_get_tef_len(priv);
-       l = mcp251xfd_get_tef_linear_len(priv);
-       err = mcp251xfd_tef_obj_read(priv, hw_tef_obj, tef_tail, l);
-       if (err)
-               return err;
-
-       if (l < len) {
-               err = mcp251xfd_tef_obj_read(priv, &hw_tef_obj[l], 0, len - l);
-               if (err)
-                       return err;
-       }
-
-       for (i = 0; i < len; i++) {
-               unsigned int frame_len = 0;
-
-               err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i], &frame_len);
-               /* -EAGAIN means the Sequence Number in the TEF
-                * doesn't match our tef_tail. This can happen if we
-                * read the TEF objects too early. Leave loop let the
-                * interrupt handler call us again.
-                */
-               if (err == -EAGAIN)
-                       goto out_netif_wake_queue;
-               if (err)
-                       return err;
-
-               total_frame_len += frame_len;
-       }
-
- out_netif_wake_queue:
-       len = i;        /* number of handled goods TEFs */
-       if (len) {
-               struct mcp251xfd_tef_ring *ring = priv->tef;
-               struct mcp251xfd_tx_ring *tx_ring = priv->tx;
-               int offset;
-
-               /* Increment the TEF FIFO tail pointer 'len' times in
-                * a single SPI message.
-                *
-                * Note:
-                * Calculate offset, so that the SPI transfer ends on
-                * the last message of the uinc_xfer array, which has
-                * "cs_change == 0", to properly deactivate the chip
-                * select.
-                */
-               offset = ARRAY_SIZE(ring->uinc_xfer) - len;
-               err = spi_sync_transfer(priv->spi,
-                                       ring->uinc_xfer + offset, len);
-               if (err)
-                       return err;
-
-               tx_ring->tail += len;
-               netdev_completed_queue(priv->ndev, len, total_frame_len);
-
-               err = mcp251xfd_check_tef_tail(priv);
-               if (err)
-                       return err;
-       }
-
-       mcp251xfd_ecc_tefif_successful(priv);
-
-       if (mcp251xfd_get_tx_free(priv->tx)) {
-               /* Make sure that anybody stopping the queue after
-                * this sees the new tx_ring->tail.
-                */
-               smp_mb();
-               netif_wake_queue(priv->ndev);
-       }
-
-       return 0;
-}
-
 static struct sk_buff *
 mcp251xfd_alloc_can_err_skb(struct mcp251xfd_priv *priv,
                            struct can_frame **cf, u32 *timestamp)
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c
new file mode 100644 (file)
index 0000000..4061660
--- /dev/null
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
+//
+// Copyright (c) 2019, 2020, 2021 Pengutronix,
+//               Marc Kleine-Budde <kernel@pengutronix.de>
+//
+// Based on:
+//
+// CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+//
+// Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
+//
+
+#include <linux/bitfield.h>
+
+#include "mcp251xfd.h"
+
+static inline int
+mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,
+                                u8 *tef_tail)
+{
+       u32 tef_ua;
+       int err;
+
+       err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFUA, &tef_ua);
+       if (err)
+               return err;
+
+       *tef_tail = tef_ua / sizeof(struct mcp251xfd_hw_tef_obj);
+
+       return 0;
+}
+
+static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv)
+{
+       u8 tef_tail_chip, tef_tail;
+       int err;
+
+       if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))
+               return 0;
+
+       err = mcp251xfd_tef_tail_get_from_chip(priv, &tef_tail_chip);
+       if (err)
+               return err;
+
+       tef_tail = mcp251xfd_get_tef_tail(priv);
+       if (tef_tail_chip != tef_tail) {
+               netdev_err(priv->ndev,
+                          "TEF tail of chip (0x%02x) and ours (0x%08x) inconsistent.\n",
+                          tef_tail_chip, tef_tail);
+               return -EILSEQ;
+       }
+
+       return 0;
+}
+
+static int
+mcp251xfd_handle_tefif_recover(const struct mcp251xfd_priv *priv, const u32 seq)
+{
+       const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
+       u32 tef_sta;
+       int err;
+
+       err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFSTA, &tef_sta);
+       if (err)
+               return err;
+
+       if (tef_sta & MCP251XFD_REG_TEFSTA_TEFOVIF) {
+               netdev_err(priv->ndev,
+                          "Transmit Event FIFO buffer overflow.\n");
+               return -ENOBUFS;
+       }
+
+       netdev_info(priv->ndev,
+                   "Transmit Event FIFO buffer %s. (seq=0x%08x, tef_tail=0x%08x, tef_head=0x%08x, tx_head=0x%08x).\n",
+                   tef_sta & MCP251XFD_REG_TEFSTA_TEFFIF ?
+                   "full" : tef_sta & MCP251XFD_REG_TEFSTA_TEFNEIF ?
+                   "not empty" : "empty",
+                   seq, priv->tef->tail, priv->tef->head, tx_ring->head);
+
+       /* The Sequence Number in the TEF doesn't match our tef_tail. */
+       return -EAGAIN;
+}
+
+static int
+mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
+                          const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
+                          unsigned int *frame_len_ptr)
+{
+       struct net_device_stats *stats = &priv->ndev->stats;
+       struct sk_buff *skb;
+       u32 seq, seq_masked, tef_tail_masked, tef_tail;
+
+       seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK,
+                       hw_tef_obj->flags);
+
+       /* Use the MCP2517FD mask on the MCP2518FD, too. We only
+        * compare 7 bits, this should be enough to detect
+        * net-yet-completed, i.e. old TEF objects.
+        */
+       seq_masked = seq &
+               field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
+       tef_tail_masked = priv->tef->tail &
+               field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
+       if (seq_masked != tef_tail_masked)
+               return mcp251xfd_handle_tefif_recover(priv, seq);
+
+       tef_tail = mcp251xfd_get_tef_tail(priv);
+       skb = priv->can.echo_skb[tef_tail];
+       if (skb)
+               mcp251xfd_skb_set_timestamp(priv, skb, hw_tef_obj->ts);
+       stats->tx_bytes +=
+               can_rx_offload_get_echo_skb(&priv->offload,
+                                           tef_tail, hw_tef_obj->ts,
+                                           frame_len_ptr);
+       stats->tx_packets++;
+       priv->tef->tail++;
+
+       return 0;
+}
+
+static int mcp251xfd_tef_ring_update(struct mcp251xfd_priv *priv)
+{
+       const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
+       unsigned int new_head;
+       u8 chip_tx_tail;
+       int err;
+
+       err = mcp251xfd_tx_tail_get_from_chip(priv, &chip_tx_tail);
+       if (err)
+               return err;
+
+       /* chip_tx_tail, is the next TX-Object send by the HW.
+        * The new TEF head must be >= the old head, ...
+        */
+       new_head = round_down(priv->tef->head, tx_ring->obj_num) + chip_tx_tail;
+       if (new_head <= priv->tef->head)
+               new_head += tx_ring->obj_num;
+
+       /* ... but it cannot exceed the TX head. */
+       priv->tef->head = min(new_head, tx_ring->head);
+
+       return mcp251xfd_check_tef_tail(priv);
+}
+
+static inline int
+mcp251xfd_tef_obj_read(const struct mcp251xfd_priv *priv,
+                      struct mcp251xfd_hw_tef_obj *hw_tef_obj,
+                      const u8 offset, const u8 len)
+{
+       const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
+       const int val_bytes = regmap_get_val_bytes(priv->map_rx);
+
+       if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
+           (offset > tx_ring->obj_num ||
+            len > tx_ring->obj_num ||
+            offset + len > tx_ring->obj_num)) {
+               netdev_err(priv->ndev,
+                          "Trying to read too many TEF objects (max=%d, offset=%d, len=%d).\n",
+                          tx_ring->obj_num, offset, len);
+               return -ERANGE;
+       }
+
+       return regmap_bulk_read(priv->map_rx,
+                               mcp251xfd_get_tef_obj_addr(offset),
+                               hw_tef_obj,
+                               sizeof(*hw_tef_obj) / val_bytes * len);
+}
+
+static inline void mcp251xfd_ecc_tefif_successful(struct mcp251xfd_priv *priv)
+{
+       struct mcp251xfd_ecc *ecc = &priv->ecc;
+
+       ecc->ecc_stat = 0;
+}
+
+int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
+{
+       struct mcp251xfd_hw_tef_obj hw_tef_obj[MCP251XFD_TX_OBJ_NUM_MAX];
+       unsigned int total_frame_len = 0;
+       u8 tef_tail, len, l;
+       int err, i;
+
+       err = mcp251xfd_tef_ring_update(priv);
+       if (err)
+               return err;
+
+       tef_tail = mcp251xfd_get_tef_tail(priv);
+       len = mcp251xfd_get_tef_len(priv);
+       l = mcp251xfd_get_tef_linear_len(priv);
+       err = mcp251xfd_tef_obj_read(priv, hw_tef_obj, tef_tail, l);
+       if (err)
+               return err;
+
+       if (l < len) {
+               err = mcp251xfd_tef_obj_read(priv, &hw_tef_obj[l], 0, len - l);
+               if (err)
+                       return err;
+       }
+
+       for (i = 0; i < len; i++) {
+               unsigned int frame_len = 0;
+
+               err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i], &frame_len);
+               /* -EAGAIN means the Sequence Number in the TEF
+                * doesn't match our tef_tail. This can happen if we
+                * read the TEF objects too early. Leave loop let the
+                * interrupt handler call us again.
+                */
+               if (err == -EAGAIN)
+                       goto out_netif_wake_queue;
+               if (err)
+                       return err;
+
+               total_frame_len += frame_len;
+       }
+
+ out_netif_wake_queue:
+       len = i;        /* number of handled goods TEFs */
+       if (len) {
+               struct mcp251xfd_tef_ring *ring = priv->tef;
+               struct mcp251xfd_tx_ring *tx_ring = priv->tx;
+               int offset;
+
+               /* Increment the TEF FIFO tail pointer 'len' times in
+                * a single SPI message.
+                *
+                * Note:
+                * Calculate offset, so that the SPI transfer ends on
+                * the last message of the uinc_xfer array, which has
+                * "cs_change == 0", to properly deactivate the chip
+                * select.
+                */
+               offset = ARRAY_SIZE(ring->uinc_xfer) - len;
+               err = spi_sync_transfer(priv->spi,
+                                       ring->uinc_xfer + offset, len);
+               if (err)
+                       return err;
+
+               tx_ring->tail += len;
+               netdev_completed_queue(priv->ndev, len, total_frame_len);
+
+               err = mcp251xfd_check_tef_tail(priv);
+               if (err)
+                       return err;
+       }
+
+       mcp251xfd_ecc_tefif_successful(priv);
+
+       if (mcp251xfd_get_tx_free(priv->tx)) {
+               /* Make sure that anybody stopping the queue after
+                * this sees the new tx_ring->tail.
+                */
+               smp_mb();
+               netif_wake_queue(priv->ndev);
+       }
+
+       return 0;
+}
index bd1c22815f31a9ac2e242d38aade90f725e7e78d..22a18d6fbda4e9d35c6f6316756e490a2ce2a1b4 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef _MCP251XFD_H
 #define _MCP251XFD_H
 
+#include <linux/bitfield.h>
 #include <linux/can/core.h>
 #include <linux/can/dev.h>
 #include <linux/can/rx-offload.h>
@@ -761,6 +762,24 @@ mcp251xfd_get_rx_obj_addr(const struct mcp251xfd_rx_ring *ring, u8 n)
        return ring->base + ring->obj_size * n;
 }
 
+static inline int
+mcp251xfd_tx_tail_get_from_chip(const struct mcp251xfd_priv *priv,
+                               u8 *tx_tail)
+{
+       u32 fifo_sta;
+       int err;
+
+       err = regmap_read(priv->map_reg,
+                         MCP251XFD_REG_FIFOSTA(MCP251XFD_TX_FIFO),
+                         &fifo_sta);
+       if (err)
+               return err;
+
+       *tx_tail = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
+
+       return 0;
+}
+
 static inline u8 mcp251xfd_get_tef_head(const struct mcp251xfd_priv *priv)
 {
        return priv->tef->head & (priv->tx->obj_num - 1);
@@ -854,6 +873,7 @@ u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size,
 u16 mcp251xfd_crc16_compute(const void *data, size_t data_size);
 int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv);
 int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv);
+int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv);
 void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
                                 struct sk_buff *skb, u32 timestamp);
 void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv);