net: stmmac: Introduce separate files for FPE implementation
authorFurong Xu <0x1207@gmail.com>
Fri, 1 Nov 2024 13:31:28 +0000 (21:31 +0800)
committerJakub Kicinski <kuba@kernel.org>
Sun, 3 Nov 2024 23:31:23 +0000 (15:31 -0800)
By moving FPE related code info separate files, FPE implementation
becomes a separate module initially.
No functional change intended.

Signed-off-by: Furong Xu <0x1207@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://patch.msgid.link/e9ddf4fbf0fc053ae30592aa6c4363e72a4d8e62.1730449003.git.0x1207@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/stmicro/stmmac/Makefile
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
drivers/net/ethernet/stmicro/stmmac/dwmac5.c
drivers/net/ethernet/stmicro/stmmac/dwmac5.h
drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c [new file with mode: 0644]
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h [new file with mode: 0644]
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

index c2f0e91f6bf83d34abe81be9aa44ec9ad778fc0d..7e46dca906287dbfce096c01c50b7de58feba1c3 100644 (file)
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o  \
              mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o  \
              dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
              stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
-             stmmac_xdp.o stmmac_est.o \
+             stmmac_xdp.o stmmac_est.o stmmac_fpe.o \
              $(stmmac-y)
 
 stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
index e65a65666cc1dee57cfe71eb5f7e17373ddb3e42..4d217926820ab2c3f910dbeaa828f42bfb2cf4e4 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include "stmmac.h"
+#include "stmmac_fpe.h"
 #include "stmmac_pcs.h"
 #include "dwmac4.h"
 #include "dwmac5.h"
index 08add508db844167faa7762eabdbb82db019771d..1c431b918719e2582ce52639985596010206be70 100644 (file)
@@ -572,153 +572,3 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
        writel(val, ioaddr + MAC_PPS_CONTROL);
        return 0;
 }
-
-void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
-                         u32 num_txq, u32 num_rxq,
-                         bool tx_enable, bool pmac_enable)
-{
-       u32 value;
-
-       if (tx_enable) {
-               cfg->fpe_csr = EFPE;
-               value = readl(ioaddr + GMAC_RXQ_CTRL1);
-               value &= ~GMAC_RXQCTRL_FPRQ;
-               value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
-               writel(value, ioaddr + GMAC_RXQ_CTRL1);
-       } else {
-               cfg->fpe_csr = 0;
-       }
-       writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
-
-       value = readl(ioaddr + GMAC_INT_EN);
-
-       if (pmac_enable) {
-               if (!(value & GMAC_INT_FPE_EN)) {
-                       /* Dummy read to clear any pending masked interrupts */
-                       readl(ioaddr + MAC_FPE_CTRL_STS);
-
-                       value |= GMAC_INT_FPE_EN;
-               }
-       } else {
-               value &= ~GMAC_INT_FPE_EN;
-       }
-
-       writel(value, ioaddr + GMAC_INT_EN);
-}
-
-int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
-{
-       u32 value;
-       int status;
-
-       status = FPE_EVENT_UNKNOWN;
-
-       /* Reads from the MAC_FPE_CTRL_STS register should only be performed
-        * here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
-        */
-       value = readl(ioaddr + MAC_FPE_CTRL_STS);
-
-       if (value & TRSP) {
-               status |= FPE_EVENT_TRSP;
-               netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
-       }
-
-       if (value & TVER) {
-               status |= FPE_EVENT_TVER;
-               netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
-       }
-
-       if (value & RRSP) {
-               status |= FPE_EVENT_RRSP;
-               netdev_dbg(dev, "FPE: Respond mPacket is received\n");
-       }
-
-       if (value & RVER) {
-               status |= FPE_EVENT_RVER;
-               netdev_dbg(dev, "FPE: Verify mPacket is received\n");
-       }
-
-       return status;
-}
-
-void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
-                            enum stmmac_mpacket_type type)
-{
-       u32 value = cfg->fpe_csr;
-
-       if (type == MPACKET_VERIFY)
-               value |= SVER;
-       else if (type == MPACKET_RESPONSE)
-               value |= SRSP;
-
-       writel(value, ioaddr + MAC_FPE_CTRL_STS);
-}
-
-int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr)
-{
-       return FIELD_GET(DWMAC5_ADD_FRAG_SZ, readl(ioaddr + MTL_FPE_CTRL_STS));
-}
-
-void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
-{
-       u32 value;
-
-       value = readl(ioaddr + MTL_FPE_CTRL_STS);
-       writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ),
-              ioaddr + MTL_FPE_CTRL_STS);
-}
-
-#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
-#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
-
-int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
-                                   struct netlink_ext_ack *extack, u32 pclass)
-{
-       u32 val, offset, count, queue_weight, preemptible_txqs = 0;
-       struct stmmac_priv *priv = netdev_priv(ndev);
-       u32 num_tc = ndev->num_tc;
-
-       if (!pclass)
-               goto update_mapping;
-
-       /* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
-        *
-        * Synopsys Databook:
-        * "The number of Tx DMA channels is equal to the number of Tx queues,
-        * and is direct one-to-one mapping."
-        */
-       for (u32 tc = 0; tc < num_tc; tc++) {
-               count = ndev->tc_to_txq[tc].count;
-               offset = ndev->tc_to_txq[tc].offset;
-
-               if (pclass & BIT(tc))
-                       preemptible_txqs |= GENMASK(offset + count - 1, offset);
-
-               /* This is 1:1 mapping, go to next TC */
-               if (count == 1)
-                       continue;
-
-               if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
-                       NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
-                       return -EINVAL;
-               }
-
-               queue_weight = priv->plat->tx_queues_cfg[offset].weight;
-
-               for (u32 i = 1; i < count; i++) {
-                       if (priv->plat->tx_queues_cfg[offset + i].weight !=
-                           queue_weight) {
-                               NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
-                                                      queue_weight, tc);
-                               return -EINVAL;
-                       }
-               }
-       }
-
-update_mapping:
-       val = readl(priv->ioaddr + MTL_FPE_CTRL_STS);
-       writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS),
-              priv->ioaddr + MTL_FPE_CTRL_STS);
-
-       return 0;
-}
index 6c6eb6790e836a6cfa7cb638cd7d699f6e58f42c..00b151b3b6887e8928603985ced6d12f98d0cc79 100644 (file)
 #define PRTYEN                         BIT(1)
 #define TMOUTEN                                BIT(0)
 
-#define MAC_FPE_CTRL_STS               0x00000234
-#define TRSP                           BIT(19)
-#define TVER                           BIT(18)
-#define RRSP                           BIT(17)
-#define RVER                           BIT(16)
-#define SRSP                           BIT(2)
-#define SVER                           BIT(1)
-#define EFPE                           BIT(0)
-
 #define MAC_PPS_CONTROL                        0x00000b70
 #define PPS_MAXIDX(x)                  ((((x) + 1) * 8) - 1)
 #define PPS_MINIDX(x)                  ((x) * 8)
 #define MAC_PPSx_INTERVAL(x)           (0x00000b88 + ((x) * 0x10))
 #define MAC_PPSx_WIDTH(x)              (0x00000b8c + ((x) * 0x10))
 
-#define MTL_FPE_CTRL_STS               0x00000c90
-/* Preemption Classification */
-#define DWMAC5_PREEMPTION_CLASS                GENMASK(15, 8)
-/* Additional Fragment Size of preempted frames */
-#define DWMAC5_ADD_FRAG_SZ             GENMASK(1, 0)
-
 #define MTL_RXP_CONTROL_STATUS         0x00000ca0
 #define RXPI                           BIT(31)
 #define NPE                            GENMASK(23, 16)
@@ -108,16 +93,5 @@ int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
 int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
                           struct stmmac_pps_cfg *cfg, bool enable,
                           u32 sub_second_inc, u32 systime_flags);
-void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
-                         u32 num_txq, u32 num_rxq,
-                         bool tx_enable, bool pmac_enable);
-void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
-                            struct stmmac_fpe_cfg *cfg,
-                            enum stmmac_mpacket_type type);
-int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
-int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr);
-void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
-int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
-                                   struct netlink_ext_ack *extack, u32 pclass);
 
 #endif /* __DWMAC5_H__ */
index 6a2c7d22df1eb81dd216e00e7525bc8a9092c048..917796293c261b982b08ba385fabe24b20524d91 100644 (file)
 #define XGMAC_MDIO_ADDR                        0x00000200
 #define XGMAC_MDIO_DATA                        0x00000204
 #define XGMAC_MDIO_C22P                        0x00000220
-#define XGMAC_FPE_CTRL_STS             0x00000280
-#define XGMAC_EFPE                     BIT(0)
 #define XGMAC_ADDRx_HIGH(x)            (0x00000300 + (x) * 0x8)
 #define XGMAC_ADDR_MAX                 32
 #define XGMAC_AE                       BIT(31)
index f519d43738b080191bb60197950a7ddee4d830b3..111ba5a524ed8077452ff616ce8d1121126df582 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/crc32.h>
 #include <linux/iopoll.h>
 #include "stmmac.h"
+#include "stmmac_fpe.h"
 #include "stmmac_ptp.h"
 #include "dwxlgmac2.h"
 #include "dwxgmac2.h"
@@ -1504,32 +1505,6 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en,
        writel(value, ioaddr + XGMAC_RX_CONFIG);
 }
 
-static void dwxgmac3_fpe_configure(void __iomem *ioaddr,
-                                  struct stmmac_fpe_cfg *cfg,
-                                  u32 num_txq, u32 num_rxq,
-                                  bool tx_enable, bool pmac_enable)
-{
-       u32 value;
-
-       if (!tx_enable) {
-               value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
-
-               value &= ~XGMAC_EFPE;
-
-               writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
-               return;
-       }
-
-       value = readl(ioaddr + XGMAC_RXQ_CTRL1);
-       value &= ~XGMAC_RQ;
-       value |= (num_rxq - 1) << XGMAC_RQ_SHIFT;
-       writel(value, ioaddr + XGMAC_RXQ_CTRL1);
-
-       value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
-       value |= XGMAC_EFPE;
-       writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
-}
-
 const struct stmmac_ops dwxgmac210_ops = {
        .core_init = dwxgmac2_core_init,
        .set_mac = dwxgmac2_set_mac,
index ea135203ff2e60117eff91149a0a5e3a62c6573a..816b979e72cc0effbcf93b256e735e437632414b 100644 (file)
@@ -146,15 +146,6 @@ struct stmmac_channel {
        u32 index;
 };
 
-/* FPE link-partner hand-shaking mPacket type */
-enum stmmac_mpacket_type {
-       MPACKET_VERIFY = 0,
-       MPACKET_RESPONSE = 1,
-};
-
-#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES       3
-#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS       128
-
 struct stmmac_fpe_cfg {
        /* Serialize access to MAC Merge state between ethtool requests
         * and link state updates.
@@ -420,7 +411,6 @@ bool stmmac_eee_init(struct stmmac_priv *priv);
 int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
 int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
 int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);
-void stmmac_fpe_apply(struct stmmac_priv *priv);
 
 static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
 {
index 2a37592a62810187e3371769df97af372948ddf1..2792a4c6cbcd288eefacd722d44d3299974ecae9 100644 (file)
@@ -17,9 +17,9 @@
 #include <linux/net_tstamp.h>
 
 #include "stmmac.h"
+#include "stmmac_fpe.h"
 #include "dwmac_dma.h"
 #include "dwxgmac2.h"
-#include "dwmac5.h"
 
 #define REG_SPACE_SIZE 0x1060
 #define GMAC4_REG_SPACE_SIZE   0x116C
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
new file mode 100644 (file)
index 0000000..8cfb5bc
--- /dev/null
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 Furong Xu <0x1207@gmail.com>
+ * stmmac FPE(802.3 Qbu) handling
+ */
+#include "stmmac.h"
+#include "stmmac_fpe.h"
+#include "dwmac4.h"
+#include "dwmac5.h"
+#include "dwxgmac2.h"
+
+#define MAC_FPE_CTRL_STS               0x00000234
+#define TRSP                           BIT(19)
+#define TVER                           BIT(18)
+#define RRSP                           BIT(17)
+#define RVER                           BIT(16)
+#define SRSP                           BIT(2)
+#define SVER                           BIT(1)
+#define EFPE                           BIT(0)
+
+#define MTL_FPE_CTRL_STS               0x00000c90
+/* Preemption Classification */
+#define DWMAC5_PREEMPTION_CLASS                GENMASK(15, 8)
+/* Additional Fragment Size of preempted frames */
+#define DWMAC5_ADD_FRAG_SZ             GENMASK(1, 0)
+
+#define XGMAC_FPE_CTRL_STS             0x00000280
+#define XGMAC_EFPE                     BIT(0)
+
+void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
+                         u32 num_txq, u32 num_rxq,
+                         bool tx_enable, bool pmac_enable)
+{
+       u32 value;
+
+       if (tx_enable) {
+               cfg->fpe_csr = EFPE;
+               value = readl(ioaddr + GMAC_RXQ_CTRL1);
+               value &= ~GMAC_RXQCTRL_FPRQ;
+               value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
+               writel(value, ioaddr + GMAC_RXQ_CTRL1);
+       } else {
+               cfg->fpe_csr = 0;
+       }
+       writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
+
+       value = readl(ioaddr + GMAC_INT_EN);
+
+       if (pmac_enable) {
+               if (!(value & GMAC_INT_FPE_EN)) {
+                       /* Dummy read to clear any pending masked interrupts */
+                       readl(ioaddr + MAC_FPE_CTRL_STS);
+
+                       value |= GMAC_INT_FPE_EN;
+               }
+       } else {
+               value &= ~GMAC_INT_FPE_EN;
+       }
+
+       writel(value, ioaddr + GMAC_INT_EN);
+}
+
+void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
+                            enum stmmac_mpacket_type type)
+{
+       u32 value = cfg->fpe_csr;
+
+       if (type == MPACKET_VERIFY)
+               value |= SVER;
+       else if (type == MPACKET_RESPONSE)
+               value |= SRSP;
+
+       writel(value, ioaddr + MAC_FPE_CTRL_STS);
+}
+
+void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
+{
+       struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
+
+       /* This is interrupt context, just spin_lock() */
+       spin_lock(&fpe_cfg->lock);
+
+       if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN)
+               goto unlock_out;
+
+       /* LP has sent verify mPacket */
+       if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER)
+               stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
+                                       MPACKET_RESPONSE);
+
+       /* Local has sent verify mPacket */
+       if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER &&
+           fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED)
+               fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
+
+       /* LP has sent response mPacket */
+       if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP &&
+           fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
+               fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
+
+unlock_out:
+       spin_unlock(&fpe_cfg->lock);
+}
+
+int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
+{
+       u32 value;
+       int status;
+
+       status = FPE_EVENT_UNKNOWN;
+
+       /* Reads from the MAC_FPE_CTRL_STS register should only be performed
+        * here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
+        */
+       value = readl(ioaddr + MAC_FPE_CTRL_STS);
+
+       if (value & TRSP) {
+               status |= FPE_EVENT_TRSP;
+               netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
+       }
+
+       if (value & TVER) {
+               status |= FPE_EVENT_TVER;
+               netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
+       }
+
+       if (value & RRSP) {
+               status |= FPE_EVENT_RRSP;
+               netdev_dbg(dev, "FPE: Respond mPacket is received\n");
+       }
+
+       if (value & RVER) {
+               status |= FPE_EVENT_RVER;
+               netdev_dbg(dev, "FPE: Verify mPacket is received\n");
+       }
+
+       return status;
+}
+
+/**
+ * stmmac_fpe_verify_timer - Timer for MAC Merge verification
+ * @t:  timer_list struct containing private info
+ *
+ * Verify the MAC Merge capability in the local TX direction, by
+ * transmitting Verify mPackets up to 3 times. Wait until link
+ * partner responds with a Response mPacket, otherwise fail.
+ */
+static void stmmac_fpe_verify_timer(struct timer_list *t)
+{
+       struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer);
+       struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv,
+                                               fpe_cfg);
+       unsigned long flags;
+       bool rearm = false;
+
+       spin_lock_irqsave(&fpe_cfg->lock, flags);
+
+       switch (fpe_cfg->status) {
+       case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
+       case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
+               if (fpe_cfg->verify_retries != 0) {
+                       stmmac_fpe_send_mpacket(priv, priv->ioaddr,
+                                               fpe_cfg, MPACKET_VERIFY);
+                       rearm = true;
+               } else {
+                       fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
+               }
+
+               fpe_cfg->verify_retries--;
+               break;
+
+       case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
+               stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
+                                    priv->plat->tx_queues_to_use,
+                                    priv->plat->rx_queues_to_use,
+                                    true, true);
+               break;
+
+       default:
+               break;
+       }
+
+       if (rearm) {
+               mod_timer(&fpe_cfg->verify_timer,
+                         jiffies + msecs_to_jiffies(fpe_cfg->verify_time));
+       }
+
+       spin_unlock_irqrestore(&fpe_cfg->lock, flags);
+}
+
+static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg)
+{
+       if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled &&
+           fpe_cfg->verify_enabled &&
+           fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED &&
+           fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) {
+               timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0);
+               mod_timer(&fpe_cfg->verify_timer, jiffies);
+       }
+}
+
+void stmmac_fpe_init(struct stmmac_priv *priv)
+{
+       priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
+       priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS;
+       priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+       timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0);
+       spin_lock_init(&priv->fpe_cfg.lock);
+}
+
+void stmmac_fpe_apply(struct stmmac_priv *priv)
+{
+       struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
+
+       /* If verification is disabled, configure FPE right away.
+        * Otherwise let the timer code do it.
+        */
+       if (!fpe_cfg->verify_enabled) {
+               stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
+                                    priv->plat->tx_queues_to_use,
+                                    priv->plat->rx_queues_to_use,
+                                    fpe_cfg->tx_enabled,
+                                    fpe_cfg->pmac_enabled);
+       } else {
+               fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
+               fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
+
+               if (netif_running(priv->dev))
+                       stmmac_fpe_verify_timer_arm(fpe_cfg);
+       }
+}
+
+void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
+{
+       struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
+       unsigned long flags;
+
+       timer_shutdown_sync(&fpe_cfg->verify_timer);
+
+       spin_lock_irqsave(&fpe_cfg->lock, flags);
+
+       if (is_up && fpe_cfg->pmac_enabled) {
+               /* VERIFY process requires pmac enabled when NIC comes up */
+               stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
+                                    priv->plat->tx_queues_to_use,
+                                    priv->plat->rx_queues_to_use,
+                                    false, true);
+
+               /* New link => maybe new partner => new verification process */
+               stmmac_fpe_apply(priv);
+       } else {
+               /* No link => turn off EFPE */
+               stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
+                                    priv->plat->tx_queues_to_use,
+                                    priv->plat->rx_queues_to_use,
+                                    false, false);
+       }
+
+       spin_unlock_irqrestore(&fpe_cfg->lock, flags);
+}
+
+int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr)
+{
+       return FIELD_GET(DWMAC5_ADD_FRAG_SZ, readl(ioaddr + MTL_FPE_CTRL_STS));
+}
+
+void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
+{
+       u32 value;
+
+       value = readl(ioaddr + MTL_FPE_CTRL_STS);
+       writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ),
+              ioaddr + MTL_FPE_CTRL_STS);
+}
+
+#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
+#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
+
+int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
+                                   struct netlink_ext_ack *extack, u32 pclass)
+{
+       u32 val, offset, count, queue_weight, preemptible_txqs = 0;
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       u32 num_tc = ndev->num_tc;
+
+       if (!pclass)
+               goto update_mapping;
+
+       /* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
+        *
+        * Synopsys Databook:
+        * "The number of Tx DMA channels is equal to the number of Tx queues,
+        * and is direct one-to-one mapping."
+        */
+       for (u32 tc = 0; tc < num_tc; tc++) {
+               count = ndev->tc_to_txq[tc].count;
+               offset = ndev->tc_to_txq[tc].offset;
+
+               if (pclass & BIT(tc))
+                       preemptible_txqs |= GENMASK(offset + count - 1, offset);
+
+               /* This is 1:1 mapping, go to next TC */
+               if (count == 1)
+                       continue;
+
+               if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
+                       NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
+                       return -EINVAL;
+               }
+
+               queue_weight = priv->plat->tx_queues_cfg[offset].weight;
+
+               for (u32 i = 1; i < count; i++) {
+                       if (priv->plat->tx_queues_cfg[offset + i].weight !=
+                           queue_weight) {
+                               NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
+                                                      queue_weight, tc);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+update_mapping:
+       val = readl(priv->ioaddr + MTL_FPE_CTRL_STS);
+       writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS),
+              priv->ioaddr + MTL_FPE_CTRL_STS);
+
+       return 0;
+}
+
+void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
+                           u32 num_txq, u32 num_rxq,
+                           bool tx_enable, bool pmac_enable)
+{
+       u32 value;
+
+       if (!tx_enable) {
+               value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
+
+               value &= ~XGMAC_EFPE;
+
+               writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
+               return;
+       }
+
+       value = readl(ioaddr + XGMAC_RXQ_CTRL1);
+       value &= ~XGMAC_RQ;
+       value |= (num_rxq - 1) << XGMAC_RQ_SHIFT;
+       writel(value, ioaddr + XGMAC_RXQ_CTRL1);
+
+       value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
+       value |= XGMAC_EFPE;
+       writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h
new file mode 100644 (file)
index 0000000..25725fd
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2024 Furong Xu <0x1207@gmail.com>
+ * stmmac FPE(802.3 Qbu) handling
+ */
+#ifndef _STMMAC_FPE_H_
+#define _STMMAC_FPE_H_
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+
+#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES       3
+#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS       128
+
+/* FPE link-partner hand-shaking mPacket type */
+enum stmmac_mpacket_type {
+       MPACKET_VERIFY = 0,
+       MPACKET_RESPONSE = 1,
+};
+
+struct stmmac_priv;
+struct stmmac_fpe_cfg;
+
+void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up);
+void stmmac_fpe_event_status(struct stmmac_priv *priv, int status);
+void stmmac_fpe_init(struct stmmac_priv *priv);
+void stmmac_fpe_apply(struct stmmac_priv *priv);
+
+void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
+                         u32 num_txq, u32 num_rxq,
+                         bool tx_enable, bool pmac_enable);
+void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
+                            struct stmmac_fpe_cfg *cfg,
+                            enum stmmac_mpacket_type type);
+int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
+int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr);
+void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
+int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
+                                   struct netlink_ext_ack *extack, u32 pclass);
+
+void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
+                           u32 num_txq, u32 num_rxq,
+                           bool tx_enable, bool pmac_enable);
+
+#endif
index 208dbc68aaf9d4a650f167a76d1ef223d5eb6aec..20bd5440abcaabe14cb84189e53c37ae9157b782 100644 (file)
@@ -43,6 +43,7 @@
 #include <net/pkt_cls.h>
 #include <net/xdp_sock_drv.h>
 #include "stmmac_ptp.h"
+#include "stmmac_fpe.h"
 #include "stmmac.h"
 #include "stmmac_xdp.h"
 #include <linux/reset.h>
@@ -966,35 +967,6 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
        /* Nothing to do, xpcs_config() handles everything */
 }
 
-static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
-{
-       struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
-       unsigned long flags;
-
-       timer_shutdown_sync(&fpe_cfg->verify_timer);
-
-       spin_lock_irqsave(&fpe_cfg->lock, flags);
-
-       if (is_up && fpe_cfg->pmac_enabled) {
-               /* VERIFY process requires pmac enabled when NIC comes up */
-               stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
-                                    priv->plat->tx_queues_to_use,
-                                    priv->plat->rx_queues_to_use,
-                                    false, true);
-
-               /* New link => maybe new partner => new verification process */
-               stmmac_fpe_apply(priv);
-       } else {
-               /* No link => turn off EFPE */
-               stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
-                                    priv->plat->tx_queues_to_use,
-                                    priv->plat->rx_queues_to_use,
-                                    false, false);
-       }
-
-       spin_unlock_irqrestore(&fpe_cfg->lock, flags);
-}
-
 static void stmmac_mac_link_down(struct phylink_config *config,
                                 unsigned int mode, phy_interface_t interface)
 {
@@ -5965,35 +5937,6 @@ static int stmmac_set_features(struct net_device *netdev,
        return 0;
 }
 
-static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
-{
-       struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
-
-       /* This is interrupt context, just spin_lock() */
-       spin_lock(&fpe_cfg->lock);
-
-       if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN)
-               goto unlock_out;
-
-       /* LP has sent verify mPacket */
-       if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER)
-               stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
-                                       MPACKET_RESPONSE);
-
-       /* Local has sent verify mPacket */
-       if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER &&
-           fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED)
-               fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
-
-       /* LP has sent response mPacket */
-       if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP &&
-           fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
-               fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
-
-unlock_out:
-       spin_unlock(&fpe_cfg->lock);
-}
-
 static void stmmac_common_interrupt(struct stmmac_priv *priv)
 {
        u32 rx_cnt = priv->plat->rx_queues_to_use;
@@ -7349,90 +7292,6 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size)
        return ret;
 }
 
-/**
- * stmmac_fpe_verify_timer - Timer for MAC Merge verification
- * @t:  timer_list struct containing private info
- *
- * Verify the MAC Merge capability in the local TX direction, by
- * transmitting Verify mPackets up to 3 times. Wait until link
- * partner responds with a Response mPacket, otherwise fail.
- */
-static void stmmac_fpe_verify_timer(struct timer_list *t)
-{
-       struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer);
-       struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv,
-                                               fpe_cfg);
-       unsigned long flags;
-       bool rearm = false;
-
-       spin_lock_irqsave(&fpe_cfg->lock, flags);
-
-       switch (fpe_cfg->status) {
-       case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
-       case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
-               if (fpe_cfg->verify_retries != 0) {
-                       stmmac_fpe_send_mpacket(priv, priv->ioaddr,
-                                               fpe_cfg, MPACKET_VERIFY);
-                       rearm = true;
-               } else {
-                       fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
-               }
-
-               fpe_cfg->verify_retries--;
-               break;
-
-       case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
-               stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
-                                    priv->plat->tx_queues_to_use,
-                                    priv->plat->rx_queues_to_use,
-                                    true, true);
-               break;
-
-       default:
-               break;
-       }
-
-       if (rearm) {
-               mod_timer(&fpe_cfg->verify_timer,
-                         jiffies + msecs_to_jiffies(fpe_cfg->verify_time));
-       }
-
-       spin_unlock_irqrestore(&fpe_cfg->lock, flags);
-}
-
-static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg)
-{
-       if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled &&
-           fpe_cfg->verify_enabled &&
-           fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED &&
-           fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) {
-               timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0);
-               mod_timer(&fpe_cfg->verify_timer, jiffies);
-       }
-}
-
-void stmmac_fpe_apply(struct stmmac_priv *priv)
-{
-       struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
-
-       /* If verification is disabled, configure FPE right away.
-        * Otherwise let the timer code do it.
-        */
-       if (!fpe_cfg->verify_enabled) {
-               stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
-                                    priv->plat->tx_queues_to_use,
-                                    priv->plat->rx_queues_to_use,
-                                    fpe_cfg->tx_enabled,
-                                    fpe_cfg->pmac_enabled);
-       } else {
-               fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
-               fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
-
-               if (netif_running(priv->dev))
-                       stmmac_fpe_verify_timer_arm(fpe_cfg);
-       }
-}
-
 static int stmmac_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
 {
        const struct stmmac_xdp_buff *ctx = (void *)_ctx;
@@ -7711,11 +7570,7 @@ int stmmac_dvr_probe(struct device *device,
 
        mutex_init(&priv->lock);
 
-       priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
-       priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS;
-       priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
-       timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0);
-       spin_lock_init(&priv->fpe_cfg.lock);
+       stmmac_fpe_init(priv);
 
        /* If a specific clk_csr value is passed from the platform
         * this means that the CSR Clock Range selection cannot be