[RFC net-next v5 2/3] net: ethernet: mtk_eth_soc: Add RSS support

Frank Wunderlich
2025-12-19T15:12:51Z

From: Mason Chang <mason-cw.chang@mediatek.com>

Add support for Receive Side Scaling.

We can adjust SMP affinity with the following command:
echo [CPU bitmap num] > /proc/irq/[virtual IRQ ID]/smp_affinity,
with interrupts evenly assigned to 4 CPUs, we were able to measure
an RX throughput of 7.3Gbps using iperf3 on the MT7988. Further
optimizations will be carried out in the future.

The experimental command is as follows:
PC: iperf3 -c [IP] -P 10
DUT: iperf3 -s

The entire indirection table can be imagined as 128 buckets, we
can use the ethtool command to mark which RX ring we want to send
the packets in these buckets to.

Show RSS RX ring parameters in indirection table and RSS hash key:
ethtool -x [interface]
Change RSS RX rings weight under uniform distribution:
ethtool --set-rxfh-indir [interface] equal [ring num]
Change RSS RX rings weight under non-uniform distribution:
ethtool --set-rxfh-indir [interface] weight [ring0 weight]
[ring1 weight] [ring2 weight] [ring3 weight]

Signed-off-by: Mason Chang <mason-cw.chang@mediatek.com>
Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
---
v5:
- fix too long line reported by checkpatch
MTK_RSS_HASH_KEY_DW
MTK_RSS_INDR_TABLE_DW
MTK_LRO_CTRL_DW[123]_CFG

v4:
- drop unrelated file
- rss-changes suggested by andrew
- fix MTK_HW_LRO_RING_NUM macro (add eth)
- fix MTK_LRO_CTRL_DW[123]_CFG (add reg_map param)
- fix MTK_RX_DONE_INT (add eth param)

v3:
- changes requested by jakub
- readded rss fix for mt7986
- name all PDMA-IRQ the same way

v2:
- drop wrong change (MTK_CDMP_IG_CTRL is only netsys v1)
- Fix immutable string IRQ setup (thx to Emilia Schotte)
- drop link to no more existent 6.6 patch in comment
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 544 +++++++++++++++-----
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 98 +++-
2 files changed, 496 insertions(+), 146 deletions(-)

diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 243ff16fd15e..4dfff59a3c8a 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1275,6 +1275,7 @@ static bool mtk_rx_get_desc(struct mtk_eth *eth, struct mtk_rx_dma_v2 *rxd,
if (mtk_is_netsys_v3_or_greater(eth)) {
rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
+ rxd->rxd7 = READ_ONCE(dma_rxd->rxd7);
}

return true;
@@ -1842,47 +1843,9 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}

-static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth)
+static void mtk_update_rx_cpu_idx(struct mtk_eth *eth, struct mtk_rx_ring *ring)
{
- int i;
- struct mtk_rx_ring *ring;
- int idx;
-
- if (!eth->hwlro)
- return &eth->rx_ring[0];
-
- for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
- struct mtk_rx_dma *rxd;
-
- ring = &eth->rx_ring[i];
- idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
- rxd = ring->dma + idx * eth->soc->rx.desc_size;
- if (rxd->rxd2 & RX_DMA_DONE) {
- ring->calc_idx_update = true;
- return ring;
- }
- }
-
- return NULL;
-}
-
-static void mtk_update_rx_cpu_idx(struct mtk_eth *eth)
-{
- struct mtk_rx_ring *ring;
- int i;
-
- if (!eth->hwlro) {
- ring = &eth->rx_ring[0];
- mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
- } else {
- for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
- ring = &eth->rx_ring[i];
- if (ring->calc_idx_update) {
- ring->calc_idx_update = false;
- mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
- }
- }
- }
+ mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
}

static bool mtk_page_pool_enabled(struct mtk_eth *eth)
@@ -1913,7 +1876,7 @@ static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
return pp;

err = __xdp_rxq_info_reg(xdp_q, eth->dummy_dev, id,
- eth->rx_napi.napi_id, PAGE_SIZE);
+ eth->rx_napi[id].napi.napi_id, PAGE_SIZE);
if (err < 0)
goto err_free_pp;

@@ -2202,7 +2165,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
struct mtk_eth *eth)
{
struct dim_sample dim_sample = {};
- struct mtk_rx_ring *ring;
+ struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+ struct mtk_rx_ring *ring = rx_napi->rx_ring;
bool xdp_flush = false;
int idx;
struct sk_buff *skb;
@@ -2213,16 +2177,15 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
dma_addr_t dma_addr = DMA_MAPPING_ERROR;
int ppe_idx = 0;

+ if (unlikely(!ring))
+ goto rx_done;
+
while (done < budget) {
unsigned int pktlen, *rxdcsum;
struct net_device *netdev;
u32 hash, reason;
int mac = 0;

- ring = mtk_get_rx_ring(eth);
- if (unlikely(!ring))
- goto rx_done;
-
idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
rxd = ring->dma + idx * eth->soc->rx.desc_size;
data = ring->data[idx];
@@ -2414,7 +2377,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
* we continue
*/
wmb();
- mtk_update_rx_cpu_idx(eth);
+ mtk_update_rx_cpu_idx(eth, ring);
}

eth->rx_packets += done;
@@ -2623,7 +2586,9 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)

static int mtk_napi_rx(struct napi_struct *napi, int budget)
{
- struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+ struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+ struct mtk_eth *eth = rx_napi->eth;
+ struct mtk_rx_ring *ring = rx_napi->rx_ring;
const struct mtk_reg_map *reg_map = eth->soc->reg_map;
int rx_done_total = 0;

@@ -2632,7 +2597,7 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
do {
int rx_done;

- mtk_w32(eth, eth->soc->rx.irq_done_mask,
+ mtk_w32(eth, MTK_RX_DONE_INT(eth, ring->ring_no),
reg_map->pdma.irq_status);
rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth);
rx_done_total += rx_done;
@@ -2648,10 +2613,10 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
return budget;

} while (mtk_r32(eth, reg_map->pdma.irq_status) &
- eth->soc->rx.irq_done_mask);
+ MTK_RX_DONE_INT(eth, ring->ring_no));

if (napi_complete_done(napi, rx_done_total))
- mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+ mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, ring->ring_no));

return rx_done_total;
}
@@ -2897,6 +2862,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
else
ring->crx_idx_reg = reg_map->pdma.pcrx_ptr +
ring_no * MTK_QRX_OFFSET;
+ ring->ring_no = ring_no;
/* make sure that all changes to the dma ring are flushed before we
* continue
*/
@@ -2965,6 +2931,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_

static int mtk_hwlro_rx_init(struct mtk_eth *eth)
{
+ const struct mtk_reg_map *reg_map = eth->soc->reg_map;
int i;
u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
@@ -2987,9 +2954,9 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)
ring_ctrl_dw3 |= MTK_RING_MAX_AGG_CNT_H;

for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) {
- mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(i));
- mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(i));
- mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(i));
+ mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(reg_map, i));
+ mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
+ mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(reg_map, i));
}

/* IPv4 checksum update enable */
@@ -3025,6 +2992,7 @@ static int mtk_hwlro_rx_init(struct mtk_eth *eth)

static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
{
+ const struct mtk_reg_map *reg_map = eth->soc->reg_map;
int i;
u32 val;

@@ -3043,7 +3011,7 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)

/* invalidate lro rings */
for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
- mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(i));
+ mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(reg_map, i));

/* disable HW LRO */
mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0);
@@ -3051,27 +3019,29 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)

static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
{
+ const struct mtk_reg_map *reg_map = eth->soc->reg_map;
u32 reg_val;

- reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+ reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(reg_map, idx));

/* invalidate the IP setting */
- mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+ mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));

mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(idx));

/* validate the IP setting */
- mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+ mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));
}

static void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx)
{
+ const struct mtk_reg_map *reg_map = eth->soc->reg_map;
u32 reg_val;

- reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+ reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(reg_map, idx));

/* invalidate the IP setting */
- mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+ mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(reg_map, idx));

mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(idx));
}
@@ -3201,6 +3171,105 @@ static int mtk_hwlro_get_fdir_all(struct net_device *dev,
return 0;
}

+static u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index)
+{
+ u32 val = 0;
+ int i;
+
+ for (i = 16 * index; i < 16 * index + 16; i++)
+ val |= (rss_params->indirection_table[i] << (2 * (i % 16)));
+
+ return val;
+}
+
+static int mtk_rss_init(struct mtk_eth *eth)
+{
+ const struct mtk_soc_data *soc = eth->soc;
+ const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+ struct mtk_rss_params *rss_params = &eth->rss_params;
+ u32 val;
+ int i;
+
+ netdev_rss_key_fill(rss_params->hash_key, MTK_RSS_HASH_KEYSIZE);
+
+ for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+ rss_params->indirection_table[i] = ethtool_rxfh_indir_default(i, eth->soc->rss_num);
+
+ if (soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+ /* Set RSS rings to PSE modes */
+ for (i = 1; i <= MTK_HW_LRO_RING_NUM(eth); i++) {
+ val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
+ val |= MTK_RING_PSE_MODE;
+ mtk_w32(eth, val, MTK_LRO_CTRL_DW2_CFG(reg_map, i));
+ }
+
+ /* Enable non-lro multiple rx */
+ val = mtk_r32(eth, reg_map->pdma.lro_ctrl_dw0);
+ val |= MTK_NON_LRO_MULTI_EN;
+ mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+
+ /* Enable RSS dly int supoort */
+ val |= MTK_LRO_DLY_INT_EN;
+ mtk_w32(eth, val, reg_map->pdma.lro_ctrl_dw0);
+ }
+
+ /* Hash Type */
+ val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+ val |= MTK_RSS_IPV4_STATIC_HASH;
+ val |= MTK_RSS_IPV6_STATIC_HASH;
+ mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+ /* Hash Key */
+ for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+ mtk_w32(eth, rss_params->hash_key[i], MTK_RSS_HASH_KEY_DW(reg_map, i));
+
+ /* Select the size of indirection table */
+ for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+ mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+ MTK_RSS_INDR_TABLE_DW(reg_map, i));
+
+ /* Pause */
+ val |= MTK_RSS_CFG_REQ;
+ mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+ /* Enable RSS */
+ val |= MTK_RSS_EN;
+ mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+ /* Release pause */
+ val &= ~(MTK_RSS_CFG_REQ);
+ mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+ /* Set perRSS GRP INT */
+ mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(1)),
+ MTK_RX_DONE_INT(eth, MTK_RSS_RING(1)), reg_map->pdma.int_grp);
+ mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(2)),
+ MTK_RX_DONE_INT(eth, MTK_RSS_RING(2)), reg_map->pdma.int_grp + 0x4);
+ mtk_m32(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(3)),
+ MTK_RX_DONE_INT(eth, MTK_RSS_RING(3)), reg_map->pdma.int_grp3);
+
+ return 0;
+}
+
+static void mtk_rss_uninit(struct mtk_eth *eth)
+{
+ const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+ u32 val;
+
+ /* Pause */
+ val = mtk_r32(eth, reg_map->pdma.rss_glo_cfg);
+ val |= MTK_RSS_CFG_REQ;
+ mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+ /* Disable RSS */
+ val &= ~(MTK_RSS_EN);
+ mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+
+ /* Release pause */
+ val &= ~(MTK_RSS_CFG_REQ);
+ mtk_w32(eth, val, reg_map->pdma.rss_glo_cfg);
+}
+
static netdev_features_t mtk_fix_features(struct net_device *dev,
netdev_features_t features)
{
@@ -3291,6 +3360,17 @@ static int mtk_dma_init(struct mtk_eth *eth)
return err;
}

+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+ for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+ err = mtk_rx_alloc(eth, MTK_RSS_RING(i), MTK_RX_FLAGS_NORMAL);
+ if (err)
+ return err;
+ }
+ err = mtk_rss_init(eth);
+ if (err)
+ return err;
+ }
+
if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
/* Enable random early drop and set drop threshold
* automatically
@@ -3337,6 +3417,12 @@ static void mtk_dma_free(struct mtk_eth *eth)
mtk_rx_clean(eth, &eth->rx_ring[i], false);
}

+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+ mtk_rss_uninit(eth);
+ for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
+ mtk_rx_clean(eth, &eth->rx_ring[MTK_RSS_RING(i)], true);
+ }
+
for (i = 0; i < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); i++) {
kfree(eth->scratch_head[i]);
eth->scratch_head[i] = NULL;
@@ -3369,23 +3455,23 @@ static void mtk_tx_timeout(struct net_device *dev, unsigned int txqueue)
schedule_work(&eth->pending_work);
}

-static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
+static int mtk_get_irqs_fe(struct platform_device *pdev, struct mtk_eth *eth)
{
int i;

/* future SoCs beginning with MT7988 should use named IRQs in dts */
- eth->irq[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
- eth->irq[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
- if (eth->irq[MTK_FE_IRQ_TX] >= 0 && eth->irq[MTK_FE_IRQ_RX] >= 0)
+ eth->irq_fe[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1");
+ eth->irq_fe[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2");
+ if (eth->irq_fe[MTK_FE_IRQ_TX] >= 0 && eth->irq_fe[MTK_FE_IRQ_RX] >= 0)
return 0;

/* only use legacy mode if platform_get_irq_byname_optional returned -ENXIO */
- if (eth->irq[MTK_FE_IRQ_TX] != -ENXIO)
- return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_TX],
+ if (eth->irq_fe[MTK_FE_IRQ_TX] != -ENXIO)
+ return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_TX],
"Error requesting FE TX IRQ\n");

- if (eth->irq[MTK_FE_IRQ_RX] != -ENXIO)
- return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_RX],
+ if (eth->irq_fe[MTK_FE_IRQ_RX] != -ENXIO)
+ return dev_err_probe(&pdev->dev, eth->irq_fe[MTK_FE_IRQ_RX],
"Error requesting FE RX IRQ\n");

if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT))
@@ -3400,14 +3486,14 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
for (i = 0; i < MTK_FE_IRQ_NUM; i++) {
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
if (i == MTK_FE_IRQ_SHARED)
- eth->irq[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
+ eth->irq_fe[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i);
else
- eth->irq[i] = eth->irq[MTK_FE_IRQ_SHARED];
+ eth->irq_fe[i] = eth->irq_fe[MTK_FE_IRQ_SHARED];
} else {
- eth->irq[i] = platform_get_irq(pdev, i + 1);
+ eth->irq_fe[i] = platform_get_irq(pdev, i + 1);
}

- if (eth->irq[i] < 0) {
+ if (eth->irq_fe[i] < 0) {
dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
return -ENXIO;
}
@@ -3416,14 +3502,36 @@ static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth)
return 0;
}

-static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
+static int mtk_get_irqs_pdma(struct platform_device *pdev, struct mtk_eth *eth)
{
- struct mtk_eth *eth = _eth;
+ char rxring[] = "pdma0";
+ int i;
+
+ for (i = 0; i < MTK_PDMA_IRQ_NUM; i++) {
+ rxring[4] = '0' + i;
+ eth->irq_pdma[i] = platform_get_irq_byname(pdev, rxring);
+ if (eth->irq_pdma[i] < 0)
+ return eth->irq_pdma[i];
+ }
+
+ return 0;
+}
+
+static irqreturn_t mtk_handle_irq_rx(int irq, void *priv)
+{
+ struct mtk_napi *rx_napi = priv;
+ struct mtk_eth *eth = rx_napi->eth;
+ struct mtk_rx_ring *ring = rx_napi->rx_ring;

eth->rx_events++;
- if (likely(napi_schedule_prep(&eth->rx_napi))) {
- mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
- __napi_schedule(&eth->rx_napi);
+ if (unlikely(!(mtk_r32(eth, eth->soc->reg_map->pdma.irq_status) &
+ mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask) &
+ MTK_RX_DONE_INT(eth, ring->ring_no))))
+ return IRQ_NONE;
+
+ if (likely(napi_schedule_prep(&rx_napi->napi))) {
+ mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, ring->ring_no));
+ __napi_schedule(&rx_napi->napi);
}

return IRQ_HANDLED;
@@ -3448,10 +3556,10 @@ static irqreturn_t mtk_handle_irq(int irq, void *_eth)
const struct mtk_reg_map *reg_map = eth->soc->reg_map;

if (mtk_r32(eth, reg_map->pdma.irq_mask) &
- eth->soc->rx.irq_done_mask) {
+ MTK_RX_DONE_INT(eth, 0)) {
if (mtk_r32(eth, reg_map->pdma.irq_status) &
- eth->soc->rx.irq_done_mask)
- mtk_handle_irq_rx(irq, _eth);
+ MTK_RX_DONE_INT(eth, 0))
+ mtk_handle_irq_rx(irq, &eth->rx_napi[0]);
}
if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) {
if (mtk_r32(eth, reg_map->tx_irq_status) & MTK_TX_DONE_INT)
@@ -3468,10 +3576,10 @@ static void mtk_poll_controller(struct net_device *dev)
struct mtk_eth *eth = mac->hw;

mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
- mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
- mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev);
+ mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, 0));
+ mtk_handle_irq_rx(eth->irq_fe[MTK_FE_IRQ_RX], &eth->rx_napi[0]);
mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
- mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+ mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, 0));
}
#endif

@@ -3643,9 +3751,17 @@ static int mtk_open(struct net_device *dev)
}

napi_enable(&eth->tx_napi);
- napi_enable(&eth->rx_napi);
+ napi_enable(&eth->rx_napi[0].napi);
mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
- mtk_rx_irq_enable(eth, soc->rx.irq_done_mask);
+ mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, 0));
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+ for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+ napi_enable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+ mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(i)));
+ }
+ }
+
refcount_set(&eth->dma_refcnt, 1);
} else {
refcount_inc(&eth->dma_refcnt);
@@ -3730,9 +3846,16 @@ static int mtk_stop(struct net_device *dev)
mtk_gdm_config(eth, i, MTK_GDMA_DROP_ALL);

mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
- mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
+ mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, 0));
napi_disable(&eth->tx_napi);
- napi_disable(&eth->rx_napi);
+ napi_disable(&eth->rx_napi[0].napi);
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+ for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+ mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(eth, MTK_RSS_RING(i)));
+ napi_disable(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+ }
+ }

cancel_work_sync(&eth->rx_dim.work);
cancel_work_sync(&eth->tx_dim.work);
@@ -3843,9 +3966,7 @@ static void mtk_dim_rx(struct work_struct *work)
dim->profile_ix);
spin_lock_bh(&eth->dim_lock);

- val = mtk_r32(eth, reg_map->pdma.delay_irq);
- val &= MTK_PDMA_DELAY_TX_MASK;
- val |= MTK_PDMA_DELAY_RX_EN;
+ val = MTK_PDMA_DELAY_RX_EN;

cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
val |= cur << MTK_PDMA_DELAY_RX_PTIME_SHIFT;
@@ -3853,9 +3974,19 @@ static void mtk_dim_rx(struct work_struct *work)
cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
val |= cur << MTK_PDMA_DELAY_RX_PINT_SHIFT;

- mtk_w32(eth, val, reg_map->pdma.delay_irq);
if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
- mtk_w32(eth, val, reg_map->qdma.delay_irq);
+ mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK,
+ val << MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+ if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+ mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK, val, reg_map->pdma.delay_irq);
+ mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int);
+ mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x4);
+ mtk_w32(eth, val, reg_map->pdma.lro_rx1_dly_int + 0x8);
+ } else {
+ val = val | (val << MTK_PDMA_DELAY_RX_RING_SHIFT);
+ mtk_w32(eth, val, reg_map->pdma.rx_delay_irq);
+ }

spin_unlock_bh(&eth->dim_lock);

@@ -3874,9 +4005,7 @@ static void mtk_dim_tx(struct work_struct *work)
dim->profile_ix);
spin_lock_bh(&eth->dim_lock);

- val = mtk_r32(eth, reg_map->pdma.delay_irq);
- val &= MTK_PDMA_DELAY_RX_MASK;
- val |= MTK_PDMA_DELAY_TX_EN;
+ val = MTK_PDMA_DELAY_TX_EN;

cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK);
val |= cur << MTK_PDMA_DELAY_TX_PTIME_SHIFT;
@@ -3884,9 +4013,16 @@ static void mtk_dim_tx(struct work_struct *work)
cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK);
val |= cur << MTK_PDMA_DELAY_TX_PINT_SHIFT;

- mtk_w32(eth, val, reg_map->pdma.delay_irq);
if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
- mtk_w32(eth, val, reg_map->qdma.delay_irq);
+ mtk_m32(eth, MTK_PDMA_DELAY_RX_MASK,
+ val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT, reg_map->qdma.delay_irq);
+
+ if (eth->soc->rx.desc_size == sizeof(struct mtk_rx_dma)) {
+ mtk_m32(eth, MTK_PDMA_DELAY_TX_MASK, val, reg_map->pdma.delay_irq);
+ } else {
+ mtk_w32(eth, val >> MTK_PDMA_DELAY_TX_PTIME_SHIFT,
+ reg_map->pdma.tx_delay_irq);
+ }

spin_unlock_bh(&eth->dim_lock);

@@ -4104,6 +4240,25 @@ static void mtk_hw_reset_monitor_work(struct work_struct *work)
MTK_DMA_MONITOR_TIMEOUT);
}

+static int mtk_napi_init(struct mtk_eth *eth)
+{
+ struct mtk_napi *rx_napi = &eth->rx_napi[0];
+ int i;
+
+ rx_napi->eth = eth;
+ rx_napi->rx_ring = &eth->rx_ring[0];
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+ for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+ rx_napi = &eth->rx_napi[MTK_RSS_RING(i)];
+ rx_napi->eth = eth;
+ rx_napi->rx_ring = &eth->rx_ring[MTK_RSS_RING(i)];
+ }
+ }
+
+ return 0;
+}
+
static int mtk_hw_init(struct mtk_eth *eth, bool reset)
{
u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA |
@@ -4193,12 +4348,11 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
*/
val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
- if (mtk_is_netsys_v1(eth)) {
- val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
- mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
+ val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
+ mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);

+ if (mtk_is_netsys_v1(eth))
mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
- }

/* set interrupt delays based on current Net DIM sample */
mtk_dim_rx(&eth->rx_dim.work);
@@ -4209,11 +4363,17 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
mtk_rx_irq_disable(eth, ~0);

/* FE int grouping */
- mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
- mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->pdma.int_grp + 4);
+
mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp);
- mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->qdma.int_grp + 4);
- mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+ mtk_w32(eth, MTK_RX_DONE_INT(eth, 0), reg_map->qdma.int_grp + 4);
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+ mtk_w32(eth, 0x210FFFF2, MTK_FE_INT_GRP);
+ } else {
+ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
+ mtk_w32(eth, MTK_RX_DONE_INT(eth, 0), reg_map->pdma.int_grp + 4);
+ mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+ }

if (mtk_is_netsys_v3_or_greater(eth)) {
/* PSE dummy page mechanism */
@@ -4651,6 +4811,8 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
int ret = -EOPNOTSUPP;

switch (cmd->cmd) {
@@ -4658,6 +4820,9 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
if (dev->hw_features & NETIF_F_LRO) {
cmd->data = MTK_MAX_RX_RING_NUM;
ret = 0;
+ } else if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+ cmd->data = MTK_RX_RSS_NUM(eth);
+ ret = 0;
}
break;
case ETHTOOL_GRXCLSRLCNT:
@@ -4732,6 +4897,70 @@ static int mtk_set_eee(struct net_device *dev, struct ethtool_keee *eee)
return phylink_ethtool_set_eee(mac->phylink, eee);
}

+static u32 mtk_get_rxfh_key_size(struct net_device *dev)
+{
+ return MTK_RSS_HASH_KEYSIZE;
+}
+
+static u32 mtk_get_rxfh_indir_size(struct net_device *dev)
+{
+ return MTK_RSS_MAX_INDIRECTION_TABLE;
+}
+
+static int mtk_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ struct mtk_rss_params *rss_params = &eth->rss_params;
+ int i;
+
+ rxfh->hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
+
+ if (rxfh->key) {
+ memcpy(rxfh->key, rss_params->hash_key,
+ sizeof(rss_params->hash_key));
+ }
+
+ if (rxfh->indir) {
+ for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+ rxfh->indir[i] = rss_params->indirection_table[i];
+ }
+
+ return 0;
+}
+
+static int mtk_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ struct mtk_rss_params *rss_params = &eth->rss_params;
+ const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+ int i;
+
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
+ return -EOPNOTSUPP;
+
+ if (rxfh->key) {
+ memcpy(rss_params->hash_key, rxfh->key,
+ sizeof(rss_params->hash_key));
+ for (i = 0; i < MTK_RSS_HASH_KEYSIZE / sizeof(u32); i++)
+ mtk_w32(eth, rss_params->hash_key[i],
+ MTK_RSS_HASH_KEY_DW(reg_map, i));
+ }
+
+ if (rxfh->indir) {
+ for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE; i++)
+ rss_params->indirection_table[i] = rxfh->indir[i];
+ for (i = 0; i < MTK_RSS_MAX_INDIRECTION_TABLE / 16; i++)
+ mtk_w32(eth, mtk_rss_indr_table(rss_params, i),
+ MTK_RSS_INDR_TABLE_DW(reg_map, i));
+ }
+
+ return 0;
+}
+
static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev)
{
@@ -4766,6 +4995,10 @@ static const struct ethtool_ops mtk_ethtool_ops = {
.set_rxnfc = mtk_set_rxnfc,
.get_eee = mtk_get_eee,
.set_eee = mtk_set_eee,
+ .get_rxfh_key_size = mtk_get_rxfh_key_size,
+ .get_rxfh_indir_size = mtk_get_rxfh_indir_size,
+ .get_rxfh = mtk_get_rxfh,
+ .set_rxfh = mtk_set_rxfh,
};

static const struct net_device_ops mtk_netdev_ops = {
@@ -4955,7 +5188,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
eth->netdev[id]->features |= eth->soc->hw_features;
eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;

- eth->netdev[id]->irq = eth->irq[MTK_FE_IRQ_SHARED];
+ eth->netdev[id]->irq = eth->irq_fe[MTK_FE_IRQ_SHARED];
eth->netdev[id]->dev.of_node = np;

if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
@@ -5066,6 +5299,7 @@ static int mtk_probe(struct platform_device *pdev)
struct resource *res = NULL;
struct device_node *mac_np;
struct mtk_eth *eth;
+ char *irqname;
int err, i;

eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
@@ -5197,10 +5431,16 @@ static int mtk_probe(struct platform_device *pdev)
}
}

- err = mtk_get_irqs(pdev, eth);
+ err = mtk_get_irqs_fe(pdev, eth);
if (err)
goto err_wed_exit;

+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+ err = mtk_get_irqs_pdma(pdev, eth);
+ if (err)
+ goto err_wed_exit;
+ }
+
for (i = 0; i < ARRAY_SIZE(eth->clks); i++) {
eth->clks[i] = devm_clk_get(eth->dev,
mtk_clks_source_name[i]);
@@ -5243,23 +5483,56 @@ static int mtk_probe(struct platform_device *pdev)
}
}

+ err = mtk_napi_init(eth);
+ if (err)
+ goto err_free_dev;
+
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
- err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_SHARED],
+ err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_SHARED],
mtk_handle_irq, 0,
dev_name(eth->dev), eth);
} else {
- err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_TX],
+ irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s TX",
+ dev_name(eth->dev));
+ err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_TX],
mtk_handle_irq_tx, 0,
- dev_name(eth->dev), eth);
+ irqname, eth);
if (err)
goto err_free_dev;

- err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_RX],
- mtk_handle_irq_rx, 0,
- dev_name(eth->dev), eth);
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
+ irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s PDMA RX %d",
+ dev_name(eth->dev), 0);
+ err = devm_request_irq(eth->dev, eth->irq_pdma[0],
+ mtk_handle_irq_rx, IRQF_SHARED,
+ irqname, &eth->rx_napi[0]);
+ if (err)
+ goto err_free_dev;
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+ for (i = 1; i < MTK_RX_RSS_NUM(eth); i++) {
+ irqname = devm_kasprintf(eth->dev, GFP_KERNEL,
+ "%s PDMA RX %d",
+ dev_name(eth->dev), i);
+ err = devm_request_irq(eth->dev,
+ eth->irq_pdma[MTK_RSS_RING(i)],
+ mtk_handle_irq_rx, IRQF_SHARED,
+ irqname,
+ &eth->rx_napi[MTK_RSS_RING(i)]);
+ if (err)
+ goto err_free_dev;
+ }
+ }
+ } else {
+ irqname = devm_kasprintf(eth->dev, GFP_KERNEL, "%s RX",
+ dev_name(eth->dev));
+ err = devm_request_irq(eth->dev, eth->irq_fe[MTK_FE_IRQ_RX],
+ mtk_handle_irq_rx, 0,
+ irqname, &eth->rx_napi[0]);
+ if (err)
+ goto err_free_dev;
+ }
}
- if (err)
- goto err_free_dev;

/* No MT7628/88 support yet */
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
@@ -5300,7 +5573,7 @@ static int mtk_probe(struct platform_device *pdev)
} else
netif_info(eth, probe, eth->netdev[i],
"mediatek frame engine at 0x%08lx, irq %d\n",
- eth->netdev[i]->base_addr, eth->irq[MTK_FE_IRQ_SHARED]);
+ eth->netdev[i]->base_addr, eth->irq_fe[MTK_FE_IRQ_SHARED]);
}

/* we run 2 devices on the same DMA ring so we need a dummy device
@@ -5313,7 +5586,13 @@ static int mtk_probe(struct platform_device *pdev)
goto err_unreg_netdev;
}
netif_napi_add(eth->dummy_dev, &eth->tx_napi, mtk_napi_tx);
- netif_napi_add(eth->dummy_dev, &eth->rx_napi, mtk_napi_rx);
+ netif_napi_add(eth->dummy_dev, &eth->rx_napi[0].napi, mtk_napi_rx);
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+ for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
+ netif_napi_add(eth->dummy_dev, &eth->rx_napi[MTK_RSS_RING(i)].napi,
+ mtk_napi_rx);
+ }

platform_set_drvdata(pdev, eth);
schedule_delayed_work(&eth->reset.monitor_work,
@@ -5357,7 +5636,12 @@ static void mtk_remove(struct platform_device *pdev)
mtk_hw_deinit(eth);

netif_napi_del(&eth->tx_napi);
- netif_napi_del(&eth->rx_napi);
+ netif_napi_del(&eth->rx_napi[0].napi);
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+ for (i = 1; i < MTK_RX_RSS_NUM(eth); i++)
+ netif_napi_del(&eth->rx_napi[MTK_RSS_RING(i)].napi);
+ }
mtk_cleanup(eth);
free_netdev(eth->dummy_dev);
mtk_mdio_cleanup(eth);
@@ -5370,6 +5654,7 @@ static const struct mtk_soc_data mt2701_data = {
.required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true,
.version = 1,
+ .rss_num = 0,
.tx = {
.desc_size = sizeof(struct mtk_tx_dma),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5379,7 +5664,6 @@ static const struct mtk_soc_data mt2701_data = {
},
.rx = {
.desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
.dma_l4_valid = RX_DMA_L4_VALID,
.dma_size = MTK_DMA_SIZE(2K),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5398,6 +5682,7 @@ static const struct mtk_soc_data mt7621_data = {
.ppe_num = 1,
.hash_offset = 2,
.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+ .rss_num = 0,
.tx = {
.desc_size = sizeof(struct mtk_tx_dma),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5407,7 +5692,6 @@ static const struct mtk_soc_data mt7621_data = {
},
.rx = {
.desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
.dma_l4_valid = RX_DMA_L4_VALID,
.dma_size = MTK_DMA_SIZE(2K),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5428,6 +5712,7 @@ static const struct mtk_soc_data mt7622_data = {
.hash_offset = 2,
.has_accounting = true,
.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+ .rss_num = 0,
.tx = {
.desc_size = sizeof(struct mtk_tx_dma),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5437,7 +5722,6 @@ static const struct mtk_soc_data mt7622_data = {
},
.rx = {
.desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
.dma_l4_valid = RX_DMA_L4_VALID,
.dma_size = MTK_DMA_SIZE(2K),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5457,6 +5741,7 @@ static const struct mtk_soc_data mt7623_data = {
.hash_offset = 2,
.foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
.disable_pll_modes = true,
+ .rss_num = 0,
.tx = {
.desc_size = sizeof(struct mtk_tx_dma),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5466,7 +5751,6 @@ static const struct mtk_soc_data mt7623_data = {
},
.rx = {
.desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
.dma_l4_valid = RX_DMA_L4_VALID,
.dma_size = MTK_DMA_SIZE(2K),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5483,6 +5767,7 @@ static const struct mtk_soc_data mt7629_data = {
.required_pctl = false,
.has_accounting = true,
.version = 1,
+ .rss_num = 0,
.tx = {
.desc_size = sizeof(struct mtk_tx_dma),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5492,7 +5777,6 @@ static const struct mtk_soc_data mt7629_data = {
},
.rx = {
.desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
.dma_l4_valid = RX_DMA_L4_VALID,
.dma_size = MTK_DMA_SIZE(2K),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5513,16 +5797,16 @@ static const struct mtk_soc_data mt7981_data = {
.hash_offset = 4,
.has_accounting = true,
.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+ .rss_num = 4,
.tx = {
.desc_size = sizeof(struct mtk_tx_dma_v2),
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = 8,
- .dma_size = MTK_DMA_SIZE(2K),
+ .dma_size = MTK_DMA_SIZE(4K),
.fq_dma_size = MTK_DMA_SIZE(2K),
},
.rx = {
.desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
.dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = 16,
@@ -5543,6 +5827,7 @@ static const struct mtk_soc_data mt7986_data = {
.hash_offset = 4,
.has_accounting = true,
.foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+ .rss_num = 4,
.tx = {
.desc_size = sizeof(struct mtk_tx_dma_v2),
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
@@ -5552,7 +5837,6 @@ static const struct mtk_soc_data mt7986_data = {
},
.rx = {
.desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
.dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = 16,
@@ -5573,20 +5857,20 @@ static const struct mtk_soc_data mt7988_data = {
.hash_offset = 4,
.has_accounting = true,
.foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
+ .rss_num = 4,
.tx = {
.desc_size = sizeof(struct mtk_tx_dma_v2),
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = 8,
- .dma_size = MTK_DMA_SIZE(2K),
+ .dma_size = MTK_DMA_SIZE(4K),
.fq_dma_size = MTK_DMA_SIZE(4K),
},
.rx = {
.desc_size = sizeof(struct mtk_rx_dma_v2),
- .irq_done_mask = MTK_RX_DONE_INT_V2,
.dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = 8,
- .dma_size = MTK_DMA_SIZE(2K),
+ .dma_size = MTK_DMA_SIZE(1K),
},
};

@@ -5597,6 +5881,7 @@ static const struct mtk_soc_data rt5350_data = {
.required_clks = MT7628_CLKS_BITMAP,
.required_pctl = false,
.version = 1,
+ .rss_num = 0,
.tx = {
.desc_size = sizeof(struct mtk_tx_dma),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
@@ -5605,7 +5890,6 @@ static const struct mtk_soc_data rt5350_data = {
},
.rx = {
.desc_size = sizeof(struct mtk_rx_dma),
- .irq_done_mask = MTK_RX_DONE_INT,
.dma_l4_valid = RX_DMA_L4_VALID_PDMA,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = 16,
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 334625814b97..987846d46151 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -76,6 +76,8 @@
#define MTK_HW_LRO_BW_THRE 3000
#define MTK_HW_LRO_REPLACE_DELTA 1000
#define MTK_HW_LRO_SDL_REMAIN_ROOM 1522
+#define MTK_RSS_HASH_KEYSIZE 40
+#define MTK_RSS_MAX_INDIRECTION_TABLE 128

/* Frame Engine Global Configuration */
#define MTK_FE_GLO_CFG(x) (((x) == MTK_GMAC3_ID) ? 0x24 : 0x00)
@@ -97,6 +99,8 @@
#define MTK_GDM1_AF BIT(28)
#define MTK_GDM2_AF BIT(29)

+#define MTK_PDMA_IRQ_NUM (4)
+
/* PDMA HW LRO Alter Flow Timer Register */
#define MTK_PDMA_LRO_ALT_REFRESH_TIMER 0x1c

@@ -179,7 +183,10 @@

/* PDMA HW LRO Control Registers */
#define MTK_PDMA_LRO_CTRL_DW0 0x980
+#define MTK_HW_LRO_RING_NUM(eth) (mtk_is_netsys_v3_or_greater(eth) ? 4 : 3)
#define MTK_LRO_EN BIT(0)
+#define MTK_NON_LRO_MULTI_EN BIT(2)
+#define MTK_LRO_DLY_INT_EN BIT(5)
#define MTK_L3_CKS_UPD_EN BIT(7)
#define MTK_L3_CKS_UPD_EN_V2 BIT(19)
#define MTK_LRO_ALT_PKT_CNT_MODE BIT(21)
@@ -198,6 +205,19 @@
#define MTK_MULTI_EN BIT(10)
#define MTK_PDMA_SIZE_8DWORDS (1 << 4)

+/* PDMA RSS Control Registers */
+#define MTK_RX_NAPI_NUM (4)
+#define MTK_RX_RSS_NUM(eth) (eth->soc->rss_num)
+#define MTK_RSS_RING(x) (x)
+#define MTK_RSS_EN BIT(0)
+#define MTK_RSS_CFG_REQ BIT(2)
+#define MTK_RSS_IPV6_STATIC_HASH (0x7 << 8)
+#define MTK_RSS_IPV4_STATIC_HASH (0x7 << 12)
+#define MTK_RSS_HASH_KEY_DW(reg_map, x) (reg_map->pdma.rss_glo_cfg + \
+ 0x20 + ((x) * 0x4))
+#define MTK_RSS_INDR_TABLE_DW(reg_map, x) (reg_map->pdma.rss_glo_cfg + \
+ 0x50 + ((x) * 0x4))
+
/* PDMA Global Configuration Register */
#define MTK_PDMA_LRO_SDL 0x3000
#define MTK_RX_CFG_SDL_OFFSET 16
@@ -209,6 +229,7 @@
/* PDMA Delay Interrupt Register */
#define MTK_PDMA_DELAY_RX_MASK GENMASK(15, 0)
#define MTK_PDMA_DELAY_RX_EN BIT(15)
+#define MTK_PDMA_DELAY_RX_RING_SHIFT 16
#define MTK_PDMA_DELAY_RX_PINT_SHIFT 8
#define MTK_PDMA_DELAY_RX_PTIME_SHIFT 0

@@ -229,14 +250,15 @@
#define MTK_RING_MYIP_VLD BIT(9)

/* PDMA HW LRO Ring Control Registers */
-#define MTK_LRO_RX_RING0_CTRL_DW1 0xb28
-#define MTK_LRO_RX_RING0_CTRL_DW2 0xb2c
-#define MTK_LRO_RX_RING0_CTRL_DW3 0xb30
-#define MTK_LRO_CTRL_DW1_CFG(x) (MTK_LRO_RX_RING0_CTRL_DW1 + (x * 0x40))
-#define MTK_LRO_CTRL_DW2_CFG(x) (MTK_LRO_RX_RING0_CTRL_DW2 + (x * 0x40))
-#define MTK_LRO_CTRL_DW3_CFG(x) (MTK_LRO_RX_RING0_CTRL_DW3 + (x * 0x40))
+#define MTK_LRO_CTRL_DW1_CFG(reg_map, x) (reg_map->pdma.lro_ring_ctrl_dw1 + \
+ ((x) * 0x40))
+#define MTK_LRO_CTRL_DW2_CFG(reg_map, x) (reg_map->pdma.lro_ring_ctrl_dw1 + \
+ 0x4 + ((x) * 0x40))
+#define MTK_LRO_CTRL_DW3_CFG(reg_map, x) (reg_map->pdma.lro_ring_ctrl_dw1 + \
+ 0x8 + ((x) * 0x40))
#define MTK_RING_AGE_TIME_L ((MTK_HW_LRO_AGE_TIME & 0x3ff) << 22)
#define MTK_RING_AGE_TIME_H ((MTK_HW_LRO_AGE_TIME >> 10) & 0x3f)
+#define MTK_RING_PSE_MODE BIT(6)
#define MTK_RING_AUTO_LERAN_MODE (3 << 6)
#define MTK_RING_VLD BIT(8)
#define MTK_RING_MAX_AGG_TIME ((MTK_HW_LRO_AGG_TIME & 0xffff) << 10)
@@ -290,7 +312,20 @@
#define FC_THRES_MIN 0x4444

/* QDMA Interrupt Status Register */
-#define MTK_RX_DONE_DLY BIT(30)
+#define MTK_RX_DONE_INT_V1(ring_no) \
+ ( \
+ (ring_no) ? \
+ BIT(24 + (ring_no)) : \
+ BIT(30) \
+ )
+
+#define MTK_RX_DONE_INT_V2(ring_no) BIT(24 + (ring_no))
+
+#define MTK_RX_DONE_INT(eth, ring_no) \
+ (mtk_is_netsys_v3_or_greater(eth) ? \
+ MTK_RX_DONE_INT_V2(ring_no) : \
+ MTK_RX_DONE_INT_V1(ring_no))
+
#define MTK_TX_DONE_DLY BIT(28)
#define MTK_RX_DONE_INT3 BIT(19)
#define MTK_RX_DONE_INT2 BIT(18)
@@ -300,11 +335,8 @@
#define MTK_TX_DONE_INT2 BIT(2)
#define MTK_TX_DONE_INT1 BIT(1)
#define MTK_TX_DONE_INT0 BIT(0)
-#define MTK_RX_DONE_INT MTK_RX_DONE_DLY
#define MTK_TX_DONE_INT MTK_TX_DONE_DLY

-#define MTK_RX_DONE_INT_V2 BIT(14)
-
#define MTK_CDM_TXFIFO_RDY BIT(7)

/* QDMA Interrupt grouping registers */
@@ -942,6 +974,7 @@ struct mtk_tx_ring {
struct mtk_tx_dma *dma_pdma; /* For MT7628/88 PDMA handling */
dma_addr_t phys_pdma;
int cpu_idx;
+ bool in_sram;
};

/* PDMA rx ring mode */
@@ -967,13 +1000,38 @@ struct mtk_rx_ring {
u16 buf_size;
u16 dma_size;
bool calc_idx_update;
+ bool in_sram;
u16 calc_idx;
u32 crx_idx_reg;
+ u32 ring_no;
/* page_pool */
struct page_pool *page_pool;
struct xdp_rxq_info xdp_q;
};

+/* struct mtk_rss_params - This is the structure holding parameters
+ * for the RSS ring
+ * @hash_key The element is used to record the
+ * secret key for the RSS ring
+ * indirection_table The element is used to record the
+ * indirection table for the RSS ring
+ */
+struct mtk_rss_params {
+ u32 hash_key[MTK_RSS_HASH_KEYSIZE / sizeof(u32)];
+ u8 indirection_table[MTK_RSS_MAX_INDIRECTION_TABLE];
+};
+
+/* struct mtk_napi - This is the structure holding NAPI-related information,
+ * and a mtk_napi struct is binding to one interrupt group
+ * @napi: The NAPI struct
+ * @rx_ring: Pointer to the memory holding info about the RX ring
+ */
+struct mtk_napi {
+ struct napi_struct napi;
+ struct mtk_eth *eth;
+ struct mtk_rx_ring *rx_ring;
+};
+
enum mkt_eth_capabilities {
MTK_RGMII_BIT = 0,
MTK_TRGMII_BIT,
@@ -985,7 +1043,9 @@ enum mkt_eth_capabilities {
MTK_INFRA_BIT,
MTK_SHARED_SGMII_BIT,
MTK_HWLRO_BIT,
+ MTK_RSS_BIT,
MTK_SHARED_INT_BIT,
+ MTK_PDMA_INT_BIT,
MTK_TRGMII_MT7621_CLK_BIT,
MTK_QDMA_BIT,
MTK_SOC_MT7628_BIT,
@@ -1025,7 +1085,9 @@ enum mkt_eth_capabilities {
#define MTK_INFRA BIT_ULL(MTK_INFRA_BIT)
#define MTK_SHARED_SGMII BIT_ULL(MTK_SHARED_SGMII_BIT)
#define MTK_HWLRO BIT_ULL(MTK_HWLRO_BIT)
+#define MTK_RSS BIT_ULL(MTK_RSS_BIT)
#define MTK_SHARED_INT BIT_ULL(MTK_SHARED_INT_BIT)
+#define MTK_PDMA_INT BIT_ULL(MTK_PDMA_INT_BIT)
#define MTK_TRGMII_MT7621_CLK BIT_ULL(MTK_TRGMII_MT7621_CLK_BIT)
#define MTK_QDMA BIT_ULL(MTK_QDMA_BIT)
#define MTK_SOC_MT7628 BIT_ULL(MTK_SOC_MT7628_BIT)
@@ -1117,15 +1179,15 @@ enum mkt_eth_capabilities {
#define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
- MTK_RSTCTRL_PPE1 | MTK_SRAM)
+ MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)

#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
- MTK_RSTCTRL_PPE1 | MTK_SRAM)
+ MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_PDMA_INT)

#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
- MTK_RSTCTRL_PPE2 | MTK_SRAM)
+ MTK_RSTCTRL_PPE2 | MTK_SRAM | MTK_PDMA_INT | MTK_RSS)

struct mtk_tx_dma_desc_info {
dma_addr_t addr;
@@ -1223,6 +1285,7 @@ struct mtk_reg_map {
struct mtk_soc_data {
const struct mtk_reg_map *reg_map;
u32 ana_rgc3;
+ u32 rss_num;
u64 caps;
u64 required_clks;
bool required_pctl;
@@ -1270,7 +1333,8 @@ struct mtk_soc_data {
* dummy for NAPI to work
* @netdev: The netdev instances
* @mac: Each netdev is linked to a physical MAC
- * @irq: The IRQ that we are using
+ * @irq_fe: Array of IRQs of the frame engine
+ * @irq_pdma: Array of IRQs of the PDMA used for RSS
* @msg_enable: Ethtool msg level
* @ethsys: The register map pointing at the range used to setup
* MII modes
@@ -1314,7 +1378,8 @@ struct mtk_eth {
struct net_device *dummy_dev;
struct net_device *netdev[MTK_MAX_DEVS];
struct mtk_mac *mac[MTK_MAX_DEVS];
- int irq[MTK_FE_IRQ_NUM];
+ int irq_fe[MTK_FE_IRQ_NUM];
+ int irq_pdma[MTK_PDMA_IRQ_NUM];
u32 msg_enable;
unsigned long sysclk;
struct regmap *ethsys;
@@ -1327,7 +1392,8 @@ struct mtk_eth {
struct mtk_rx_ring rx_ring[MTK_MAX_RX_RING_NUM];
struct mtk_rx_ring rx_ring_qdma;
struct napi_struct tx_napi;
- struct napi_struct rx_napi;
+ struct mtk_napi rx_napi[MTK_RX_NAPI_NUM];
+ struct mtk_rss_params rss_params;
void *scratch_ring;
dma_addr_t phy_scratch_ring;
void *scratch_head[MTK_FQ_DMA_HEAD];
--
2.43.0