Skip to content

Commit

Permalink
drivers/net: fixed drivers that support netpoll use ndo_start_xmit()
Browse files Browse the repository at this point in the history
The NETPOLL API requires that interrupts remain disabled in
netpoll_send_skb(). The use of "A functions set" in the NETPOLL API
callbacks causes the interrupts to get enabled and can lead to kernel
instability.

The solution is to use "B functions set" to prevent the irqs from
getting enabled while in netpoll_send_skb().

A functions set:
local_irq_disable()/local_irq_enable()
spin_lock_irq()/spin_unlock_irq()
spin_trylock_irq()/spin_unlock_irq()

B functions set:
local_irq_save()/local_irq_restore()
spin_lock_irqsave()/spin_unlock_irqrestore()
spin_trylock_irqsave()/spin_unlock_irqrestore()

Signed-off-by: Dongdong Deng <dongdong.deng@windriver.com>
Acked-by: Matt Mackall <mpm@selenic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Dongdong Deng authored and David S. Miller committed Aug 24, 2009
1 parent 79b1bee commit 4871953
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 9 deletions.
5 changes: 3 additions & 2 deletions drivers/net/fec_mpc52xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,14 +309,15 @@ static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
struct bcom_fec_bd *bd;
unsigned long flags;

if (bcom_queue_full(priv->tx_dmatsk)) {
if (net_ratelimit())
dev_err(&dev->dev, "transmit queue overrun\n");
return NETDEV_TX_BUSY;
}

spin_lock_irq(&priv->lock);
spin_lock_irqsave(&priv->lock, flags);
dev->trans_start = jiffies;

bd = (struct bcom_fec_bd *)
Expand All @@ -332,7 +333,7 @@ static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}

spin_unlock_irq(&priv->lock);
spin_unlock_irqrestore(&priv->lock, flags);

return NETDEV_TX_OK;
}
Expand Down
5 changes: 3 additions & 2 deletions drivers/net/ixp2000/ixpdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
struct ixpdev_priv *ip = netdev_priv(dev);
struct ixpdev_tx_desc *desc;
int entry;
unsigned long flags;

if (unlikely(skb->len > PAGE_SIZE)) {
/* @@@ Count drops. */
Expand All @@ -63,11 +64,11 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)

dev->trans_start = jiffies;

local_irq_disable();
local_irq_save(flags);
ip->tx_queue_entries++;
if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN)
netif_stop_queue(dev);
local_irq_enable();
local_irq_restore(flags);

return 0;
}
Expand Down
7 changes: 4 additions & 3 deletions drivers/net/macb.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
dma_addr_t mapping;
unsigned int len, entry;
u32 ctrl;
unsigned long flags;

#ifdef DEBUG
int i;
Expand All @@ -635,12 +636,12 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
#endif

len = skb->len;
spin_lock_irq(&bp->lock);
spin_lock_irqsave(&bp->lock, flags);

/* This is a hard error, log it. */
if (TX_BUFFS_AVAIL(bp) < 1) {
netif_stop_queue(dev);
spin_unlock_irq(&bp->lock);
spin_unlock_irqrestore(&bp->lock, flags);
dev_err(&bp->pdev->dev,
"BUG! Tx Ring full when queue awake!\n");
dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n",
Expand Down Expand Up @@ -674,7 +675,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL(bp) < 1)
netif_stop_queue(dev);

spin_unlock_irq(&bp->lock);
spin_unlock_irqrestore(&bp->lock, flags);

dev->trans_start = jiffies;

Expand Down
5 changes: 3 additions & 2 deletions drivers/net/mlx4/en_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind)
{
struct mlx4_en_cq *cq = &priv->tx_cq[tx_ind];
struct mlx4_en_tx_ring *ring = &priv->tx_ring[tx_ind];
unsigned long flags;

/* If we don't have a pending timer, set one up to catch our recent
post in case the interface becomes idle */
Expand All @@ -445,9 +446,9 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind)

/* Poll the CQ every mlx4_en_TX_MODER_POLL packets */
if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0)
if (spin_trylock_irq(&ring->comp_lock)) {
if (spin_trylock_irqsave(&ring->comp_lock, flags)) {
mlx4_en_process_tx_cq(priv->dev, cq);
spin_unlock_irq(&ring->comp_lock);
spin_unlock_irqrestore(&ring->comp_lock, flags);
}
}

Expand Down

0 comments on commit 4871953

Please sign in to comment.