Skip to content

Commit 283e38d

Browse files
bwh-ctdavem330
authored andcommitted
sh_eth: Fix serialisation of interrupt disable with interrupt & NAPI handlers
In order to stop the RX path accessing the RX ring while it's being stopped or resized, we clear the interrupt mask (EESIPR) and then call free_irq() or synchronise_irq(). This is insufficient because the interrupt handler or NAPI poller may set EESIPR again after we clear it. Also, in sh_eth_set_ringparam() we currently don't disable NAPI polling at all. I could easily trigger a crash by running the loop: while ethtool -G eth0 rx 128 && ethtool -G eth0 rx 64; do echo -n .; done and 'ping -f' toward the sh_eth port from another machine. To fix this: - Add a software flag (irq_enabled) to signal whether interrupts should be enabled - In the interrupt handler, if the flag is clear then clear EESIPR and return - In the NAPI poller, if the flag is clear then don't set EESIPR - Set the flag before enabling interrupts in sh_eth_dev_init() and sh_eth_set_ringparam() - Clear the flag and serialise with the interrupt and NAPI handlers before clearing EESIPR in sh_eth_close() and sh_eth_set_ringparam() After this, I could run the loop for 100,000 iterations successfully. Signed-off-by: Ben Hutchings <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 084236d commit 283e38d

File tree

2 files changed

+31
-9
lines changed

2 files changed

+31
-9
lines changed

drivers/net/ethernet/renesas/sh_eth.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,8 +1316,10 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)
13161316
RFLR);
13171317

13181318
sh_eth_write(ndev, sh_eth_read(ndev, EESR), EESR);
1319-
if (start)
1319+
if (start) {
1320+
mdp->irq_enabled = true;
13201321
sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
1322+
}
13211323

13221324
/* PAUSE Prohibition */
13231325
val = (sh_eth_read(ndev, ECMR) & ECMR_DM) |
@@ -1653,7 +1655,12 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
16531655
if (intr_status & (EESR_RX_CHECK | cd->tx_check | cd->eesr_err_check))
16541656
ret = IRQ_HANDLED;
16551657
else
1656-
goto other_irq;
1658+
goto out;
1659+
1660+
if (!likely(mdp->irq_enabled)) {
1661+
sh_eth_write(ndev, 0, EESIPR);
1662+
goto out;
1663+
}
16571664

16581665
if (intr_status & EESR_RX_CHECK) {
16591666
if (napi_schedule_prep(&mdp->napi)) {
@@ -1684,7 +1691,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
16841691
sh_eth_error(ndev, intr_status);
16851692
}
16861693

1687-
other_irq:
1694+
out:
16881695
spin_unlock(&mdp->lock);
16891696

16901697
return ret;
@@ -1712,7 +1719,8 @@ static int sh_eth_poll(struct napi_struct *napi, int budget)
17121719
napi_complete(napi);
17131720

17141721
/* Reenable Rx interrupts */
1715-
sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
1722+
if (mdp->irq_enabled)
1723+
sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
17161724
out:
17171725
return budget - quota;
17181726
}
@@ -1970,12 +1978,20 @@ static int sh_eth_set_ringparam(struct net_device *ndev,
19701978
if (netif_running(ndev)) {
19711979
netif_device_detach(ndev);
19721980
netif_tx_disable(ndev);
1973-
/* Disable interrupts by clearing the interrupt mask. */
1981+
1982+
/* Serialise with the interrupt handler and NAPI, then
1983+
* disable interrupts. We have to clear the
1984+
* irq_enabled flag first to ensure that interrupts
1985+
* won't be re-enabled.
1986+
*/
1987+
mdp->irq_enabled = false;
1988+
synchronize_irq(ndev->irq);
1989+
napi_synchronize(&mdp->napi);
19741990
sh_eth_write(ndev, 0x0000, EESIPR);
1991+
19751992
/* Stop the chip's Tx and Rx processes. */
19761993
sh_eth_write(ndev, 0, EDTRR);
19771994
sh_eth_write(ndev, 0, EDRRR);
1978-
synchronize_irq(ndev->irq);
19791995

19801996
/* Free all the skbuffs in the Rx queue. */
19811997
sh_eth_ring_free(ndev);
@@ -2001,6 +2017,7 @@ static int sh_eth_set_ringparam(struct net_device *ndev,
20012017
return ret;
20022018
}
20032019

2020+
mdp->irq_enabled = true;
20042021
sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
20052022
/* Setting the Rx mode will start the Rx process. */
20062023
sh_eth_write(ndev, EDRRR_R, EDRRR);
@@ -2184,7 +2201,13 @@ static int sh_eth_close(struct net_device *ndev)
21842201

21852202
netif_stop_queue(ndev);
21862203

2187-
/* Disable interrupts by clearing the interrupt mask. */
2204+
/* Serialise with the interrupt handler and NAPI, then disable
2205+
* interrupts. We have to clear the irq_enabled flag first to
2206+
* ensure that interrupts won't be re-enabled.
2207+
*/
2208+
mdp->irq_enabled = false;
2209+
synchronize_irq(ndev->irq);
2210+
napi_disable(&mdp->napi);
21882211
sh_eth_write(ndev, 0x0000, EESIPR);
21892212

21902213
/* Stop the chip's Tx and Rx processes. */
@@ -2201,8 +2224,6 @@ static int sh_eth_close(struct net_device *ndev)
22012224

22022225
free_irq(ndev->irq, ndev);
22032226

2204-
napi_disable(&mdp->napi);
2205-
22062227
/* Free all the skbuffs in the Rx queue. */
22072228
sh_eth_ring_free(ndev);
22082229

drivers/net/ethernet/renesas/sh_eth.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,7 @@ struct sh_eth_private {
513513
u32 rx_buf_sz; /* Based on MTU+slack. */
514514
int edmac_endian;
515515
struct napi_struct napi;
516+
bool irq_enabled;
516517
/* MII transceiver section. */
517518
u32 phy_id; /* PHY ID */
518519
struct mii_bus *mii_bus; /* MDIO bus control */

0 commit comments

Comments
 (0)