can: mcp251xfd: move RX 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 RX 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-9-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-rx.c [new file with mode: 0644]
drivers/net/can/spi/mcp251xfd/mcp251xfd.h

index 3cba3b9447ea24ec43085b0d6e834ff2eb3caff5..8e1146015eeb5fa2b667f6b98c6e9fdd8cbe3bb6 100644 (file)
@@ -6,6 +6,7 @@ mcp251xfd-objs :=
 mcp251xfd-objs += mcp251xfd-core.o
 mcp251xfd-objs += mcp251xfd-crc16.o
 mcp251xfd-objs += mcp251xfd-regmap.o
+mcp251xfd-objs += mcp251xfd-rx.o
 mcp251xfd-objs += mcp251xfd-timestamp.o
 
 mcp251xfd-$(CONFIG_DEV_COREDUMP) += mcp251xfd-dump.o
index 105426dcf06507d0abb10336fd229fba951716aa..d6d0d0f3489384a1ce7b06e0d2262f6eb02cacb8 100644 (file)
@@ -250,43 +250,6 @@ mcp251xfd_tx_tail_get_from_chip(const struct mcp251xfd_priv *priv,
        return 0;
 }
 
-static inline int
-mcp251xfd_rx_head_get_from_chip(const struct mcp251xfd_priv *priv,
-                               const struct mcp251xfd_rx_ring *ring,
-                               u8 *rx_head)
-{
-       u32 fifo_sta;
-       int err;
-
-       err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
-                         &fifo_sta);
-       if (err)
-               return err;
-
-       *rx_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
-
-       return 0;
-}
-
-static inline int
-mcp251xfd_rx_tail_get_from_chip(const struct mcp251xfd_priv *priv,
-                               const struct mcp251xfd_rx_ring *ring,
-                               u8 *rx_tail)
-{
-       u32 fifo_ua;
-       int err;
-
-       err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOUA(ring->fifo_nr),
-                         &fifo_ua);
-       if (err)
-               return err;
-
-       fifo_ua -= ring->base - MCP251XFD_RAM_START;
-       *rx_tail = fifo_ua / ring->obj_size;
-
-       return 0;
-}
-
 static void
 mcp251xfd_tx_ring_init_tx_obj(const struct mcp251xfd_priv *priv,
                              const struct mcp251xfd_tx_ring *ring,
@@ -1208,31 +1171,6 @@ static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv)
        return 0;
 }
 
-static int
-mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv,
-                       const struct mcp251xfd_rx_ring *ring)
-{
-       u8 rx_tail_chip, rx_tail;
-       int err;
-
-       if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))
-               return 0;
-
-       err = mcp251xfd_rx_tail_get_from_chip(priv, ring, &rx_tail_chip);
-       if (err)
-               return err;
-
-       rx_tail = mcp251xfd_get_rx_tail(ring);
-       if (rx_tail_chip != rx_tail) {
-               netdev_err(priv->ndev,
-                          "RX tail of chip (%d) and ours (%d) inconsistent.\n",
-                          rx_tail_chip, rx_tail);
-               return -EILSEQ;
-       }
-
-       return 0;
-}
-
 static int
 mcp251xfd_handle_tefif_recover(const struct mcp251xfd_priv *priv, const u32 seq)
 {
@@ -1430,188 +1368,6 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
        return 0;
 }
 
-static int
-mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
-                        struct mcp251xfd_rx_ring *ring)
-{
-       u32 new_head;
-       u8 chip_rx_head;
-       int err;
-
-       err = mcp251xfd_rx_head_get_from_chip(priv, ring, &chip_rx_head);
-       if (err)
-               return err;
-
-       /* chip_rx_head, is the next RX-Object filled by the HW.
-        * The new RX head must be >= the old head.
-        */
-       new_head = round_down(ring->head, ring->obj_num) + chip_rx_head;
-       if (new_head <= ring->head)
-               new_head += ring->obj_num;
-
-       ring->head = new_head;
-
-       return mcp251xfd_check_rx_tail(priv, ring);
-}
-
-static void
-mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
-                          const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
-                          struct sk_buff *skb)
-{
-       struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
-       u8 dlc;
-
-       if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_IDE) {
-               u32 sid, eid;
-
-               eid = FIELD_GET(MCP251XFD_OBJ_ID_EID_MASK, hw_rx_obj->id);
-               sid = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK, hw_rx_obj->id);
-
-               cfd->can_id = CAN_EFF_FLAG |
-                       FIELD_PREP(MCP251XFD_REG_FRAME_EFF_EID_MASK, eid) |
-                       FIELD_PREP(MCP251XFD_REG_FRAME_EFF_SID_MASK, sid);
-       } else {
-               cfd->can_id = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK,
-                                       hw_rx_obj->id);
-       }
-
-       dlc = FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC_MASK, hw_rx_obj->flags);
-
-       /* CANFD */
-       if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF) {
-
-               if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_ESI)
-                       cfd->flags |= CANFD_ESI;
-
-               if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_BRS)
-                       cfd->flags |= CANFD_BRS;
-
-               cfd->len = can_fd_dlc2len(dlc);
-       } else {
-               if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR)
-                       cfd->can_id |= CAN_RTR_FLAG;
-
-               can_frame_set_cc_len((struct can_frame *)cfd, dlc,
-                                    priv->can.ctrlmode);
-       }
-
-       if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
-               memcpy(cfd->data, hw_rx_obj->data, cfd->len);
-
-       mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
-}
-
-static int
-mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
-                         struct mcp251xfd_rx_ring *ring,
-                         const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj)
-{
-       struct net_device_stats *stats = &priv->ndev->stats;
-       struct sk_buff *skb;
-       struct canfd_frame *cfd;
-       int err;
-
-       if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF)
-               skb = alloc_canfd_skb(priv->ndev, &cfd);
-       else
-               skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cfd);
-
-       if (!skb) {
-               stats->rx_dropped++;
-               return 0;
-       }
-
-       mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
-       err = can_rx_offload_queue_sorted(&priv->offload, skb, hw_rx_obj->ts);
-       if (err)
-               stats->rx_fifo_errors++;
-
-       return 0;
-}
-
-static inline int
-mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv,
-                     const struct mcp251xfd_rx_ring *ring,
-                     struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
-                     const u8 offset, const u8 len)
-{
-       const int val_bytes = regmap_get_val_bytes(priv->map_rx);
-       int err;
-
-       err = regmap_bulk_read(priv->map_rx,
-                              mcp251xfd_get_rx_obj_addr(ring, offset),
-                              hw_rx_obj,
-                              len * ring->obj_size / val_bytes);
-
-       return err;
-}
-
-static int
-mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
-                          struct mcp251xfd_rx_ring *ring)
-{
-       struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj;
-       u8 rx_tail, len;
-       int err, i;
-
-       err = mcp251xfd_rx_ring_update(priv, ring);
-       if (err)
-               return err;
-
-       while ((len = mcp251xfd_get_rx_linear_len(ring))) {
-               int offset;
-
-               rx_tail = mcp251xfd_get_rx_tail(ring);
-
-               err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj,
-                                           rx_tail, len);
-               if (err)
-                       return err;
-
-               for (i = 0; i < len; i++) {
-                       err = mcp251xfd_handle_rxif_one(priv, ring,
-                                                       (void *)hw_rx_obj +
-                                                       i * ring->obj_size);
-                       if (err)
-                               return err;
-               }
-
-               /* Increment the RX 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;
-
-               ring->tail += len;
-       }
-
-       return 0;
-}
-
-static int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
-{
-       struct mcp251xfd_rx_ring *ring;
-       int err, n;
-
-       mcp251xfd_for_each_rx_ring(priv, ring, n) {
-               err = mcp251xfd_handle_rxif_ring(priv, ring);
-               if (err)
-                       return err;
-       }
-
-       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-rx.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c
new file mode 100644 (file)
index 0000000..63f2526
--- /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_rx_head_get_from_chip(const struct mcp251xfd_priv *priv,
+                               const struct mcp251xfd_rx_ring *ring,
+                               u8 *rx_head)
+{
+       u32 fifo_sta;
+       int err;
+
+       err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
+                         &fifo_sta);
+       if (err)
+               return err;
+
+       *rx_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
+
+       return 0;
+}
+
+static inline int
+mcp251xfd_rx_tail_get_from_chip(const struct mcp251xfd_priv *priv,
+                               const struct mcp251xfd_rx_ring *ring,
+                               u8 *rx_tail)
+{
+       u32 fifo_ua;
+       int err;
+
+       err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOUA(ring->fifo_nr),
+                         &fifo_ua);
+       if (err)
+               return err;
+
+       fifo_ua -= ring->base - MCP251XFD_RAM_START;
+       *rx_tail = fifo_ua / ring->obj_size;
+
+       return 0;
+}
+
+static int
+mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv,
+                       const struct mcp251xfd_rx_ring *ring)
+{
+       u8 rx_tail_chip, rx_tail;
+       int err;
+
+       if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))
+               return 0;
+
+       err = mcp251xfd_rx_tail_get_from_chip(priv, ring, &rx_tail_chip);
+       if (err)
+               return err;
+
+       rx_tail = mcp251xfd_get_rx_tail(ring);
+       if (rx_tail_chip != rx_tail) {
+               netdev_err(priv->ndev,
+                          "RX tail of chip (%d) and ours (%d) inconsistent.\n",
+                          rx_tail_chip, rx_tail);
+               return -EILSEQ;
+       }
+
+       return 0;
+}
+
+static int
+mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
+                        struct mcp251xfd_rx_ring *ring)
+{
+       u32 new_head;
+       u8 chip_rx_head;
+       int err;
+
+       err = mcp251xfd_rx_head_get_from_chip(priv, ring, &chip_rx_head);
+       if (err)
+               return err;
+
+       /* chip_rx_head, is the next RX-Object filled by the HW.
+        * The new RX head must be >= the old head.
+        */
+       new_head = round_down(ring->head, ring->obj_num) + chip_rx_head;
+       if (new_head <= ring->head)
+               new_head += ring->obj_num;
+
+       ring->head = new_head;
+
+       return mcp251xfd_check_rx_tail(priv, ring);
+}
+
+static void
+mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
+                          const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
+                          struct sk_buff *skb)
+{
+       struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+       u8 dlc;
+
+       if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_IDE) {
+               u32 sid, eid;
+
+               eid = FIELD_GET(MCP251XFD_OBJ_ID_EID_MASK, hw_rx_obj->id);
+               sid = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK, hw_rx_obj->id);
+
+               cfd->can_id = CAN_EFF_FLAG |
+                       FIELD_PREP(MCP251XFD_REG_FRAME_EFF_EID_MASK, eid) |
+                       FIELD_PREP(MCP251XFD_REG_FRAME_EFF_SID_MASK, sid);
+       } else {
+               cfd->can_id = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK,
+                                       hw_rx_obj->id);
+       }
+
+       dlc = FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC_MASK, hw_rx_obj->flags);
+
+       /* CANFD */
+       if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF) {
+               if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_ESI)
+                       cfd->flags |= CANFD_ESI;
+
+               if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_BRS)
+                       cfd->flags |= CANFD_BRS;
+
+               cfd->len = can_fd_dlc2len(dlc);
+       } else {
+               if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR)
+                       cfd->can_id |= CAN_RTR_FLAG;
+
+               can_frame_set_cc_len((struct can_frame *)cfd, dlc,
+                                    priv->can.ctrlmode);
+       }
+
+       if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
+               memcpy(cfd->data, hw_rx_obj->data, cfd->len);
+
+       mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
+}
+
+static int
+mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
+                         struct mcp251xfd_rx_ring *ring,
+                         const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj)
+{
+       struct net_device_stats *stats = &priv->ndev->stats;
+       struct sk_buff *skb;
+       struct canfd_frame *cfd;
+       int err;
+
+       if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF)
+               skb = alloc_canfd_skb(priv->ndev, &cfd);
+       else
+               skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cfd);
+
+       if (!skb) {
+               stats->rx_dropped++;
+               return 0;
+       }
+
+       mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
+       err = can_rx_offload_queue_sorted(&priv->offload, skb, hw_rx_obj->ts);
+       if (err)
+               stats->rx_fifo_errors++;
+
+       return 0;
+}
+
+static inline int
+mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv,
+                     const struct mcp251xfd_rx_ring *ring,
+                     struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
+                     const u8 offset, const u8 len)
+{
+       const int val_bytes = regmap_get_val_bytes(priv->map_rx);
+       int err;
+
+       err = regmap_bulk_read(priv->map_rx,
+                              mcp251xfd_get_rx_obj_addr(ring, offset),
+                              hw_rx_obj,
+                              len * ring->obj_size / val_bytes);
+
+       return err;
+}
+
+static int
+mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
+                          struct mcp251xfd_rx_ring *ring)
+{
+       struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj;
+       u8 rx_tail, len;
+       int err, i;
+
+       err = mcp251xfd_rx_ring_update(priv, ring);
+       if (err)
+               return err;
+
+       while ((len = mcp251xfd_get_rx_linear_len(ring))) {
+               int offset;
+
+               rx_tail = mcp251xfd_get_rx_tail(ring);
+
+               err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj,
+                                           rx_tail, len);
+               if (err)
+                       return err;
+
+               for (i = 0; i < len; i++) {
+                       err = mcp251xfd_handle_rxif_one(priv, ring,
+                                                       (void *)hw_rx_obj +
+                                                       i * ring->obj_size);
+                       if (err)
+                               return err;
+               }
+
+               /* Increment the RX 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;
+
+               ring->tail += len;
+       }
+
+       return 0;
+}
+
+int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
+{
+       struct mcp251xfd_rx_ring *ring;
+       int err, n;
+
+       mcp251xfd_for_each_rx_ring(priv, ring, n) {
+               err = mcp251xfd_handle_rxif_ring(priv, ring);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
index 8a6e07ba66d5b07bd7296d291ce73756af5408cb..8b35417316a0cf8ef2d2ecce57e034f31a54a619 100644 (file)
@@ -853,6 +853,7 @@ u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size,
                             const void *data, size_t data_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);
 void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
                                 struct sk_buff *skb, u32 timestamp);
 void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv);