<div dir="auto">Fq everything </div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">---------- Forwarded message ---------<br>From: <strong class="gmail_sendername" dir="auto">Felix Fietkau</strong> <span dir="auto"><<a href="mailto:nbd@nbd.name">nbd@nbd.name</a>></span><br>Date: Wed, Nov 16, 2022, 12:24 AM<br>Subject: [PATCH net-next 4/6] net: ethernet: mtk_eth_soc: implement multi-queue support for per-port queues<br>To:  <<a href="mailto:netdev@vger.kernel.org">netdev@vger.kernel.org</a>>, John Crispin <<a href="mailto:john@phrozen.org">john@phrozen.org</a>>, Sean Wang <<a href="mailto:sean.wang@mediatek.com">sean.wang@mediatek.com</a>>, Mark Lee <<a href="mailto:Mark-MC.Lee@mediatek.com">Mark-MC.Lee@mediatek.com</a>>, Lorenzo Bianconi <<a href="mailto:lorenzo@kernel.org">lorenzo@kernel.org</a>>, David S. Miller <<a href="mailto:davem@davemloft.net">davem@davemloft.net</a>>, Eric Dumazet <<a href="mailto:edumazet@google.com">edumazet@google.com</a>>, Jakub Kicinski <<a href="mailto:kuba@kernel.org">kuba@kernel.org</a>>, Paolo Abeni <<a href="mailto:pabeni@redhat.com">pabeni@redhat.com</a>>, Matthias Brugger <<a href="mailto:matthias.bgg@gmail.com">matthias.bgg@gmail.com</a>>, Russell King <<a href="mailto:linux@armlinux.org.uk">linux@armlinux.org.uk</a>><br>Cc:  <<a href="mailto:linux-arm-kernel@lists.infradead.org">linux-arm-kernel@lists.infradead.org</a>>,  <<a href="mailto:linux-mediatek@lists.infradead.org">linux-mediatek@lists.infradead.org</a>>,  <<a href="mailto:linux-kernel@vger.kernel.org">linux-kernel@vger.kernel.org</a>><br></div><br><br>When sending traffic to multiple ports with different link speeds, queued<br>
packets to one port can drown out tx to other ports.<br>
In order to better handle transmission to multiple ports, use the hardware<br>
shaper feature to implement weighted fair queueing between ports.<br>
Weight and maximum rate are automatically adjusted based on the link speed<br>
of the port.<br>
The first 3 queues are unrestricted and reserved for non-DSA direct tx on<br>
GMAC ports. The following queues are automatically assigned by the MTK DSA<br>
tag driver based on the target port number.<br>
The PPE offload code configures the queues for offloaded traffic in the same<br>
way.<br>
This feature is only supported on devices supporting QDMA. All queues still<br>
share the same DMA ring and descriptor pool.<br>
<br>
Signed-off-by: Felix Fietkau <<a href="mailto:nbd@nbd.name" target="_blank" rel="noreferrer">nbd@nbd.name</a>><br>
---<br>
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 281 ++++++++++++++++----<br>
 drivers/net/ethernet/mediatek/mtk_eth_soc.h |  26 +-<br>
 2 files changed, 258 insertions(+), 49 deletions(-)<br>
<br>
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c<br>
index 9e5545242216..e1cc813bbb6f 100644<br>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c<br>
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c<br>
@@ -55,6 +55,7 @@ static const struct mtk_reg_map mtk_reg_map = {<br>
        },<br>
        .qdma = {<br>
                .qtx_cfg        = 0x1800,<br>
+               .qtx_sch        = 0x1804,<br>
                .rx_ptr         = 0x1900,<br>
                .rx_cnt_cfg     = 0x1904,<br>
                .qcrx_ptr       = 0x1908,<br>
@@ -62,6 +63,7 @@ static const struct mtk_reg_map mtk_reg_map = {<br>
                .rst_idx        = 0x1a08,<br>
                .delay_irq      = 0x1a0c,<br>
                .fc_th          = 0x1a10,<br>
+               .tx_sch_rate    = 0x1a14,<br>
                .int_grp        = 0x1a20,<br>
                .hred           = 0x1a44,<br>
                .ctx_ptr        = 0x1b00,<br>
@@ -114,6 +116,7 @@ static const struct mtk_reg_map mt7986_reg_map = {<br>
        },<br>
        .qdma = {<br>
                .qtx_cfg        = 0x4400,<br>
+               .qtx_sch        = 0x4404,<br>
                .rx_ptr         = 0x4500,<br>
                .rx_cnt_cfg     = 0x4504,<br>
                .qcrx_ptr       = 0x4508,<br>
@@ -131,6 +134,7 @@ static const struct mtk_reg_map mt7986_reg_map = {<br>
                .fq_tail        = 0x4724,<br>
                .fq_count       = 0x4728,<br>
                .fq_blen        = 0x472c,<br>
+               .tx_sch_rate    = 0x4798,<br>
        },<br>
        .gdm1_cnt               = 0x1c00,<br>
        .gdma_to_ppe            = 0x3333,<br>
@@ -614,6 +618,75 @@ static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,<br>
        mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));<br>
 }<br>
<br>
+static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx,<br>
+                               int speed)<br>
+{<br>
+       const struct mtk_soc_data *soc = eth->soc;<br>
+       u32 ofs, val;<br>
+<br>
+       if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA))<br>
+               return;<br>
+<br>
+       val = MTK_QTX_SCH_MIN_RATE_EN |<br>
+             /* minimum: 10 Mbps */<br>
+             FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |<br>
+             FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |<br>
+             MTK_QTX_SCH_LEAKY_BUCKET_SIZE;<br>
+       if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))<br>
+               val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;<br>
+<br>
+       if (IS_ENABLED(CONFIG_SOC_MT7621)) {<br>
+               switch (speed) {<br>
+               case SPEED_10:<br>
+                       val |= MTK_QTX_SCH_MAX_RATE_EN |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 103) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 2) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);<br>
+                       break;<br>
+               case SPEED_100:<br>
+                       val |= MTK_QTX_SCH_MAX_RATE_EN |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 103) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 3);<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);<br>
+                       break;<br>
+               case SPEED_1000:<br>
+                       val |= MTK_QTX_SCH_MAX_RATE_EN |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 105) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 4) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 10);<br>
+                       break;<br>
+               default:<br>
+                       break;<br>
+               }<br>
+       } else {<br>
+               switch (speed) {<br>
+               case SPEED_10:<br>
+                       val |= MTK_QTX_SCH_MAX_RATE_EN |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 4) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);<br>
+                       break;<br>
+               case SPEED_100:<br>
+                       val |= MTK_QTX_SCH_MAX_RATE_EN |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5);<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);<br>
+                       break;<br>
+               case SPEED_1000:<br>
+                       val |= MTK_QTX_SCH_MAX_RATE_EN |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 10) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5) |<br>
+                              FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 10);<br>
+                       break;<br>
+               default:<br>
+                       break;<br>
+               }<br>
+       }<br>
+<br>
+       ofs = MTK_QTX_OFFSET * idx;<br>
+       mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);<br>
+}<br>
+<br>
 static void mtk_mac_link_up(struct phylink_config *config,<br>
                            struct phy_device *phy,<br>
                            unsigned int mode, phy_interface_t interface,<br>
@@ -639,6 +712,8 @@ static void mtk_mac_link_up(struct phylink_config *config,<br>
                break;<br>
        }<br>
<br>
+       mtk_set_queue_speed(mac->hw, mac->id, speed);<br>
+<br>
        /* Configure duplex */<br>
        if (duplex == DUPLEX_FULL)<br>
                mcr |= MAC_MCR_FORCE_DPX;<br>
@@ -1099,7 +1174,8 @@ static void mtk_tx_set_dma_desc_v1(struct net_device *dev, void *txd,<br>
<br>
        WRITE_ONCE(desc->txd1, info->addr);<br>
<br>
-       data = TX_DMA_SWC | TX_DMA_PLEN0(info->size);<br>
+       data = TX_DMA_SWC | TX_DMA_PLEN0(info->size) |<br>
+              FIELD_PREP(TX_DMA_PQID, info->qid);<br>
        if (info->last)<br>
                data |= TX_DMA_LS0;<br>
        WRITE_ONCE(desc->txd3, data);<br>
@@ -1133,9 +1209,6 @@ static void mtk_tx_set_dma_desc_v2(struct net_device *dev, void *txd,<br>
                data |= TX_DMA_LS0;<br>
        WRITE_ONCE(desc->txd3, data);<br>
<br>
-       if (!info->qid && mac->id)<br>
-               info->qid = MTK_QDMA_GMAC2_QID;<br>
-<br>
        data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */<br>
        data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid);<br>
        WRITE_ONCE(desc->txd4, data);<br>
@@ -1179,11 +1252,12 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,<br>
                .gso = gso,<br>
                .csum = skb->ip_summed == CHECKSUM_PARTIAL,<br>
                .vlan = skb_vlan_tag_present(skb),<br>
-               .qid = skb->mark & MTK_QDMA_TX_MASK,<br>
+               .qid = skb_get_queue_mapping(skb),<br>
                .vlan_tci = skb_vlan_tag_get(skb),<br>
                .first = true,<br>
                .last = !skb_is_nonlinear(skb),<br>
        };<br>
+       struct netdev_queue *txq;<br>
        struct mtk_mac *mac = netdev_priv(dev);<br>
        struct mtk_eth *eth = mac->hw;<br>
        const struct mtk_soc_data *soc = eth->soc;<br>
@@ -1191,8 +1265,10 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,<br>
        struct mtk_tx_dma *itxd_pdma, *txd_pdma;<br>
        struct mtk_tx_buf *itx_buf, *tx_buf;<br>
        int i, n_desc = 1;<br>
+       int queue = skb_get_queue_mapping(skb);<br>
        int k = 0;<br>
<br>
+       txq = netdev_get_tx_queue(dev, queue);<br>
        itxd = ring->next_free;<br>
        itxd_pdma = qdma_to_pdma(ring, itxd);<br>
        if (itxd == ring->last_free)<br>
@@ -1241,7 +1317,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,<br>
                        memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));<br>
                        txd_info.size = min_t(unsigned int, frag_size,<br>
                                              soc->txrx.dma_max_len);<br>
-                       txd_info.qid = skb->mark & MTK_QDMA_TX_MASK;<br>
+                       txd_info.qid = queue;<br>
                        txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 &&<br>
                                        !(frag_size - txd_info.size);<br>
                        txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag,<br>
@@ -1280,7 +1356,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,<br>
                        txd_pdma->txd2 |= TX_DMA_LS1;<br>
        }<br>
<br>
-       netdev_sent_queue(dev, skb->len);<br>
+       netdev_tx_sent_queue(txq, skb->len);<br>
        skb_tx_timestamp(skb);<br>
<br>
        ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);<br>
@@ -1292,8 +1368,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,<br>
        wmb();<br>
<br>
        if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) {<br>
-               if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) ||<br>
-                   !netdev_xmit_more())<br>
+               if (netif_xmit_stopped(txq) || !netdev_xmit_more())<br>
                        mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr);<br>
        } else {<br>
                int next_idx;<br>
@@ -1362,7 +1437,7 @@ static void mtk_wake_queue(struct mtk_eth *eth)<br>
        for (i = 0; i < MTK_MAC_COUNT; i++) {<br>
                if (!eth->netdev[i])<br>
                        continue;<br>
-               netif_wake_queue(eth->netdev[i]);<br>
+               netif_tx_wake_all_queues(eth->netdev[i]);<br>
        }<br>
 }<br>
<br>
@@ -1386,7 +1461,7 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)<br>
<br>
        tx_num = mtk_cal_txd_req(eth, skb);<br>
        if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {<br>
-               netif_stop_queue(dev);<br>
+               netif_tx_stop_all_queues(dev);<br>
                netif_err(eth, tx_queued, dev,<br>
                          "Tx Ring full when queue awake!\n");<br>
                spin_unlock(&eth->page_lock);<br>
@@ -1412,7 +1487,7 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)<br>
                goto drop;<br>
<br>
        if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))<br>
-               netif_stop_queue(dev);<br>
+               netif_tx_stop_all_queues(dev);<br>
<br>
        spin_unlock(&eth->page_lock);<br>
<br>
@@ -1579,10 +1654,12 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf,<br>
        struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf);<br>
        const struct mtk_soc_data *soc = eth->soc;<br>
        struct mtk_tx_ring *ring = &eth->tx_ring;<br>
+       struct mtk_mac *mac = netdev_priv(dev);<br>
        struct mtk_tx_dma_desc_info txd_info = {<br>
                .size   = xdpf->len,<br>
                .first  = true,<br>
                .last   = !xdp_frame_has_frags(xdpf),<br>
+               .qid    = mac->id,<br>
        };<br>
        int err, index = 0, n_desc = 1, nr_frags;<br>
        struct mtk_tx_buf *htx_buf, *tx_buf;<br>
@@ -1632,6 +1709,7 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf,<br>
                memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));<br>
                txd_info.size = skb_frag_size(&sinfo->frags[index]);<br>
                txd_info.last = index + 1 == nr_frags;<br>
+               txd_info.qid = mac->id;<br>
                data = skb_frag_address(&sinfo->frags[index]);<br>
<br>
                index++;<br>
@@ -1992,8 +2070,46 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,<br>
        return done;<br>
 }<br>
<br>
+struct mtk_poll_state {<br>
+    struct netdev_queue *txq;<br>
+    unsigned int total;<br>
+    unsigned int done;<br>
+    unsigned int bytes;<br>
+};<br>
+<br>
+static void<br>
+mtk_poll_tx_done(struct mtk_eth *eth, struct mtk_poll_state *state, u8 mac,<br>
+                struct sk_buff *skb)<br>
+{<br>
+       struct netdev_queue *txq;<br>
+       struct net_device *dev;<br>
+       unsigned int bytes = skb->len;<br>
+<br>
+       state->total++;<br>
+       eth->tx_packets++;<br>
+       eth->tx_bytes += bytes;<br>
+<br>
+       dev = eth->netdev[mac];<br>
+       if (!dev)<br>
+               return;<br>
+<br>
+       txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));<br>
+       if (state->txq == txq) {<br>
+               state->done++;<br>
+               state->bytes += bytes;<br>
+               return;<br>
+       }<br>
+<br>
+       if (state->txq)<br>
+               netdev_tx_completed_queue(state->txq, state->done, state->bytes);<br>
+<br>
+       state->txq = txq;<br>
+       state->done = 1;<br>
+       state->bytes = bytes;<br>
+}<br>
+<br>
 static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget,<br>
-                           unsigned int *done, unsigned int *bytes)<br>
+                           struct mtk_poll_state *state)<br>
 {<br>
        const struct mtk_reg_map *reg_map = eth->soc->reg_map;<br>
        struct mtk_tx_ring *ring = &eth->tx_ring;<br>
@@ -2025,12 +2141,9 @@ static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget,<br>
                        break;<br>
<br>
                if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) {<br>
-                       if (tx_buf->type == MTK_TYPE_SKB) {<br>
-                               struct sk_buff *skb = tx_buf->data;<br>
+                       if (tx_buf->type == MTK_TYPE_SKB)<br>
+                               mtk_poll_tx_done(eth, state, mac, tx_buf->data);<br>
<br>
-                               bytes[mac] += skb->len;<br>
-                               done[mac]++;<br>
-                       }<br>
                        budget--;<br>
                }<br>
                mtk_tx_unmap(eth, tx_buf, &bq, true);<br>
@@ -2049,7 +2162,7 @@ static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget,<br>
 }<br>
<br>
 static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget,<br>
-                           unsigned int *done, unsigned int *bytes)<br>
+                           struct mtk_poll_state *state)<br>
 {<br>
        struct mtk_tx_ring *ring = &eth->tx_ring;<br>
        struct mtk_tx_buf *tx_buf;<br>
@@ -2067,12 +2180,8 @@ static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget,<br>
                        break;<br>
<br>
                if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) {<br>
-                       if (tx_buf->type == MTK_TYPE_SKB) {<br>
-                               struct sk_buff *skb = tx_buf->data;<br>
-<br>
-                               bytes[0] += skb->len;<br>
-                               done[0]++;<br>
-                       }<br>
+                       if (tx_buf->type == MTK_TYPE_SKB)<br>
+                               mtk_poll_tx_done(eth, state, 0, tx_buf->data);<br>
                        budget--;<br>
                }<br>
                mtk_tx_unmap(eth, tx_buf, &bq, true);<br>
@@ -2094,26 +2203,15 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget)<br>
 {<br>
        struct mtk_tx_ring *ring = &eth->tx_ring;<br>
        struct dim_sample dim_sample = {};<br>
-       unsigned int done[MTK_MAX_DEVS];<br>
-       unsigned int bytes[MTK_MAX_DEVS];<br>
-       int total = 0, i;<br>
-<br>
-       memset(done, 0, sizeof(done));<br>
-       memset(bytes, 0, sizeof(bytes));<br>
+       struct mtk_poll_state state = {};<br>
<br>
        if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))<br>
-               budget = mtk_poll_tx_qdma(eth, budget, done, bytes);<br>
+               budget = mtk_poll_tx_qdma(eth, budget, &state);<br>
        else<br>
-               budget = mtk_poll_tx_pdma(eth, budget, done, bytes);<br>
+               budget = mtk_poll_tx_pdma(eth, budget, &state);<br>
<br>
-       for (i = 0; i < MTK_MAC_COUNT; i++) {<br>
-               if (!eth->netdev[i] || !done[i])<br>
-                       continue;<br>
-               netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);<br>
-               total += done[i];<br>
-               eth->tx_packets += done[i];<br>
-               eth->tx_bytes += bytes[i];<br>
-       }<br>
+       if (state.txq)<br>
+               netdev_tx_completed_queue(state.txq, state.done, state.bytes);<br>
<br>
        dim_update_sample(eth->tx_events, eth->tx_packets, eth->tx_bytes,<br>
                          &dim_sample);<br>
@@ -2123,7 +2221,7 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget)<br>
            (atomic_read(&ring->free_count) > ring->thresh))<br>
                mtk_wake_queue(eth);<br>
<br>
-       return total;<br>
+       return state.total;<br>
 }<br>
<br>
 static void mtk_handle_status_irq(struct mtk_eth *eth)<br>
@@ -2209,6 +2307,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth)<br>
        int i, sz = soc->txrx.txd_size;<br>
        struct mtk_tx_dma_v2 *txd;<br>
        int ring_size;<br>
+       u32 ofs, val;<br>
<br>
        if (MTK_HAS_CAPS(soc->caps, MTK_QDMA))<br>
                ring_size = MTK_QDMA_RING_SIZE;<br>
@@ -2276,8 +2375,25 @@ static int mtk_tx_alloc(struct mtk_eth *eth)<br>
                        ring->phys + ((ring_size - 1) * sz),<br>
                        soc->reg_map->qdma.crx_ptr);<br>
                mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr);<br>
-               mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES,<br>
-                       soc->reg_map->qdma.qtx_cfg);<br>
+<br>
+               for (i = 0, ofs = 0; i < MTK_QDMA_NUM_QUEUES; i++) {<br>
+                       val = (QDMA_RES_THRES << 8) | QDMA_RES_THRES;<br>
+                       mtk_w32(eth, val, soc->reg_map->qdma.qtx_cfg + ofs);<br>
+<br>
+                       val = MTK_QTX_SCH_MIN_RATE_EN |<br>
+                             /* minimum: 10 Mbps */<br>
+                             FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |<br>
+                             FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |<br>
+                             MTK_QTX_SCH_LEAKY_BUCKET_SIZE;<br>
+                       if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))<br>
+                               val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;<br>
+                       mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);<br>
+                       ofs += MTK_QTX_OFFSET;<br>
+               }<br>
+               val = MTK_QDMA_TX_SCH_MAX_WFQ | (MTK_QDMA_TX_SCH_MAX_WFQ << 16);<br>
+               mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate);<br>
+               if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))<br>
+                       mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate + 4);<br>
        } else {<br>
                mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0);<br>
                mtk_w32(eth, ring_size, MT7628_TX_MAX_CNT0);<br>
@@ -2957,7 +3073,7 @@ static int mtk_start_dma(struct mtk_eth *eth)<br>
                if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))<br>
                        val |= MTK_MUTLI_CNT | MTK_RESV_BUF |<br>
                               MTK_WCOMP_EN | MTK_DMAD_WR_WDONE |<br>
-                              MTK_CHK_DDONE_EN;<br>
+                              MTK_CHK_DDONE_EN | MTK_LEAKY_BUCKET_EN;<br>
                else<br>
                        val |= MTK_RX_BT_32DWORDS;<br>
                mtk_w32(eth, val, reg_map->qdma.glo_cfg);<br>
@@ -3014,6 +3130,45 @@ static bool mtk_uses_dsa(struct net_device *dev)<br>
 #endif<br>
 }<br>
<br>
+static int mtk_device_event(struct notifier_block *n, unsigned long event, void *ptr)<br>
+{<br>
+       struct mtk_mac *mac = container_of(n, struct mtk_mac, device_notifier);<br>
+       struct mtk_eth *eth = mac->hw;<br>
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);<br>
+       struct ethtool_link_ksettings s;<br>
+       struct net_device *ldev;<br>
+       struct list_head *iter;<br>
+       struct dsa_port *dp;<br>
+<br>
+       if (event != NETDEV_CHANGE)<br>
+               return NOTIFY_DONE;<br>
+<br>
+       netdev_for_each_lower_dev(dev, ldev, iter) {<br>
+               if (netdev_priv(ldev) == mac)<br>
+                       goto found;<br>
+       }<br>
+<br>
+       return NOTIFY_DONE;<br>
+<br>
+found:<br>
+       if (!dsa_slave_dev_check(dev))<br>
+               return NOTIFY_DONE;<br>
+<br>
+       if (__ethtool_get_link_ksettings(dev, &s))<br>
+               return NOTIFY_DONE;<br>
+<br>
+       if (s.base.speed == 0 || s.base.speed == ((__u32)-1))<br>
+               return NOTIFY_DONE;<br>
+<br>
+       dp = dsa_port_from_netdev(dev);<br>
+       if (dp->index >= MTK_QDMA_NUM_QUEUES)<br>
+               return NOTIFY_DONE;<br>
+<br>
+       mtk_set_queue_speed(eth, dp->index + 3, s.base.speed);<br>
+<br>
+       return NOTIFY_DONE;<br>
+}<br>
+<br>
 static int mtk_open(struct net_device *dev)<br>
 {<br>
        struct mtk_mac *mac = netdev_priv(dev);<br>
@@ -3078,7 +3233,8 @@ static int mtk_open(struct net_device *dev)<br>
                refcount_inc(&eth->dma_refcnt);<br>
<br>
        phylink_start(mac->phylink);<br>
-       netif_start_queue(dev);<br>
+       netif_tx_start_all_queues(dev);<br>
+<br>
        return 0;<br>
 }<br>
<br>
@@ -3607,8 +3763,12 @@ static int mtk_unreg_dev(struct mtk_eth *eth)<br>
        int i;<br>
<br>
        for (i = 0; i < MTK_MAC_COUNT; i++) {<br>
+               struct mtk_mac *mac;<br>
                if (!eth->netdev[i])<br>
                        continue;<br>
+               mac = netdev_priv(eth->netdev[i]);<br>
+               if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))<br>
+                       unregister_netdevice_notifier(&mac->device_notifier);<br>
                unregister_netdev(eth->netdev[i]);<br>
        }<br>
<br>
@@ -3824,6 +3984,23 @@ static int mtk_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)<br>
        return ret;<br>
 }<br>
<br>
+static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,<br>
+                           struct net_device *sb_dev)<br>
+{<br>
+       struct mtk_mac *mac = netdev_priv(dev);<br>
+       unsigned int queue = 0;<br>
+<br>
+       if (netdev_uses_dsa(dev))<br>
+               queue = skb_get_queue_mapping(skb) + 3;<br>
+       else<br>
+               queue = mac->id;<br>
+<br>
+       if (queue >= dev->num_tx_queues)<br>
+               queue = 0;<br>
+<br>
+       return queue;<br>
+}<br>
+<br>
 static const struct ethtool_ops mtk_ethtool_ops = {<br>
        .get_link_ksettings     = mtk_get_link_ksettings,<br>
        .set_link_ksettings     = mtk_set_link_ksettings,<br>
@@ -3859,6 +4036,7 @@ static const struct net_device_ops mtk_netdev_ops = {<br>
        .ndo_setup_tc           = mtk_eth_setup_tc,<br>
        .ndo_bpf                = mtk_xdp,<br>
        .ndo_xdp_xmit           = mtk_xdp_xmit,<br>
+       .ndo_select_queue       = mtk_select_queue,<br>
 };<br>
<br>
 static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)<br>
@@ -3868,6 +4046,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)<br>
        struct phylink *phylink;<br>
        struct mtk_mac *mac;<br>
        int id, err;<br>
+       int txqs = 1;<br>
<br>
        if (!_id) {<br>
                dev_err(eth->dev, "missing mac id\n");<br>
@@ -3885,7 +4064,10 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)<br>
                return -EINVAL;<br>
        }<br>
<br>
-       eth->netdev[id] = alloc_etherdev(sizeof(*mac));<br>
+       if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))<br>
+               txqs = MTK_QDMA_NUM_QUEUES;<br>
+<br>
+       eth->netdev[id] = alloc_etherdev_mqs(sizeof(*mac), txqs, 1);<br>
        if (!eth->netdev[id]) {<br>
                dev_err(eth->dev, "alloc_etherdev failed\n");<br>
                return -ENOMEM;<br>
@@ -3982,6 +4164,11 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)<br>
        else<br>
                eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH_2K - MTK_RX_ETH_HLEN;<br>
<br>
+       if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {<br>
+               mac->device_notifier.notifier_call = mtk_device_event;<br>
+               register_netdevice_notifier(&mac->device_notifier);<br>
+       }<br>
+<br>
        return 0;<br>
<br>
 free_netdev:<br>
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h<br>
index eaaa0c67ef2a..1581eba053ab 100644<br>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h<br>
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h<br>
@@ -25,6 +25,7 @@<br>
 #define MTK_MAX_DSA_PORTS      7<br>
 #define MTK_DSA_PORT_MASK      GENMASK(2, 0)<br>
<br>
+#define MTK_QDMA_NUM_QUEUES    16<br>
 #define MTK_QDMA_PAGE_SIZE     2048<br>
 #define MTK_MAX_RX_LENGTH      1536<br>
 #define MTK_MAX_RX_LENGTH_2K   2048<br>
@@ -210,8 +211,26 @@<br>
 #define MTK_RING_MAX_AGG_CNT_H         ((MTK_HW_LRO_MAX_AGG_CNT >> 6) & 0x3)<br>
<br>
 /* QDMA TX Queue Configuration Registers */<br>
+#define MTK_QTX_OFFSET         0x10<br>
 #define QDMA_RES_THRES         4<br>
<br>
+/* QDMA Tx Queue Scheduler Configuration Registers */<br>
+#define MTK_QTX_SCH_TX_SEL             BIT(31)<br>
+#define MTK_QTX_SCH_TX_SEL_V2          GENMASK(31, 30)<br>
+<br>
+#define MTK_QTX_SCH_LEAKY_BUCKET_EN    BIT(30)<br>
+#define MTK_QTX_SCH_LEAKY_BUCKET_SIZE  GENMASK(29, 28)<br>
+#define MTK_QTX_SCH_MIN_RATE_EN                BIT(27)<br>
+#define MTK_QTX_SCH_MIN_RATE_MAN       GENMASK(26, 20)<br>
+#define MTK_QTX_SCH_MIN_RATE_EXP       GENMASK(19, 16)<br>
+#define MTK_QTX_SCH_MAX_RATE_WEIGHT    GENMASK(15, 12)<br>
+#define MTK_QTX_SCH_MAX_RATE_EN                BIT(11)<br>
+#define MTK_QTX_SCH_MAX_RATE_MAN       GENMASK(10, 4)<br>
+#define MTK_QTX_SCH_MAX_RATE_EXP       GENMASK(3, 0)<br>
+<br>
+/* QDMA TX Scheduler Rate Control Register */<br>
+#define MTK_QDMA_TX_SCH_MAX_WFQ                BIT(15)<br>
+<br>
 /* QDMA Global Configuration Register */<br>
 #define MTK_RX_2B_OFFSET       BIT(31)<br>
 #define MTK_RX_BT_32DWORDS     (3 << 11)<br>
@@ -230,6 +249,7 @@<br>
 #define MTK_WCOMP_EN           BIT(24)<br>
 #define MTK_RESV_BUF           (0x40 << 16)<br>
 #define MTK_MUTLI_CNT          (0x4 << 12)<br>
+#define MTK_LEAKY_BUCKET_EN    BIT(11)<br>
<br>
 /* QDMA Flow Control Register */<br>
 #define FC_THRES_DROP_MODE     BIT(20)<br>
@@ -258,8 +278,6 @@<br>
 #define MTK_STAT_OFFSET                0x40<br>
<br>
 /* QDMA TX NUM */<br>
-#define MTK_QDMA_TX_NUM                16<br>
-#define MTK_QDMA_TX_MASK       (MTK_QDMA_TX_NUM - 1)<br>
 #define QID_BITS_V2(x)         (((x) & 0x3f) << 16)<br>
 #define MTK_QDMA_GMAC2_QID     8<br>
<br>
@@ -289,6 +307,7 @@<br>
 #define TX_DMA_PLEN0(x)                (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset)<br>
 #define TX_DMA_PLEN1(x)                ((x) & eth->soc->txrx.dma_max_len)<br>
 #define TX_DMA_SWC             BIT(14)<br>
+#define TX_DMA_PQID            GENMASK(3, 0)<br>
<br>
 /* PDMA on MT7628 */<br>
 #define TX_DMA_DONE            BIT(31)<br>
@@ -947,6 +966,7 @@ struct mtk_reg_map {<br>
        } pdma;<br>
        struct {<br>
                u32     qtx_cfg;        /* tx queue configuration */<br>
+               u32     qtx_sch;        /* tx queue scheduler configuration */<br>
                u32     rx_ptr;         /* rx base pointer */<br>
                u32     rx_cnt_cfg;     /* rx max count configuration */<br>
                u32     qcrx_ptr;       /* rx cpu pointer */<br>
@@ -964,6 +984,7 @@ struct mtk_reg_map {<br>
                u32     fq_tail;        /* fq tail pointer */<br>
                u32     fq_count;       /* fq free page count */<br>
                u32     fq_blen;        /* fq free page buffer length */<br>
+               u32     tx_sch_rate;    /* tx scheduler rate control registers */<br>
        } qdma;<br>
        u32     gdm1_cnt;<br>
        u32     gdma_to_ppe;<br>
@@ -1157,6 +1178,7 @@ struct mtk_mac {<br>
        __be32                          hwlro_ip[MTK_MAX_LRO_IP_CNT];<br>
        int                             hwlro_ip_cnt;<br>
        unsigned int                    syscfg0;<br>
+       struct notifier_block           device_notifier;<br>
 };<br>
<br>
 /* the struct describing the SoC. these are declared in the soc_xyz.c files */<br>
-- <br>
2.38.1<br>
<br>
</div>