Skip to content

Commit 3dd002f

Browse files
nikita-youshkuba-moo
authored andcommitted
net: renesas: rswitch: handle stop vs interrupt race
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 <nikita.yoush@cogentembedded.com> Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Fixes: 3590918 ("net: ethernet: renesas: Add support for "Ethernet Switch"") Link: https://patch.msgid.link/20241209113204.175015-1-nikita.yoush@cogentembedded.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 93763e6 commit 3dd002f

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
@@ -908,8 +908,10 @@ static int rswitch_poll(struct napi_struct *napi, int budget)
908908

909909
if (napi_complete_done(napi, budget - quota)) {
910910
spin_lock_irqsave(&priv->lock, flags);
911-
rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true);
912-
rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true);
911+
if (test_bit(rdev->port, priv->opened_ports)) {
912+
rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true);
913+
rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true);
914+
}
913915
spin_unlock_irqrestore(&priv->lock, flags);
914916
}
915917

@@ -1538,20 +1540,20 @@ static int rswitch_open(struct net_device *ndev)
15381540
struct rswitch_device *rdev = netdev_priv(ndev);
15391541
unsigned long flags;
15401542

1541-
phy_start(ndev->phydev);
1543+
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
1544+
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE);
15421545

15431546
napi_enable(&rdev->napi);
1544-
netif_start_queue(ndev);
15451547

15461548
spin_lock_irqsave(&rdev->priv->lock, flags);
1549+
bitmap_set(rdev->priv->opened_ports, rdev->port, 1);
15471550
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, true);
15481551
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, true);
15491552
spin_unlock_irqrestore(&rdev->priv->lock, flags);
15501553

1551-
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
1552-
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE);
1554+
phy_start(ndev->phydev);
15531555

1554-
bitmap_set(rdev->priv->opened_ports, rdev->port, 1);
1556+
netif_start_queue(ndev);
15551557

15561558
return 0;
15571559
};
@@ -1563,7 +1565,16 @@ static int rswitch_stop(struct net_device *ndev)
15631565
unsigned long flags;
15641566

15651567
netif_tx_stop_all_queues(ndev);
1568+
1569+
phy_stop(ndev->phydev);
1570+
1571+
spin_lock_irqsave(&rdev->priv->lock, flags);
1572+
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false);
1573+
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false);
15661574
bitmap_clear(rdev->priv->opened_ports, rdev->port, 1);
1575+
spin_unlock_irqrestore(&rdev->priv->lock, flags);
1576+
1577+
napi_disable(&rdev->napi);
15671578

15681579
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
15691580
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDID);
@@ -1576,14 +1587,6 @@ static int rswitch_stop(struct net_device *ndev)
15761587
kfree(ts_info);
15771588
}
15781589

1579-
spin_lock_irqsave(&rdev->priv->lock, flags);
1580-
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false);
1581-
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false);
1582-
spin_unlock_irqrestore(&rdev->priv->lock, flags);
1583-
1584-
phy_stop(ndev->phydev);
1585-
napi_disable(&rdev->napi);
1586-
15871590
return 0;
15881591
};
15891592

0 commit comments

Comments
 (0)