diff options
author | Dongdong Deng <dongdong.deng@windriver.com> | 2009-08-23 22:49:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-23 22:51:03 -0400 |
commit | 4871953c0ef2cafeb37bbe186d9d13dcb24fc2c5 (patch) | |
tree | e272c3a7aeb61a40f3ec807e2b4c8001ed837a7b /drivers/net | |
parent | 79b1bee888d43b14cf0c08fb8e5aa6cb161e48f8 (diff) |
drivers/net: fixed drivers that support netpoll use ndo_start_xmit()
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>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/fec_mpc52xx.c | 5 | ||||
-rw-r--r-- | drivers/net/ixp2000/ixpdev.c | 5 | ||||
-rw-r--r-- | drivers/net/macb.c | 7 | ||||
-rw-r--r-- | drivers/net/mlx4/en_tx.c | 5 |
4 files changed, 13 insertions, 9 deletions
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index cc786333d95c..c40113f58963 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c | |||
@@ -309,6 +309,7 @@ static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
309 | { | 309 | { |
310 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | 310 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); |
311 | struct bcom_fec_bd *bd; | 311 | struct bcom_fec_bd *bd; |
312 | unsigned long flags; | ||
312 | 313 | ||
313 | if (bcom_queue_full(priv->tx_dmatsk)) { | 314 | if (bcom_queue_full(priv->tx_dmatsk)) { |
314 | if (net_ratelimit()) | 315 | if (net_ratelimit()) |
@@ -316,7 +317,7 @@ static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
316 | return NETDEV_TX_BUSY; | 317 | return NETDEV_TX_BUSY; |
317 | } | 318 | } |
318 | 319 | ||
319 | spin_lock_irq(&priv->lock); | 320 | spin_lock_irqsave(&priv->lock, flags); |
320 | dev->trans_start = jiffies; | 321 | dev->trans_start = jiffies; |
321 | 322 | ||
322 | bd = (struct bcom_fec_bd *) | 323 | bd = (struct bcom_fec_bd *) |
@@ -332,7 +333,7 @@ static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
332 | netif_stop_queue(dev); | 333 | netif_stop_queue(dev); |
333 | } | 334 | } |
334 | 335 | ||
335 | spin_unlock_irq(&priv->lock); | 336 | spin_unlock_irqrestore(&priv->lock, flags); |
336 | 337 | ||
337 | return NETDEV_TX_OK; | 338 | return NETDEV_TX_OK; |
338 | } | 339 | } |
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 2a0174b62e96..92fb8235c766 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c | |||
@@ -41,6 +41,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
41 | struct ixpdev_priv *ip = netdev_priv(dev); | 41 | struct ixpdev_priv *ip = netdev_priv(dev); |
42 | struct ixpdev_tx_desc *desc; | 42 | struct ixpdev_tx_desc *desc; |
43 | int entry; | 43 | int entry; |
44 | unsigned long flags; | ||
44 | 45 | ||
45 | if (unlikely(skb->len > PAGE_SIZE)) { | 46 | if (unlikely(skb->len > PAGE_SIZE)) { |
46 | /* @@@ Count drops. */ | 47 | /* @@@ Count drops. */ |
@@ -63,11 +64,11 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
63 | 64 | ||
64 | dev->trans_start = jiffies; | 65 | dev->trans_start = jiffies; |
65 | 66 | ||
66 | local_irq_disable(); | 67 | local_irq_save(flags); |
67 | ip->tx_queue_entries++; | 68 | ip->tx_queue_entries++; |
68 | if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN) | 69 | if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN) |
69 | netif_stop_queue(dev); | 70 | netif_stop_queue(dev); |
70 | local_irq_enable(); | 71 | local_irq_restore(flags); |
71 | 72 | ||
72 | return 0; | 73 | return 0; |
73 | } | 74 | } |
diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 5b5c25368d1e..e3601cf3f931 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c | |||
@@ -620,6 +620,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
620 | dma_addr_t mapping; | 620 | dma_addr_t mapping; |
621 | unsigned int len, entry; | 621 | unsigned int len, entry; |
622 | u32 ctrl; | 622 | u32 ctrl; |
623 | unsigned long flags; | ||
623 | 624 | ||
624 | #ifdef DEBUG | 625 | #ifdef DEBUG |
625 | int i; | 626 | int i; |
@@ -635,12 +636,12 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
635 | #endif | 636 | #endif |
636 | 637 | ||
637 | len = skb->len; | 638 | len = skb->len; |
638 | spin_lock_irq(&bp->lock); | 639 | spin_lock_irqsave(&bp->lock, flags); |
639 | 640 | ||
640 | /* This is a hard error, log it. */ | 641 | /* This is a hard error, log it. */ |
641 | if (TX_BUFFS_AVAIL(bp) < 1) { | 642 | if (TX_BUFFS_AVAIL(bp) < 1) { |
642 | netif_stop_queue(dev); | 643 | netif_stop_queue(dev); |
643 | spin_unlock_irq(&bp->lock); | 644 | spin_unlock_irqrestore(&bp->lock, flags); |
644 | dev_err(&bp->pdev->dev, | 645 | dev_err(&bp->pdev->dev, |
645 | "BUG! Tx Ring full when queue awake!\n"); | 646 | "BUG! Tx Ring full when queue awake!\n"); |
646 | dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n", | 647 | dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n", |
@@ -674,7 +675,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
674 | if (TX_BUFFS_AVAIL(bp) < 1) | 675 | if (TX_BUFFS_AVAIL(bp) < 1) |
675 | netif_stop_queue(dev); | 676 | netif_stop_queue(dev); |
676 | 677 | ||
677 | spin_unlock_irq(&bp->lock); | 678 | spin_unlock_irqrestore(&bp->lock, flags); |
678 | 679 | ||
679 | dev->trans_start = jiffies; | 680 | dev->trans_start = jiffies; |
680 | 681 | ||
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 5a88b3f57693..62208401c4df 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c | |||
@@ -437,6 +437,7 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind) | |||
437 | { | 437 | { |
438 | struct mlx4_en_cq *cq = &priv->tx_cq[tx_ind]; | 438 | struct mlx4_en_cq *cq = &priv->tx_cq[tx_ind]; |
439 | struct mlx4_en_tx_ring *ring = &priv->tx_ring[tx_ind]; | 439 | struct mlx4_en_tx_ring *ring = &priv->tx_ring[tx_ind]; |
440 | unsigned long flags; | ||
440 | 441 | ||
441 | /* If we don't have a pending timer, set one up to catch our recent | 442 | /* If we don't have a pending timer, set one up to catch our recent |
442 | post in case the interface becomes idle */ | 443 | post in case the interface becomes idle */ |
@@ -445,9 +446,9 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind) | |||
445 | 446 | ||
446 | /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */ | 447 | /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */ |
447 | if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0) | 448 | if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0) |
448 | if (spin_trylock_irq(&ring->comp_lock)) { | 449 | if (spin_trylock_irqsave(&ring->comp_lock, flags)) { |
449 | mlx4_en_process_tx_cq(priv->dev, cq); | 450 | mlx4_en_process_tx_cq(priv->dev, cq); |
450 | spin_unlock_irq(&ring->comp_lock); | 451 | spin_unlock_irqrestore(&ring->comp_lock, flags); |
451 | } | 452 | } |
452 | } | 453 | } |
453 | 454 | ||