Merge branch 'net-ethernet-mtk_eth_soc-improve-device-tree-handling'

Daniel Golle says:

====================
net: ethernet: mtk_eth_soc: improve device tree handling

This series further improves the mtk_eth_soc driver in preparation to
complete upstream support for the MediaTek MT7988 SoC family.

Frank Wunderlich's previous attempt to have the ethernet node included
in mt7988a.dtsi and cover support for MT7988 in the device tree bindings
was criticized for the way mtk_eth_soc references SRAM in device tree[1].

Having a 2nd 'reg' property, like introduced by commit ebb1e4f9cf
("net: ethernet: mtk_eth_soc: add support for in-SoC SRAM") isn't
acceptable and a dedicated "mmio-sram" node should be used instead.

In order to make the code more clean and readable, the existing
hardcoded offsets for the scratch ring, RX and TX rings are dropped in
favor of using the generic allocator. However, support for the hardcoded
offset of the SRAM itself being included as part of the Ethernet's "reg"
MMIO space is kept as it will still be required in order to support
existing legacy device trees of the MT7986 SoC family.

While at it also replace confusing error messages when using legacy
device trees without "interrupt-names" with a warning informing users
that they are using a legacy device tree.

[1]: https://patchwork.ozlabs.org/comment/3533543/
====================

Link: https://patch.msgid.link/cover.1751461762.git.daniel@makrotopia.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2025-07-07 18:50:48 -07:00
commit 49402a628e
3 changed files with 101 additions and 78 deletions

View File

@ -17,6 +17,7 @@ config NET_MEDIATEK_SOC
select PINCTRL
select PHYLINK
select DIMLIB
select GENERIC_ALLOCATOR
select PAGE_POOL
select PAGE_POOL_STATS
select PCS_MTK_LYNXI

View File

@ -27,6 +27,7 @@
#include <net/dsa.h>
#include <net/dst_metadata.h>
#include <net/page_pool/helpers.h>
#include <linux/genalloc.h>
#include "mtk_eth_soc.h"
#include "mtk_wed.h"
@ -1267,6 +1268,34 @@ static void *mtk_max_lro_buf_alloc(gfp_t gfp_mask)
return (void *)data;
}
static void *mtk_dma_ring_alloc(struct mtk_eth *eth, size_t size,
dma_addr_t *dma_handle, bool use_sram)
{
void *dma_ring;
if (use_sram && eth->sram_pool) {
dma_ring = (void *)gen_pool_alloc(eth->sram_pool, size);
if (!dma_ring)
return dma_ring;
*dma_handle = gen_pool_virt_to_phys(eth->sram_pool,
(unsigned long)dma_ring);
} else {
dma_ring = dma_alloc_coherent(eth->dma_dev, size, dma_handle,
GFP_KERNEL);
}
return dma_ring;
}
static void mtk_dma_ring_free(struct mtk_eth *eth, size_t size, void *dma_ring,
dma_addr_t dma_handle, bool in_sram)
{
if (in_sram && eth->sram_pool)
gen_pool_free(eth->sram_pool, (unsigned long)dma_ring, size);
else
dma_free_coherent(eth->dma_dev, size, dma_ring, dma_handle);
}
/* the qdma core needs scratch memory to be setup */
static int mtk_init_fq_dma(struct mtk_eth *eth)
{
@ -1276,13 +1305,8 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
dma_addr_t dma_addr;
int i, j, len;
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM))
eth->scratch_ring = eth->sram_base;
else
eth->scratch_ring = dma_alloc_coherent(eth->dma_dev,
cnt * soc->tx.desc_size,
&eth->phy_scratch_ring,
GFP_KERNEL);
eth->scratch_ring = mtk_dma_ring_alloc(eth, cnt * soc->tx.desc_size,
&eth->phy_scratch_ring, true);
if (unlikely(!eth->scratch_ring))
return -ENOMEM;
@ -2620,14 +2644,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
if (!ring->buf)
goto no_tx_mem;
if (MTK_HAS_CAPS(soc->caps, MTK_SRAM)) {
ring->dma = eth->sram_base + soc->tx.fq_dma_size * sz;
ring->phys = eth->phy_scratch_ring + soc->tx.fq_dma_size * (dma_addr_t)sz;
} else {
ring->dma = dma_alloc_coherent(eth->dma_dev, ring_size * sz,
&ring->phys, GFP_KERNEL);
}
ring->dma = mtk_dma_ring_alloc(eth, ring_size * sz, &ring->phys, true);
if (!ring->dma)
goto no_tx_mem;
@ -2726,10 +2743,10 @@ static void mtk_tx_clean(struct mtk_eth *eth)
kfree(ring->buf);
ring->buf = NULL;
}
if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && ring->dma) {
dma_free_coherent(eth->dma_dev,
ring->dma_size * soc->tx.desc_size,
ring->dma, ring->phys);
if (ring->dma) {
mtk_dma_ring_free(eth, ring->dma_size * soc->tx.desc_size,
ring->dma, ring->phys, true);
ring->dma = NULL;
}
@ -2746,14 +2763,9 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
const struct mtk_reg_map *reg_map = eth->soc->reg_map;
const struct mtk_soc_data *soc = eth->soc;
struct mtk_rx_ring *ring;
int rx_data_len, rx_dma_size, tx_ring_size;
int rx_data_len, rx_dma_size;
int i;
if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
tx_ring_size = MTK_QDMA_RING_SIZE;
else
tx_ring_size = soc->tx.dma_size;
if (rx_flag == MTK_RX_FLAGS_QDMA) {
if (ring_no)
return -EINVAL;
@ -2788,20 +2800,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
ring->page_pool = pp;
}
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM) ||
rx_flag != MTK_RX_FLAGS_NORMAL) {
ring->dma = dma_alloc_coherent(eth->dma_dev,
rx_dma_size * eth->soc->rx.desc_size,
&ring->phys, GFP_KERNEL);
} else {
struct mtk_tx_ring *tx_ring = &eth->tx_ring;
ring->dma = tx_ring->dma + tx_ring_size *
eth->soc->tx.desc_size * (ring_no + 1);
ring->phys = tx_ring->phys + tx_ring_size *
eth->soc->tx.desc_size * (ring_no + 1);
}
ring->dma = mtk_dma_ring_alloc(eth,
rx_dma_size * eth->soc->rx.desc_size,
&ring->phys,
rx_flag == MTK_RX_FLAGS_NORMAL);
if (!ring->dma)
return -ENOMEM;
@ -2916,10 +2918,9 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
ring->data = NULL;
}
if (!in_sram && ring->dma) {
dma_free_coherent(eth->dma_dev,
ring->dma_size * eth->soc->rx.desc_size,
ring->dma, ring->phys);
if (ring->dma) {
mtk_dma_ring_free(eth, ring->dma_size * eth->soc->rx.desc_size,
ring->dma, ring->phys, in_sram);
ring->dma = NULL;
}
@ -3287,15 +3288,16 @@ static void mtk_dma_free(struct mtk_eth *eth)
netdev_tx_reset_subqueue(eth->netdev[i], j);
}
if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) {
dma_free_coherent(eth->dma_dev,
MTK_QDMA_RING_SIZE * soc->tx.desc_size,
eth->scratch_ring, eth->phy_scratch_ring);
if (eth->scratch_ring) {
mtk_dma_ring_free(eth, soc->tx.fq_dma_size * soc->tx.desc_size,
eth->scratch_ring, eth->phy_scratch_ring,
true);
eth->scratch_ring = NULL;
eth->phy_scratch_ring = 0;
}
mtk_tx_clean(eth);
mtk_rx_clean(eth, &eth->rx_ring[0], MTK_HAS_CAPS(soc->caps, MTK_SRAM));
mtk_rx_clean(eth, &eth->rx_ring[0], true);
mtk_rx_clean(eth, &eth->rx_ring_qdma, false);
if (eth->hwlro) {
@ -3341,17 +3343,22 @@ static int mtk_get_irqs(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(pdev, "fe1");
eth->irq[MTK_FE_IRQ_RX] = platform_get_irq_byname(pdev, "fe2");
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)
return 0;
/* only use legacy mode if platform_get_irq_byname returned -ENXIO */
/* only use legacy mode if platform_get_irq_byname_optional returned -ENXIO */
if (eth->irq[MTK_FE_IRQ_TX] != -ENXIO)
return eth->irq[MTK_FE_IRQ_TX];
return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_TX],
"Error requesting FE TX IRQ\n");
if (eth->irq[MTK_FE_IRQ_RX] != -ENXIO)
return eth->irq[MTK_FE_IRQ_RX];
return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_RX],
"Error requesting FE RX IRQ\n");
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT))
dev_warn(&pdev->dev, "legacy DT: missing interrupt-names.");
/* legacy way:
* On MTK_SHARED_INT SoCs (MT7621 + MT7628) the first IRQ is taken
@ -5002,9 +5009,30 @@ static int mtk_sgmii_init(struct mtk_eth *eth)
return 0;
}
static int mtk_setup_legacy_sram(struct mtk_eth *eth, struct resource *res)
{
dev_warn(eth->dev, "legacy DT: using hard-coded SRAM offset.\n");
if (res->start + MTK_ETH_SRAM_OFFSET + MTK_ETH_NETSYS_V2_SRAM_SIZE - 1 >
res->end)
return -EINVAL;
eth->sram_pool = devm_gen_pool_create(eth->dev,
const_ilog2(MTK_ETH_SRAM_GRANULARITY),
NUMA_NO_NODE, dev_name(eth->dev));
if (IS_ERR(eth->sram_pool))
return PTR_ERR(eth->sram_pool);
return gen_pool_add_virt(eth->sram_pool,
(unsigned long)eth->base + MTK_ETH_SRAM_OFFSET,
res->start + MTK_ETH_SRAM_OFFSET,
MTK_ETH_NETSYS_V2_SRAM_SIZE, NUMA_NO_NODE);
}
static int mtk_probe(struct platform_device *pdev)
{
struct resource *res = NULL, *res_sram;
struct resource *res = NULL;
struct device_node *mac_np;
struct mtk_eth *eth;
int err, i;
@ -5024,20 +5052,6 @@ static int mtk_probe(struct platform_device *pdev)
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
eth->ip_align = NET_IP_ALIGN;
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM)) {
/* SRAM is actual memory and supports transparent access just like DRAM.
* Hence we don't require __iomem being set and don't need to use accessor
* functions to read from or write to SRAM.
*/
if (mtk_is_netsys_v3_or_greater(eth)) {
eth->sram_base = (void __force *)devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(eth->sram_base))
return PTR_ERR(eth->sram_base);
} else {
eth->sram_base = (void __force *)eth->base + MTK_ETH_SRAM_OFFSET;
}
}
if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) {
err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36));
if (!err)
@ -5112,16 +5126,21 @@ static int mtk_probe(struct platform_device *pdev)
err = -EINVAL;
goto err_destroy_sgmii;
}
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM)) {
if (mtk_is_netsys_v3_or_greater(eth)) {
res_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res_sram) {
eth->sram_pool = of_gen_pool_get(pdev->dev.of_node,
"sram", 0);
if (!eth->sram_pool) {
if (!mtk_is_netsys_v3_or_greater(eth)) {
err = mtk_setup_legacy_sram(eth, res);
if (err)
goto err_destroy_sgmii;
} else {
dev_err(&pdev->dev,
"Could not get SRAM pool\n");
err = -EINVAL;
goto err_destroy_sgmii;
}
eth->phy_scratch_ring = res_sram->start;
} else {
eth->phy_scratch_ring = res->start + MTK_ETH_SRAM_OFFSET;
}
}
}

View File

@ -141,8 +141,10 @@
#define MTK_GDMA_MAC_ADRH(x) ({ typeof(x) _x = (x); (_x == MTK_GMAC3_ID) ? \
0x54C : 0x50C + (_x * 0x1000); })
/* Internal SRAM offset */
#define MTK_ETH_SRAM_OFFSET 0x40000
/* legacy DT support for internal SRAM */
#define MTK_ETH_SRAM_OFFSET 0x40000
#define MTK_ETH_SRAM_GRANULARITY 32
#define MTK_ETH_NETSYS_V2_SRAM_SIZE 0x40000
/* FE global misc reg*/
#define MTK_FE_GLO_MISC 0x124
@ -1243,8 +1245,9 @@ struct mtk_soc_data {
/* struct mtk_eth - This is the main datasructure for holding the state
* of the driver
* @dev: The device pointer
* @dev: The device pointer used for dma mapping/alloc
* @dma_dev: The device pointer used for dma mapping/alloc
* @base: The mapped register i/o base
* @sram_pool: Pointer to SRAM pool used for DMA descriptor rings
* @page_lock: Make sure that register operations are atomic
* @tx_irq__lock: Make sure that IRQ register operations are atomic
* @rx_irq__lock: Make sure that IRQ register operations are atomic
@ -1290,7 +1293,7 @@ struct mtk_eth {
struct device *dev;
struct device *dma_dev;
void __iomem *base;
void *sram_base;
struct gen_pool *sram_pool;
spinlock_t page_lock;
spinlock_t tx_irq_lock;
spinlock_t rx_irq_lock;