[PATCH net-next v2 5/6] net: ftgmac100: Add AST2700 upper DMA address support
From: Jacky Chou
Date: Tue Oct 06 2026 - 03:25:10 EST
Program the high RX and TX descriptor ring base registers and carry the
upper DMA address bits in RX and TX descriptors. Rebuild full buffer DMA
addresses in a 64-bit type before unmapping them so bits 34:32 are not
lost to 32-bit arithmetic.
The descriptor format provides three upper buffer address bits, so
request a 35-bit DMA mask instead of advertising an address range that
the hardware cannot encode. Gate all extended address handling with a
match-data quirk so older register layouts remain untouched and later
compatible controllers can opt into the same capability.
Signed-off-by: Jacky Chou <jacky_chou@xxxxxxxxxxxxxx>
---
drivers/net/ethernet/faraday/ftgmac100.c | 62 +++++++++++++++++++++++++++-----
drivers/net/ethernet/faraday/ftgmac100.h | 6 ++++
2 files changed, 59 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 2d029d1262e6..af2e272f32f2 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -8,6 +8,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/dma-mapping.h>
@@ -42,6 +43,7 @@ enum ftgmac100_mac_id {
};
#define FTGMAC100_QUIRK_RMII_ENABLE BIT(0)
+#define FTGMAC100_QUIRK_DMA_35BIT BIT(1)
struct ftgmac100_match_data {
enum ftgmac100_mac_id mac_id;
@@ -303,10 +305,16 @@ static void ftgmac100_init_hw(struct ftgmac100 *priv)
iowrite32(reg, priv->base + FTGMAC100_OFFSET_ISR);
/* Setup RX ring buffer base */
- iowrite32(priv->rxdes_dma, priv->base + FTGMAC100_OFFSET_RXR_BADR);
+ iowrite32(lower_32_bits(priv->rxdes_dma), priv->base + FTGMAC100_OFFSET_RXR_BADR);
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT)
+ iowrite32(upper_32_bits(priv->rxdes_dma),
+ priv->base + FTGMAC100_OFFSET_RXR_BADDR_HIGH);
/* Setup TX ring buffer base */
- iowrite32(priv->txdes_dma, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
+ iowrite32(lower_32_bits(priv->txdes_dma), priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT)
+ iowrite32(upper_32_bits(priv->txdes_dma),
+ priv->base + FTGMAC100_OFFSET_TXR_BADDR_HIGH);
/* Configure RX buffer size */
iowrite32(FTGMAC100_RBSR_SIZE(RX_BUF_SIZE),
@@ -469,7 +477,10 @@ static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry,
priv->rx_skbs[entry] = skb;
/* Store DMA address into RX desc */
- rxdes->rxdes3 = cpu_to_le32(map);
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT)
+ rxdes->rxdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_RXDES2_RXBUF_BADR_HI,
+ upper_32_bits(map)));
+ rxdes->rxdes3 = cpu_to_le32(lower_32_bits(map));
/* Ensure the above is ordered vs clearing the OWN bit */
dma_wmb();
@@ -596,6 +607,9 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
/* Tear down DMA mapping, do necessary cache management */
map = le32_to_cpu(rxdes->rxdes3);
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT)
+ map |= (u64)FIELD_GET(FTGMAC100_RXDES2_RXBUF_BADR_HI,
+ le32_to_cpu(rxdes->rxdes2)) << 32;
#if defined(CONFIG_ARM) && !defined(CONFIG_ARM_DMA_USE_IOMMU)
/* When we don't have an iommu, we can save cycles by not
@@ -672,9 +686,14 @@ static void ftgmac100_free_tx_packet(struct ftgmac100 *priv,
struct ftgmac100_txdes *txdes,
u32 ctl_stat)
{
- dma_addr_t map = le32_to_cpu(txdes->txdes3);
+ dma_addr_t map;
size_t len;
+ map = le32_to_cpu(txdes->txdes3);
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT)
+ map |= (u64)FIELD_GET(FTGMAC100_TXDES2_TXBUF_BADR_HI,
+ le32_to_cpu(txdes->txdes2)) << 32;
+
if (ctl_stat & FTGMAC100_TXDES0_FTS) {
len = skb_headlen(skb);
dma_unmap_single(priv->dev, map, len, DMA_TO_DEVICE);
@@ -828,7 +847,10 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,
f_ctl_stat |= FTGMAC100_TXDES0_FTS;
if (nfrags == 0)
f_ctl_stat |= FTGMAC100_TXDES0_LTS;
- txdes->txdes3 = cpu_to_le32(map);
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT)
+ txdes->txdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_TXDES2_TXBUF_BADR_HI,
+ upper_32_bits(map)));
+ txdes->txdes3 = cpu_to_le32(lower_32_bits(map));
txdes->txdes1 = cpu_to_le32(csum_vlan);
/* Next descriptor */
@@ -856,7 +878,10 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,
ctl_stat |= FTGMAC100_TXDES0_LTS;
txdes->txdes0 = cpu_to_le32(ctl_stat);
txdes->txdes1 = 0;
- txdes->txdes3 = cpu_to_le32(map);
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT)
+ txdes->txdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_TXDES2_TXBUF_BADR_HI,
+ upper_32_bits(map)));
+ txdes->txdes3 = cpu_to_le32(lower_32_bits(map));
/* Next one */
pointer = ftgmac100_next_tx_pointer(priv, pointer);
@@ -931,7 +956,12 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv)
for (i = 0; i < priv->rx_q_entries; i++) {
struct ftgmac100_rxdes *rxdes = &priv->rxdes[i];
struct sk_buff *skb = priv->rx_skbs[i];
- dma_addr_t map = le32_to_cpu(rxdes->rxdes3);
+ dma_addr_t map;
+
+ map = le32_to_cpu(rxdes->rxdes3);
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT)
+ map |= (u64)FIELD_GET(FTGMAC100_RXDES2_RXBUF_BADR_HI,
+ le32_to_cpu(rxdes->rxdes2)) << 32;
if (!skb)
continue;
@@ -1050,7 +1080,12 @@ static void ftgmac100_init_rings(struct ftgmac100 *priv)
for (i = 0; i < priv->rx_q_entries; i++) {
rxdes = &priv->rxdes[i];
rxdes->rxdes0 = 0;
- rxdes->rxdes3 = cpu_to_le32(priv->rx_scratch_dma);
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT) {
+ u32 hi = upper_32_bits(priv->rx_scratch_dma);
+
+ rxdes->rxdes2 = cpu_to_le32(FIELD_PREP(FTGMAC100_RXDES2_RXBUF_BADR_HI, hi));
+ }
+ rxdes->rxdes3 = cpu_to_le32(lower_32_bits(priv->rx_scratch_dma));
}
/* Mark the end of the ring */
rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
@@ -2099,6 +2134,14 @@ static int ftgmac100_probe(struct platform_device *pdev)
netdev->hw_features &= ~(NETIF_F_HW_CSUM | NETIF_F_RXCSUM);
netdev->features |= netdev->hw_features;
+ if (priv->quirks & FTGMAC100_QUIRK_DMA_35BIT) {
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(35));
+ if (err) {
+ dev_err(&pdev->dev, "35-bit DMA enable failed\n");
+ goto err;
+ }
+ }
+
/* register network device */
err = register_netdev(netdev);
if (err) {
@@ -2151,7 +2194,8 @@ static const struct ftgmac100_match_data ftgmac100_match_data_ast2600 = {
static const struct ftgmac100_match_data ftgmac100_match_data_ast2700 = {
.mac_id = FTGMAC100_AST2700,
- .quirks = FTGMAC100_QUIRK_RMII_ENABLE,
+ .quirks = FTGMAC100_QUIRK_RMII_ENABLE |
+ FTGMAC100_QUIRK_DMA_35BIT,
};
static const struct ftgmac100_match_data ftgmac100_match_data_faraday = {
diff --git a/drivers/net/ethernet/faraday/ftgmac100.h b/drivers/net/ethernet/faraday/ftgmac100.h
index 8c35c895b146..0c244b1c0a35 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.h
+++ b/drivers/net/ethernet/faraday/ftgmac100.h
@@ -57,6 +57,9 @@
#define FTGMAC100_OFFSET_RX_RUNT 0xc0
#define FTGMAC100_OFFSET_RX_CRCER_FTL 0xc4
#define FTGMAC100_OFFSET_RX_COL_LOST 0xc8
+/* reserved 0xcc - 0x178 */
+#define FTGMAC100_OFFSET_TXR_BADDR_HIGH 0x17c
+#define FTGMAC100_OFFSET_RXR_BADDR_HIGH 0x18c
/*
* Interrupt status register & interrupt enable register
@@ -226,6 +229,7 @@ struct ftgmac100_txdes {
#define FTGMAC100_TXDES1_TX2FIC (1 << 30)
#define FTGMAC100_TXDES1_TXIC (1 << 31)
+#define FTGMAC100_TXDES2_TXBUF_BADR_HI GENMASK(18, 16)
/*
* Receive descriptor, aligned to 16 bytes
*/
@@ -272,4 +276,6 @@ struct ftgmac100_rxdes {
#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26)
#define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27)
+#define FTGMAC100_RXDES2_RXBUF_BADR_HI GENMASK(18, 16)
+
#endif /* __FTGMAC100_H */
--
2.34.1