* [PATCH net v2 01/12] net: au1000: recycle RX descriptors on allocation failure
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 02/12] net: au1000: clear all-multicast mode when restoring hash filtering Florian Fainelli
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
An skb allocation failure retries the same completed descriptor forever
in hard IRQ context. Return the buffer to DMA and advance the ring even
when the packet must be dropped.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 8682323d693f..cd25248f4e3a 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -788,7 +788,7 @@ static int au1000_rx(struct net_device *dev)
skb = netdev_alloc_skb(dev, frmlen + 2);
if (!skb) {
dev->stats.rx_dropped++;
- continue;
+ goto next;
}
skb_reserve(skb, 2); /* 16 byte IP header align */
skb_copy_to_linear_data(skb,
@@ -820,6 +820,7 @@ static int au1000_rx(struct net_device *dev)
pr_cont("\n");
}
}
+next:
prxd->buff_stat = lower_32_bits(pDB->dma_addr) | RX_DMA_ENABLE;
aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1);
wmb(); /* drain writebuffer */
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 02/12] net: au1000: clear all-multicast mode when restoring hash filtering
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 01/12] net: au1000: recycle RX descriptors on allocation failure Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 03/12] net: au1000: disconnect the PHY before freeing the MDIO bus Florian Fainelli
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
MAC_PASS_ALL_MULTI remains set after IFF_ALLMULTI is cleared or the
multicast list shrinks below the filter limit. Clear it when programming
the selective multicast hash so unwanted multicast traffic is filtered
again.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index cd25248f4e3a..58bc8e1b539d 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -1042,7 +1042,7 @@ static void au1000_multicast_list(struct net_device *dev)
(long *)mc_filter);
writel(mc_filter[1], &aup->mac->multi_hash_high);
writel(mc_filter[0], &aup->mac->multi_hash_low);
- reg &= ~MAC_PROMISCUOUS;
+ reg &= ~(MAC_PROMISCUOUS | MAC_PASS_ALL_MULTI);
reg |= MAC_HASH_MODE;
}
writel(reg, &aup->mac->control);
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 03/12] net: au1000: disconnect the PHY before freeing the MDIO bus
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 01/12] net: au1000: recycle RX descriptors on allocation failure Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 02/12] net: au1000: clear all-multicast mode when restoring hash filtering Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 04/12] net: au1000: report MDIO transaction timeouts Florian Fainelli
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
Balance phy_connect() on probe failure and removal. Otherwise PHY
interrupts, device references and the attachment to the freed netdev
survive teardown. Disconnect before unregistering the bus while its MDIO
callbacks and MAC registers remain usable.
PHY teardown can re-enable the MAC for MDIO even if the interface was
never opened. Reset the MAC after PHY and MDIO bus teardown, before
releasing descriptors and register mappings. Skip MAC control accesses
when mac_enabled is clear, since stopping an already clock-gated MAC
hangs MTX-1. Always clear the DMA descriptor control bits and TX state.
The teardown corrections were identified by Sashiko AI review and
hardware testing, with OpenAI Codex assisting implementation, validation
and commit-message consolidation. Previously validated on MTX-1 with
opened and never-opened removal, rebind and traffic; both removal cases
left the MAC enable register at zero. MIPS build and extracted-function
ASan/UBSan checks passed before this series was consolidated.
Fixes: 0638dec01e89 ("[PATCH] net: au1000_eth: PHY framework conversion")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 58bc8e1b539d..7063f9e5bc7c 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -584,14 +584,17 @@ static void au1000_reset_mac_unlocked(struct net_device *dev)
struct au1000_private *const aup = netdev_priv(dev);
int i;
- au1000_hard_stop(dev);
+ if (aup->mac_enabled) {
+ au1000_hard_stop(dev);
- writel(MAC_EN_CLOCK_ENABLE, aup->enable);
- wmb(); /* drain writebuffer */
- mdelay(2);
- writel(0, aup->enable);
- wmb(); /* drain writebuffer */
- mdelay(2);
+ writel(MAC_EN_CLOCK_ENABLE, aup->enable);
+ wmb(); /* drain writebuffer */
+ mdelay(2);
+ writel(0, aup->enable);
+ wmb(); /* drain writebuffer */
+ mdelay(2);
+ aup->mac_enabled = 0;
+ }
aup->tx_full = 0;
for (i = 0; i < NUM_RX_DMA; i++) {
@@ -603,8 +606,6 @@ static void au1000_reset_mac_unlocked(struct net_device *dev)
aup->tx_dma_ring[i]->buff_stat &= ~0xf;
}
- aup->mac_enabled = 0;
-
}
static void au1000_reset_mac(struct net_device *dev)
@@ -1287,6 +1288,8 @@ static int au1000_probe(struct platform_device *pdev)
return 0;
err_out:
+ if (dev->phydev)
+ phy_disconnect(dev->phydev);
if (aup->mii_bus)
mdiobus_unregister(aup->mii_bus);
@@ -1334,9 +1337,14 @@ static void au1000_remove(struct platform_device *pdev)
struct resource *base, *macen;
unregister_netdev(dev);
+ if (dev->phydev)
+ phy_disconnect(dev->phydev);
mdiobus_unregister(aup->mii_bus);
mdiobus_free(aup->mii_bus);
+ /* PHY teardown may have re-enabled the MAC for MDIO accesses. */
+ au1000_reset_mac(dev);
+
for (i = 0; i < NUM_RX_DMA; i++)
if (aup->rx_db_inuse[i])
au1000_ReleaseDB(aup, aup->rx_db_inuse[i]);
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 04/12] net: au1000: report MDIO transaction timeouts
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
` (2 preceding siblings ...)
2026-11-12 4:52 ` [PATCH net v2 03/12] net: au1000: disconnect the PHY before freeing the MDIO bus Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 05/12] net: au1000: serialize TX completion with packet submission Florian Fainelli
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
The MDIO write callback reports success even if the controller stays
busy and no write is issued. Propagate timeout errors and wait for write
completion so failure of the final transaction is reported to phylib as
well. Return ETIMEDOUT for read timeouts too.
Use readl_poll_timeout() for write completion with a 20 microsecond sleep
interval and a 20 millisecond timeout. The MDIO callback runs in sleepable
context, so avoid adding millisecond busy-waits for completion.
Fixes: 0638dec01e89 ("[PATCH] net: au1000_eth: PHY framework conversion")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 7063f9e5bc7c..6b2e216a8361 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -41,6 +41,7 @@
#include <linux/platform_device.h>
#include <linux/cpu.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <asm/mipsregs.h>
#include <asm/irq.h>
@@ -278,7 +279,7 @@ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
mdelay(1);
if (--timedout == 0) {
netdev_err(dev, "read_MII busy timeout!!\n");
- return -1;
+ return -ETIMEDOUT;
}
}
@@ -292,26 +293,27 @@ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
mdelay(1);
if (--timedout == 0) {
netdev_err(dev, "mdio_read busy timeout!!\n");
- return -1;
+ return -ETIMEDOUT;
}
}
return readl(mii_data_reg);
}
-static void au1000_mdio_write(struct net_device *dev, int phy_addr,
- int reg, u16 value)
+static int au1000_mdio_write(struct net_device *dev, int phy_addr,
+ int reg, u16 value)
{
struct au1000_private *aup = netdev_priv(dev);
u32 *const mii_control_reg = &aup->mac->mii_control;
u32 *const mii_data_reg = &aup->mac->mii_data;
u32 timedout = 20;
u32 mii_control;
+ int ret;
while (readl(mii_control_reg) & MAC_MII_BUSY) {
mdelay(1);
if (--timedout == 0) {
netdev_err(dev, "mdio_write busy timeout!!\n");
- return;
+ return -ETIMEDOUT;
}
}
@@ -320,6 +322,13 @@ static void au1000_mdio_write(struct net_device *dev, int phy_addr,
writel(value, mii_data_reg);
writel(mii_control, mii_control_reg);
+
+ ret = readl_poll_timeout(mii_control_reg, mii_control,
+ !(mii_control & MAC_MII_BUSY), 20, 20000);
+ if (ret)
+ netdev_err(dev, "mdio_write busy timeout!!\n");
+
+ return ret;
}
static int au1000_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
@@ -344,8 +353,7 @@ static int au1000_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
*/
au1000_enable_mac(dev, 0);
- au1000_mdio_write(dev, phy_addr, regnum, value);
- return 0;
+ return au1000_mdio_write(dev, phy_addr, regnum, value);
}
static int au1000_mdiobus_reset(struct mii_bus *bus)
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 05/12] net: au1000: serialize TX completion with packet submission
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
` (3 preceding siblings ...)
2026-11-12 4:52 ` [PATCH net v2 04/12] net: au1000: report MDIO transaction timeouts Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 06/12] net: au1000: assign a valid MAC address without platform data Florian Fainelli
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
TX completion runs in hard IRQ context while ndo_start_xmit updates the
same descriptors and ring state without locking. An interrupt between
netif_stop_queue() and setting tx_full can miss the wakeup and leave the
queue stopped until the watchdog runs. Use the existing IRQ-safe device
lock in both paths to serialize reclamation and queue state changes.
When submission reclaims a completed descriptor at tx_head, advance
tx_tail before reusing it so the interrupt handler does not wait on the
new packet while older completions remain pending. Consume the copied
skb after releasing the lock with dev_consume_skb_any(), which also
handles netpoll entry with hardware interrupts disabled.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 6b2e216a8361..5ce106d0389f 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -872,7 +872,9 @@ static void au1000_tx_ack(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
struct tx_dma *ptxd;
+ unsigned long flags;
+ spin_lock_irqsave(&aup->lock, flags);
ptxd = aup->tx_dma_ring[aup->tx_tail];
while (ptxd->buff_stat & TX_T_DONE) {
@@ -889,6 +891,8 @@ static void au1000_tx_ack(struct net_device *dev)
netif_wake_queue(dev);
}
}
+
+ spin_unlock_irqrestore(&aup->lock, flags);
}
/*
@@ -972,21 +976,25 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
u32 buff_stat;
struct db_dest *pDB;
int i;
+ unsigned long flags;
netif_dbg(aup, tx_queued, dev, "tx: aup %x len=%d, data=%p, head %d\n",
(unsigned)aup, skb->len,
skb->data, aup->tx_head);
+ spin_lock_irqsave(&aup->lock, flags);
ptxd = aup->tx_dma_ring[aup->tx_head];
buff_stat = ptxd->buff_stat;
if (buff_stat & TX_DMA_ENABLE) {
/* We've wrapped around and the transmitter is still busy */
netif_stop_queue(dev);
aup->tx_full = 1;
+ spin_unlock_irqrestore(&aup->lock, flags);
return NETDEV_TX_BUSY;
} else if (buff_stat & TX_T_DONE) {
au1000_update_tx_stats(dev, ptxd->status);
ptxd->len = 0;
+ aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1);
}
if (aup->tx_full) {
@@ -1009,8 +1017,9 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
ptxd->buff_stat = lower_32_bits(pDB->dma_addr) | TX_DMA_ENABLE;
wmb(); /* drain writebuffer */
- dev_kfree_skb(skb);
aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
+ spin_unlock_irqrestore(&aup->lock, flags);
+ dev_consume_skb_any(skb);
return NETDEV_TX_OK;
}
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 06/12] net: au1000: assign a valid MAC address without platform data
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
` (4 preceding siblings ...)
2026-11-12 4:52 ` [PATCH net v2 05/12] net: au1000: serialize TX completion with packet submission Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 07/12] net: au1000: fix buffer descriptor free list insertion Florian Fainelli
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
The supported no-platform-data path leaves dev_addr as all zeroes. The
device can register but eth_validate_addr() prevents it from opening.
Generate a random address just as for platform data containing an
invalid address.
Fixes: 7718f2c27dbd ("au1000_eth: use eth_hw_addr_random() instead of random_ether_addr()")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 5ce106d0389f..ea8f7787dd5d 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -1196,6 +1196,7 @@ static int au1000_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "no platform_data passed,"
" PHY search on MAC0\n");
aup->phy1_search_mac0 = 1;
+ eth_hw_addr_random(dev);
} else {
if (is_valid_ether_addr(pd->mac)) {
eth_hw_addr_set(dev, pd->mac);
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 07/12] net: au1000: fix buffer descriptor free list insertion
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
` (5 preceding siblings ...)
2026-11-12 4:52 ` [PATCH net v2 06/12] net: au1000: assign a valid MAC address without platform data Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 08/12] net: au1000: restore receive filtering before enabling RX Florian Fainelli
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
ReleaseDB links the old head to the returned descriptor and makes the
returned descriptor the new head without updating its stale next
pointer. This loses free descriptors and can create cycles. Link the
returned descriptor to the old head instead, matching GetFreeDB and the
list initialization.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index ea8f7787dd5d..f127c0184036 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -581,9 +581,7 @@ static struct db_dest *au1000_GetFreeDB(struct au1000_private *aup)
static void au1000_ReleaseDB(struct au1000_private *aup, struct db_dest *pDB)
{
- struct db_dest *pDBfree = aup->pDBfree;
- if (pDBfree)
- pDBfree->pnext = pDB;
+ pDB->pnext = aup->pDBfree;
aup->pDBfree = pDB;
}
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 08/12] net: au1000: restore receive filtering before enabling RX
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
` (6 preceding siblings ...)
2026-11-12 4:52 ` [PATCH net v2 07/12] net: au1000: fix buffer descriptor free list insertion Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 09/12] net: au1000: restore RX buffer addresses when restarting the MAC Florian Fainelli
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
MAC initialization overwrites the receive mode, dropping promiscuous and
multicast settings after a watchdog reset without notifying the network
stack. Restore the requested filtering before the control write that
enables RX, avoiding a window with the wrong filter.
Factor receive-mode programming into a helper shared by initialization
and the receive-mode callback. Hold the address-list lock before the
device lock through initialization so the filter snapshot stays current.
Protect callback control-register updates with the device lock as well.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index f127c0184036..67f4899c34a6 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -683,6 +683,8 @@ static const struct ethtool_ops au1000_ethtool_ops = {
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
+static u32 au1000_rx_mode(struct net_device *dev, u32 reg);
+
/*
* Initialize the interface.
*
@@ -704,6 +706,7 @@ static int au1000_init(struct net_device *dev)
/* bring the device out of reset */
au1000_enable_mac(dev, 1);
+ netif_addr_lock_bh(dev);
spin_lock_irqsave(&aup->lock, flags);
writel(0, &aup->mac->control);
@@ -736,11 +739,14 @@ static int au1000_init(struct net_device *dev)
control |= MAC_FULL_DUPLEX;
}
+ control = au1000_rx_mode(dev, control);
+
writel(control, &aup->mac->control);
writel(0x8100, &aup->mac->vlan1_tag); /* activate vlan support */
wmb(); /* drain writebuffer */
spin_unlock_irqrestore(&aup->lock, flags);
+ netif_addr_unlock_bh(dev);
return 0;
}
@@ -1034,13 +1040,12 @@ static void au1000_tx_timeout(struct net_device *dev, unsigned int txqueue)
netif_wake_queue(dev);
}
-static void au1000_multicast_list(struct net_device *dev)
+/* Caller holds the address-list lock and aup->lock. */
+static u32 au1000_rx_mode(struct net_device *dev, u32 reg)
{
struct au1000_private *aup = netdev_priv(dev);
- u32 reg;
netif_dbg(aup, drv, dev, "%s: flags=%x\n", __func__, dev->flags);
- reg = readl(&aup->mac->control);
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
reg |= MAC_PROMISCUOUS;
} else if ((dev->flags & IFF_ALLMULTI) ||
@@ -1061,7 +1066,19 @@ static void au1000_multicast_list(struct net_device *dev)
reg &= ~(MAC_PROMISCUOUS | MAC_PASS_ALL_MULTI);
reg |= MAC_HASH_MODE;
}
+ return reg;
+}
+
+static void au1000_multicast_list(struct net_device *dev)
+{
+ struct au1000_private *aup = netdev_priv(dev);
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&aup->lock, flags);
+ reg = au1000_rx_mode(dev, readl(&aup->mac->control));
writel(reg, &aup->mac->control);
+ spin_unlock_irqrestore(&aup->lock, flags);
}
static const struct net_device_ops au1000_netdev_ops = {
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 09/12] net: au1000: restore RX buffer addresses when restarting the MAC
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
` (7 preceding siblings ...)
2026-11-12 4:52 ` [PATCH net v2 08/12] net: au1000: restore receive filtering before enabling RX Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 10/12] net: phy: smsc: wait for LAN83C183 power-down recovery Florian Fainelli
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
The MAC DMA engine updates each receive descriptor's address as it
transfers data. Clearing the descriptor control bits during reset does
not restore the buffer's starting address.
au1000_init() only set RX_DMA_ENABLE on the address left in the
descriptor. After closing and reopening the interface, a receive could
therefore start partway through its buffer and overwrite memory beyond
the allocation.
Reload each RX descriptor from rx_db_inuse before enabling it, as the
receive completion path already does.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 67f4899c34a6..8b7a88ceb3c5 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -722,7 +722,8 @@ static int au1000_init(struct net_device *dev)
for (i = 0; i < NUM_RX_DMA; i++)
- aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE;
+ writel(lower_32_bits(aup->rx_db_inuse[i]->dma_addr) |
+ RX_DMA_ENABLE, &aup->rx_dma_ring[i]->buff_stat);
wmb(); /* drain writebuffer */
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 10/12] net: phy: smsc: wait for LAN83C183 power-down recovery
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
` (8 preceding siblings ...)
2026-11-12 4:52 ` [PATCH net v2 09/12] net: au1000: restore RX buffer addresses when restarting the MAC Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 11/12] net: au1000: keep the MAC stopped until the PHY link is ready Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 12/12] net: au1000: reject frames larger than the TX bounce buffer Florian Fainelli
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
The LAN83C183 uses the generic PHY driver, which returns immediately
after clearing BMCR_PDOWN. Section 1.11 of the datasheet allows 500 ms
before normal operation is restored. Starting the Au1000 MAC before the
MII clocks recover can hang the MTX-1 when reopening its interface.
Add a LAN83C183 driver entry and resume callback. Wait for recovery only
when BMCR_PDOWN was actually cleared, and propagate MDIO errors without
waiting. Resuming an already awake PHY does not incur the delay.
Fixes: be9dad1f9f26 ("net: phy: suspend phydev when going to HALTED")
Link: https://pdf.dzsc.com/LAN/LAN83C183.pdf#page=44
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/phy/Kconfig | 2 +-
drivers/net/phy/smsc.c | 26 ++++++++++++++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 30e9d22c8d1a..10466b2574eb 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -421,7 +421,7 @@ config SMSC_PHY
tristate "SMSC PHYs"
select CRC16
help
- Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
+ Currently supports the LAN83C183, LAN83C185, LAN8187 and LAN8700 PHYs
config STE10XP
tristate "STMicroelectronics STe10Xp PHYs"
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 48487149c225..c3b51afd4b1e 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -13,6 +13,7 @@
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
@@ -684,8 +685,32 @@ int smsc_phy_probe(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(smsc_phy_probe);
+static int lan83c183_resume(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_modify_changed(phydev, MII_BMCR, BMCR_PDOWN, 0);
+ if (ret < 0)
+ return ret;
+
+ /* The PHY needs up to 500 ms to restore operation after power-down. */
+ if (ret)
+ msleep(500);
+
+ return 0;
+}
+
static struct phy_driver smsc_phy_driver[] = {
{
+ .phy_id = 0x0016f840,
+ .phy_id_mask = 0xfffffff0,
+ .name = "SMSC LAN83C183",
+
+ .get_features = genphy_read_abilities,
+ .suspend = genphy_suspend,
+ .resume = lan83c183_resume,
+ .set_loopback = genphy_loopback,
+}, {
.phy_id = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN83C185",
@@ -887,6 +912,7 @@ MODULE_AUTHOR("Herbert Valerio Riedel");
MODULE_LICENSE("GPL");
static const struct mdio_device_id __maybe_unused smsc_tbl[] = {
+ { 0x0016f840, 0xfffffff0 },
{ 0x0007c0a0, 0xfffffff0 },
{ 0x0007c0b0, 0xfffffff0 },
{ 0x0007c0c0, 0xfffffff0 },
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 11/12] net: au1000: keep the MAC stopped until the PHY link is ready
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
` (9 preceding siblings ...)
2026-11-12 4:52 ` [PATCH net v2 10/12] net: phy: smsc: wait for LAN83C183 power-down recovery Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
2026-11-12 4:52 ` [PATCH net v2 12/12] net: au1000: reject frames larger than the TX bounce buffer Florian Fainelli
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
phy_stop() powers down the PHY when the interface is closed. The driver
leaves MAC receive/transmit enabled on link-down and enables them during
initialization before the PHY resumes. MTX-1 can hang when the MAC runs
while its MII clocks are absent or still recovering.
Stop the MAC on link-down before phylib suspends the PHY. On open, clear
the driver's acknowledged link cache and synchronously resume the PHY
to restore its MII clocks and honor its recovery delay. Initialize the
MAC before phy_start() so the PHY worker cannot access MDIO or enable
traffic during setup. Leave RX/TX stopped until a link-up callback
configures duplex and enables traffic.
Use the acknowledged link and duplex cache under the device lock during
initialization, retaining it for watchdog recovery. Keep the reset-time
hard stop for paths without a preceding link-down callback. On resume
failure reset the MAC and release the IRQ; if initialization fails,
suspend the PHY again before cleanup.
Fixes: be9dad1f9f26 ("net: phy: suspend phydev when going to HALTED")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 39 ++++++++++++++++++++++-----
1 file changed, 32 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 8b7a88ceb3c5..d60430a3795e 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -456,7 +456,8 @@ au1000_adjust_link(struct net_device *dev)
/* link state changed */
if (!phydev->link) {
- /* link went down */
+ /* Stop the MAC before the PHY can remove its clocks. */
+ au1000_hard_stop(dev);
aup->old_speed = 0;
aup->old_duplex = -1;
}
@@ -691,8 +692,8 @@ static u32 au1000_rx_mode(struct net_device *dev, u32 reg);
* When the device powers up, the clocks are disabled and the
* mac is in reset state. When the interface is closed, we
* do the same -- reset the device and disable the clocks to
- * conserve power. Thus, whenever au1000_init() is called,
- * the device should already be in reset state.
+ * conserve power. The device must be stopped before au1000_init() is
+ * called, but may be out of reset for MDIO accesses while resuming the PHY.
*/
static int au1000_init(struct net_device *dev)
{
@@ -727,12 +728,12 @@ static int au1000_init(struct net_device *dev)
wmb(); /* drain writebuffer */
- control = MAC_RX_ENABLE | MAC_TX_ENABLE;
+ control = 0;
#ifndef CONFIG_CPU_LITTLE_ENDIAN
control |= MAC_BIG_ENDIAN;
#endif
if (dev->phydev) {
- if (dev->phydev->link && (DUPLEX_FULL == dev->phydev->duplex))
+ if (aup->old_link && aup->old_duplex == DUPLEX_FULL)
control |= MAC_FULL_DUPLEX;
else
control |= MAC_DISABLE_RX_OWN;
@@ -742,6 +743,10 @@ static int au1000_init(struct net_device *dev)
control = au1000_rx_mode(dev, control);
+ /* Only use link state acknowledged by au1000_adjust_link(). */
+ if (!dev->phydev || aup->old_link)
+ control |= MAC_RX_ENABLE | MAC_TX_ENABLE;
+
writel(control, &aup->mac->control);
writel(0x8100, &aup->mac->vlan1_tag); /* activate vlan support */
wmb(); /* drain writebuffer */
@@ -916,6 +921,7 @@ static irqreturn_t au1000_interrupt(int irq, void *dev_id)
static int au1000_open(struct net_device *dev)
{
+ unsigned long flags;
int retval;
struct au1000_private *aup = netdev_priv(dev);
@@ -928,11 +934,25 @@ static int au1000_open(struct net_device *dev)
return retval;
}
+ spin_lock_irqsave(&aup->lock, flags);
+ aup->old_link = 0;
+ aup->old_speed = 0;
+ aup->old_duplex = -1;
+ spin_unlock_irqrestore(&aup->lock, flags);
+
+ /* Restore the MII clocks without starting the PHY state machine. */
+ if (dev->phydev) {
+ retval = phy_resume(dev->phydev);
+ if (retval)
+ goto err_reset;
+ }
+
retval = au1000_init(dev);
if (retval) {
netdev_err(dev, "error in au1000_init\n");
- free_irq(dev->irq, dev);
- return retval;
+ if (dev->phydev)
+ phy_suspend(dev->phydev);
+ goto err_reset;
}
if (dev->phydev)
@@ -943,6 +963,11 @@ static int au1000_open(struct net_device *dev)
netif_dbg(aup, drv, dev, "open: Initialization done.\n");
return 0;
+
+err_reset:
+ au1000_reset_mac(dev);
+ free_irq(dev->irq, dev);
+ return retval;
}
static int au1000_close(struct net_device *dev)
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH net v2 12/12] net: au1000: reject frames larger than the TX bounce buffer
2026-11-12 4:52 [PATCH net v2 00/12] net: au1000: Bug fixes Florian Fainelli
` (10 preceding siblings ...)
2026-11-12 4:52 ` [PATCH net v2 11/12] net: au1000: keep the MAC stopped until the PHY link is ready Florian Fainelli
@ 2026-11-12 4:52 ` Florian Fainelli
11 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2026-11-12 4:52 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Heiner Kallweit, Russell King,
Jijie Shao, Simon Horman, Runyu Xiao, David Yang,
Herbert Valerio Riedel, Jeff Garzik, Danny Kukawka,
Mugunthan V N, Sebastian Hesselbarth, open list, Manuel Lauss
au1000_tx() copies skb->len bytes into a MAX_BUF_SIZE coherent buffer
without checking the length. Oversized non-GSO packets can reach this
path through AF_PACKET with PACKET_VNET_HDR and PACKET_TX_RING, whose
MTU checks are skipped when a virtio header is present. The copy can
corrupt neighboring DMA buffers or run beyond the coherent allocation.
Drop oversized packets before touching the ring or copying any data,
and account them in tx_dropped. Use an IRQ-safe skb free for netpoll.
Identified by Sashiko AI review; implementation and validation assisted
by OpenAI Codex. An extracted-function harness passed ASan/UBSan checks
for 2049- and 4096-byte drops and a 2048-byte accepted frame, as well as
TX ring regression cases. MIPS driver compilation and checkpatch passed.
The complete AF_PACKET trigger and hardware operation were not tested.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/ethernet/amd/au1000_eth.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index d60430a3795e..d8855ccf87aa 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -1008,6 +1008,12 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
int i;
unsigned long flags;
+ if (unlikely(skb->len > MAX_BUF_SIZE)) {
+ dev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
netif_dbg(aup, tx_queued, dev, "tx: aup %x len=%d, data=%p, head %d\n",
(unsigned)aup, skb->len,
skb->data, aup->tx_head);
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread