rtase: Add ndo_setup_tc support for CBS offload in traffic control setup
authorJustin Lai <justinlai0215@realtek.com>
Wed, 16 Apr 2025 11:57:57 +0000 (19:57 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 22 Apr 2025 11:48:16 +0000 (13:48 +0200)
Add support for ndo_setup_tc to enable CBS offload functionality as
part of traffic control configuration for network devices, where CBS
is applied from the CPU to the switch. More specifically, CBS is
applied at the GMAC in the topmost architecture diagram.

Signed-off-by: Justin Lai <justinlai0215@realtek.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250416115757.28156-1-justinlai0215@realtek.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/realtek/rtase/rtase.h
drivers/net/ethernet/realtek/rtase/rtase_main.c

index 2bbfcad613abb6b7003695953ddce5d24d326c15..498cfe4d0cac3abb8adf238c73e61cf3a6eee65e 100644 (file)
@@ -170,6 +170,7 @@ enum rtase_registers {
 #define RTASE_TC_MODE_MASK GENMASK(11, 10)
 
        RTASE_TOKSEL      = 0x2046,
+       RTASE_TXQCRDT_0   = 0x2500,
        RTASE_RFIFONFULL  = 0x4406,
        RTASE_INT_MITI_TX = 0x0A00,
        RTASE_INT_MITI_RX = 0x0A80,
@@ -259,6 +260,12 @@ union rtase_rx_desc {
 #define RTASE_VLAN_TAG_MASK     GENMASK(15, 0)
 #define RTASE_RX_PKT_SIZE_MASK  GENMASK(13, 0)
 
+/* txqos hardware definitions */
+#define RTASE_1T_CLOCK            64
+#define RTASE_1T_POWER            10000000
+#define RTASE_IDLESLOPE_INT_SHIFT 25
+#define RTASE_IDLESLOPE_INT_MASK  GENMASK(31, 25)
+
 #define RTASE_IVEC_NAME_SIZE (IFNAMSIZ + 10)
 
 struct rtase_int_vector {
@@ -294,6 +301,13 @@ struct rtase_ring {
        u64 alloc_fail;
 };
 
+struct rtase_txqos {
+       int hicredit;
+       int locredit;
+       int idleslope;
+       int sendslope;
+};
+
 struct rtase_stats {
        u64 tx_dropped;
        u64 rx_dropped;
@@ -313,6 +327,7 @@ struct rtase_private {
 
        struct page_pool *page_pool;
        struct rtase_ring tx_ring[RTASE_NUM_TX_QUEUE];
+       struct rtase_txqos tx_qos[RTASE_NUM_TX_QUEUE];
        struct rtase_ring rx_ring[RTASE_NUM_RX_QUEUE];
        struct rtase_counters *tally_vaddr;
        dma_addr_t tally_paddr;
index 2aacc1996796db97700ca6ac0db445862e697fb7..6251548d50ffc578321024140dcde1a9c6e6bd83 100644 (file)
@@ -1661,6 +1661,65 @@ static void rtase_get_stats64(struct net_device *dev,
        stats->rx_length_errors = tp->stats.rx_length_errors;
 }
 
+static void rtase_set_hw_cbs(const struct rtase_private *tp, u32 queue)
+{
+       u32 idle = tp->tx_qos[queue].idleslope * RTASE_1T_CLOCK;
+       u32 val, i;
+
+       val = u32_encode_bits(idle / RTASE_1T_POWER, RTASE_IDLESLOPE_INT_MASK);
+       idle %= RTASE_1T_POWER;
+
+       for (i = 1; i <= RTASE_IDLESLOPE_INT_SHIFT; i++) {
+               idle *= 2;
+               if ((idle / RTASE_1T_POWER) == 1)
+                       val |= BIT(RTASE_IDLESLOPE_INT_SHIFT - i);
+
+               idle %= RTASE_1T_POWER;
+       }
+
+       rtase_w32(tp, RTASE_TXQCRDT_0 + queue * 4, val);
+}
+
+static int rtase_setup_tc_cbs(struct rtase_private *tp,
+                             const struct tc_cbs_qopt_offload *qopt)
+{
+       int queue = qopt->queue;
+
+       if (queue < 0 || queue >= tp->func_tx_queue_num)
+               return -EINVAL;
+
+       if (!qopt->enable) {
+               tp->tx_qos[queue].hicredit = 0;
+               tp->tx_qos[queue].locredit = 0;
+               tp->tx_qos[queue].idleslope = 0;
+               tp->tx_qos[queue].sendslope = 0;
+
+               rtase_w32(tp, RTASE_TXQCRDT_0 + queue * 4, 0);
+       } else {
+               tp->tx_qos[queue].hicredit = qopt->hicredit;
+               tp->tx_qos[queue].locredit = qopt->locredit;
+               tp->tx_qos[queue].idleslope = qopt->idleslope;
+               tp->tx_qos[queue].sendslope = qopt->sendslope;
+
+               rtase_set_hw_cbs(tp, queue);
+       }
+
+       return 0;
+}
+
+static int rtase_setup_tc(struct net_device *dev, enum tc_setup_type type,
+                         void *type_data)
+{
+       struct rtase_private *tp = netdev_priv(dev);
+
+       switch (type) {
+       case TC_SETUP_QDISC_CBS:
+               return rtase_setup_tc_cbs(tp, type_data);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static netdev_features_t rtase_fix_features(struct net_device *dev,
                                            netdev_features_t features)
 {
@@ -1696,6 +1755,7 @@ static const struct net_device_ops rtase_netdev_ops = {
        .ndo_change_mtu = rtase_change_mtu,
        .ndo_tx_timeout = rtase_tx_timeout,
        .ndo_get_stats64 = rtase_get_stats64,
+       .ndo_setup_tc = rtase_setup_tc,
        .ndo_fix_features = rtase_fix_features,
        .ndo_set_features = rtase_set_features,
 };