Skip to content

Commit 01b2c76

Browse files
nikita-youshgregkh
authored andcommitted
net: renesas: rswitch: handle stop vs interrupt race
[ Upstream commit 3dd002f ] Currently the stop routine of rswitch driver does not immediately prevent hardware from continuing to update descriptors and requesting interrupts. It can happen that when rswitch_stop() executes the masking of interrupts from the queues of the port being closed, napi poll for that port is already scheduled or running on a different CPU. When execution of this napi poll completes, it will unmask the interrupts. And unmasked interrupt can fire after rswitch_stop() returns from napi_disable() call. Then, the handler won't mask it, because napi_schedule_prep() will return false, and interrupt storm will happen. This can't be fixed by making rswitch_stop() call napi_disable() before masking interrupts. In this case, the interrupt storm will happen if interrupt fires between napi_disable() and masking. Fix this by checking for priv->opened_ports bit when unmasking interrupts after napi poll. For that to be consistent, move priv->opened_ports changes into spinlock-protected areas, and reorder other operations in rswitch_open() and rswitch_stop() accordingly. Signed-off-by: Nikita Yushchenko <[email protected]> Reviewed-by: Yoshihiro Shimoda <[email protected]> Fixes: 3590918 ("net: ethernet: renesas: Add support for "Ethernet Switch"") Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent bf8c675 commit 01b2c76

File tree

1 file changed

+18
-15
lines changed

1 file changed

+18
-15
lines changed

drivers/net/ethernet/renesas/rswitch.c

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -839,8 +839,10 @@ static int rswitch_poll(struct napi_struct *napi, int budget)
839839

840840
if (napi_complete_done(napi, budget - quota)) {
841841
spin_lock_irqsave(&priv->lock, flags);
842-
rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true);
843-
rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true);
842+
if (test_bit(rdev->port, priv->opened_ports)) {
843+
rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true);
844+
rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true);
845+
}
844846
spin_unlock_irqrestore(&priv->lock, flags);
845847
}
846848

@@ -1467,20 +1469,20 @@ static int rswitch_open(struct net_device *ndev)
14671469
struct rswitch_device *rdev = netdev_priv(ndev);
14681470
unsigned long flags;
14691471

1470-
phy_start(ndev->phydev);
1472+
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
1473+
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE);
14711474

14721475
napi_enable(&rdev->napi);
1473-
netif_start_queue(ndev);
14741476

14751477
spin_lock_irqsave(&rdev->priv->lock, flags);
1478+
bitmap_set(rdev->priv->opened_ports, rdev->port, 1);
14761479
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, true);
14771480
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, true);
14781481
spin_unlock_irqrestore(&rdev->priv->lock, flags);
14791482

1480-
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
1481-
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE);
1483+
phy_start(ndev->phydev);
14821484

1483-
bitmap_set(rdev->priv->opened_ports, rdev->port, 1);
1485+
netif_start_queue(ndev);
14841486

14851487
return 0;
14861488
};
@@ -1492,7 +1494,16 @@ static int rswitch_stop(struct net_device *ndev)
14921494
unsigned long flags;
14931495

14941496
netif_tx_stop_all_queues(ndev);
1497+
1498+
phy_stop(ndev->phydev);
1499+
1500+
spin_lock_irqsave(&rdev->priv->lock, flags);
1501+
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false);
1502+
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false);
14951503
bitmap_clear(rdev->priv->opened_ports, rdev->port, 1);
1504+
spin_unlock_irqrestore(&rdev->priv->lock, flags);
1505+
1506+
napi_disable(&rdev->napi);
14961507

14971508
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
14981509
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDID);
@@ -1505,14 +1516,6 @@ static int rswitch_stop(struct net_device *ndev)
15051516
kfree(ts_info);
15061517
}
15071518

1508-
spin_lock_irqsave(&rdev->priv->lock, flags);
1509-
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false);
1510-
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false);
1511-
spin_unlock_irqrestore(&rdev->priv->lock, flags);
1512-
1513-
phy_stop(ndev->phydev);
1514-
napi_disable(&rdev->napi);
1515-
15161519
return 0;
15171520
};
15181521

0 commit comments

Comments
 (0)