]> git.dujemihanovic.xyz Git - linux.git/commitdiff
net: stmmac: support fp parameter of tc-mqprio
authorFurong Xu <0x1207@gmail.com>
Fri, 6 Sep 2024 14:30:10 +0000 (22:30 +0800)
committerJakub Kicinski <kuba@kernel.org>
Tue, 10 Sep 2024 23:42:12 +0000 (16:42 -0700)
tc-mqprio can select whether traffic classes are express or preemptible.

After some traffic tests, MAC merge layer statistics are all good.

Local device:
ethtool --include-statistics --json --show-mm eth1
[ {
        "ifname": "eth1",
        "pmac-enabled": true,
        "tx-enabled": true,
        "tx-active": true,
        "tx-min-frag-size": 60,
        "rx-min-frag-size": 60,
        "verify-enabled": true,
        "verify-time": 100,
        "max-verify-time": 128,
        "verify-status": "SUCCEEDED",
        "statistics": {
            "MACMergeFrameAssErrorCount": 0,
            "MACMergeFrameSmdErrorCount": 0,
            "MACMergeFrameAssOkCount": 0,
            "MACMergeFragCountRx": 0,
            "MACMergeFragCountTx": 35105,
            "MACMergeHoldCount": 0
        }
    } ]

Remote device:
ethtool --include-statistics --json --show-mm end1
[ {
        "ifname": "end1",
        "pmac-enabled": true,
        "tx-enabled": true,
        "tx-active": true,
        "tx-min-frag-size": 60,
        "rx-min-frag-size": 60,
        "verify-enabled": true,
        "verify-time": 100,
        "max-verify-time": 128,
        "verify-status": "SUCCEEDED",
        "statistics": {
            "MACMergeFrameAssErrorCount": 0,
            "MACMergeFrameSmdErrorCount": 0,
            "MACMergeFrameAssOkCount": 35105,
            "MACMergeFragCountRx": 35105,
            "MACMergeFragCountTx": 0,
            "MACMergeHoldCount": 0
        }
    } ]

Tested on DWMAC CORE 5.10a

Signed-off-by: Furong Xu <0x1207@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://patch.msgid.link/592965ea93ed8240f0a1b8f6f8ebb8914f69419b.1725631883.git.0x1207@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
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/hwif.c
drivers/net/ethernet/stmicro/stmmac/hwif.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c

index 679efcc631f1b54beac5acb05099ac83d8e7131a..a1858f083eef884a4aac484d39903b2e2efe431f 100644 (file)
@@ -1266,6 +1266,7 @@ const struct stmmac_ops dwmac410_ops = {
        .fpe_irq_status = dwmac5_fpe_irq_status,
        .fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size,
        .fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size,
+       .fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
        .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
        .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
        .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
@@ -1320,6 +1321,7 @@ const struct stmmac_ops dwmac510_ops = {
        .fpe_irq_status = dwmac5_fpe_irq_status,
        .fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size,
        .fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size,
+       .fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
        .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
        .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
        .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
index db7bbc50cfae3417db543cd3e7bccafc7eb7cc27..ab96fc055f48201e643619115d3fd69988c03072 100644 (file)
@@ -667,3 +667,58 @@ void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
        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 58704c15f320020e30ad87f63b53a593a85a078c..6c6eb6790e836a6cfa7cb638cd7d699f6e58f42c 100644 (file)
@@ -40,6 +40,8 @@
 #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)
 
@@ -115,5 +117,7 @@ void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
 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 29367105df548271d3aa22cfad80a40dece256c1..88cce28b2f98050be53266c2cf7253018353d40b 100644 (file)
@@ -171,7 +171,7 @@ static const struct stmmac_hwif_entry {
                .mac = &dwmac4_ops,
                .hwtimestamp = &stmmac_ptp,
                .mode = NULL,
-               .tc = &dwmac510_tc_ops,
+               .tc = &dwmac4_tc_ops,
                .mmc = &dwmac_mmc_ops,
                .est = &dwmac510_est_ops,
                .setup = dwmac4_setup,
@@ -252,7 +252,7 @@ static const struct stmmac_hwif_entry {
                .mac = &dwxgmac210_ops,
                .hwtimestamp = &stmmac_ptp,
                .mode = NULL,
-               .tc = &dwmac510_tc_ops,
+               .tc = &dwxgmac_tc_ops,
                .mmc = &dwxgmac_mmc_ops,
                .est = &dwmac510_est_ops,
                .setup = dwxgmac2_setup,
@@ -273,7 +273,7 @@ static const struct stmmac_hwif_entry {
                .mac = &dwxlgmac2_ops,
                .hwtimestamp = &stmmac_ptp,
                .mode = NULL,
-               .tc = &dwmac510_tc_ops,
+               .tc = &dwxgmac_tc_ops,
                .mmc = &dwxgmac_mmc_ops,
                .est = &dwmac510_est_ops,
                .setup = dwxlgmac2_setup,
index f080e271f7af3b58b1360f90f9889448f2690374..d5a9f01ecac53f79d697f2457cc355699cb10607 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/stmmac.h>
+#include <net/pkt_cls.h>
 
 #define stmmac_do_void_callback(__priv, __module, __cname,  __arg0, __args...) \
 ({ \
@@ -428,6 +429,9 @@ struct stmmac_ops {
        int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev);
        int (*fpe_get_add_frag_size)(const void __iomem *ioaddr);
        void (*fpe_set_add_frag_size)(void __iomem *ioaddr, u32 add_frag_size);
+       int (*fpe_map_preemption_class)(struct net_device *ndev,
+                                       struct netlink_ext_ack *extack,
+                                       u32 pclass);
 };
 
 #define stmmac_core_init(__priv, __args...) \
@@ -536,6 +540,8 @@ struct stmmac_ops {
        stmmac_do_callback(__priv, mac, fpe_get_add_frag_size, __args)
 #define stmmac_fpe_set_add_frag_size(__priv, __args...) \
        stmmac_do_void_callback(__priv, mac, fpe_set_add_frag_size, __args)
+#define stmmac_fpe_map_preemption_class(__priv, __args...) \
+       stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args)
 
 /* PTP and HW Timer helpers */
 struct stmmac_hwtimestamp {
@@ -623,6 +629,8 @@ struct stmmac_tc_ops {
                         struct tc_etf_qopt_offload *qopt);
        int (*query_caps)(struct stmmac_priv *priv,
                          struct tc_query_caps_base *base);
+       int (*setup_mqprio)(struct stmmac_priv *priv,
+                           struct tc_mqprio_qopt_offload *qopt);
 };
 
 #define stmmac_tc_init(__priv, __args...) \
@@ -639,6 +647,8 @@ struct stmmac_tc_ops {
        stmmac_do_callback(__priv, tc, setup_etf, __args)
 #define stmmac_tc_query_caps(__priv, __args...) \
        stmmac_do_callback(__priv, tc, query_caps, __args)
+#define stmmac_tc_setup_mqprio(__priv, __args...) \
+       stmmac_do_callback(__priv, tc, setup_mqprio, __args)
 
 struct stmmac_counters;
 
@@ -682,7 +692,9 @@ extern const struct stmmac_dma_ops dwmac4_dma_ops;
 extern const struct stmmac_ops dwmac410_ops;
 extern const struct stmmac_dma_ops dwmac410_dma_ops;
 extern const struct stmmac_ops dwmac510_ops;
+extern const struct stmmac_tc_ops dwmac4_tc_ops;
 extern const struct stmmac_tc_ops dwmac510_tc_ops;
+extern const struct stmmac_tc_ops dwxgmac_tc_ops;
 extern const struct stmmac_ops dwxgmac210_ops;
 extern const struct stmmac_ops dwxlgmac2_ops;
 extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
index 5a38bdb3f535d70d0290af1c8d5777c21d3dc3e1..d3895d7eecfc52785b27abc7f5f5bd29117f3648 100644 (file)
@@ -6216,6 +6216,8 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
        switch (type) {
        case TC_QUERY_CAPS:
                return stmmac_tc_query_caps(priv, priv, type_data);
+       case TC_SETUP_QDISC_MQPRIO:
+               return stmmac_tc_setup_mqprio(priv, priv, type_data);
        case TC_SETUP_BLOCK:
                return flow_block_cb_setup_simple(type_data,
                                                  &stmmac_block_cb_list,
index a58282d6458c9e99c061e3da50bf60d3eb0cb9ad..cfdb9ab1fa2a35edc988c3b41289314319e0ee2f 100644 (file)
@@ -1174,6 +1174,13 @@ static int tc_query_caps(struct stmmac_priv *priv,
                         struct tc_query_caps_base *base)
 {
        switch (base->type) {
+       case TC_SETUP_QDISC_MQPRIO: {
+               struct tc_mqprio_caps *caps = base->caps;
+
+               caps->validate_queue_counts = true;
+
+               return 0;
+       }
        case TC_SETUP_QDISC_TAPRIO: {
                struct tc_taprio_caps *caps = base->caps;
 
@@ -1190,6 +1197,81 @@ static int tc_query_caps(struct stmmac_priv *priv,
        }
 }
 
+static void stmmac_reset_tc_mqprio(struct net_device *ndev,
+                                  struct netlink_ext_ack *extack)
+{
+       struct stmmac_priv *priv = netdev_priv(ndev);
+
+       netdev_reset_tc(ndev);
+       netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use);
+       stmmac_fpe_map_preemption_class(priv, ndev, extack, 0);
+}
+
+static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
+                                   struct tc_mqprio_qopt_offload *mqprio)
+{
+       struct netlink_ext_ack *extack = mqprio->extack;
+       struct tc_mqprio_qopt *qopt = &mqprio->qopt;
+       u32 offset, count, num_stack_tx_queues = 0;
+       struct net_device *ndev = priv->dev;
+       u32 num_tc = qopt->num_tc;
+       int err;
+
+       if (!num_tc) {
+               stmmac_reset_tc_mqprio(ndev, extack);
+               return 0;
+       }
+
+       err = netdev_set_num_tc(ndev, num_tc);
+       if (err)
+               return err;
+
+       for (u32 tc = 0; tc < num_tc; tc++) {
+               offset = qopt->offset[tc];
+               count = qopt->count[tc];
+               num_stack_tx_queues += count;
+
+               err = netdev_set_tc_queue(ndev, tc, count, offset);
+               if (err)
+                       goto err_reset_tc;
+       }
+
+       err = netif_set_real_num_tx_queues(ndev, num_stack_tx_queues);
+       if (err)
+               goto err_reset_tc;
+
+       err = stmmac_fpe_map_preemption_class(priv, ndev, extack,
+                                             mqprio->preemptible_tcs);
+       if (err)
+               goto err_reset_tc;
+
+       return 0;
+
+err_reset_tc:
+       stmmac_reset_tc_mqprio(ndev, extack);
+
+       return err;
+}
+
+static int tc_setup_mqprio_unimplemented(struct stmmac_priv *priv,
+                                        struct tc_mqprio_qopt_offload *mqprio)
+{
+       NL_SET_ERR_MSG_MOD(mqprio->extack,
+                          "mqprio HW offload is not implemented for this MAC");
+       return -EOPNOTSUPP;
+}
+
+const struct stmmac_tc_ops dwmac4_tc_ops = {
+       .init = tc_init,
+       .setup_cls_u32 = tc_setup_cls_u32,
+       .setup_cbs = tc_setup_cbs,
+       .setup_cls = tc_setup_cls,
+       .setup_taprio = tc_setup_taprio,
+       .setup_etf = tc_setup_etf,
+       .query_caps = tc_query_caps,
+       .setup_mqprio = tc_setup_mqprio_unimplemented,
+};
+
 const struct stmmac_tc_ops dwmac510_tc_ops = {
        .init = tc_init,
        .setup_cls_u32 = tc_setup_cls_u32,
@@ -1198,4 +1280,16 @@ const struct stmmac_tc_ops dwmac510_tc_ops = {
        .setup_taprio = tc_setup_taprio,
        .setup_etf = tc_setup_etf,
        .query_caps = tc_query_caps,
+       .setup_mqprio = tc_setup_dwmac510_mqprio,
+};
+
+const struct stmmac_tc_ops dwxgmac_tc_ops = {
+       .init = tc_init,
+       .setup_cls_u32 = tc_setup_cls_u32,
+       .setup_cbs = tc_setup_cbs,
+       .setup_cls = tc_setup_cls,
+       .setup_taprio = tc_setup_taprio,
+       .setup_etf = tc_setup_etf,
+       .query_caps = tc_query_caps,
+       .setup_mqprio = tc_setup_mqprio_unimplemented,
 };