diff options
author | Dongdong Deng <dongdong.deng@windriver.com> | 2009-08-13 15:12:31 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-14 19:41:16 -0400 |
commit | 22580f894ac190c46beebb5c3172e450a2318f79 (patch) | |
tree | 01f88df9a5bc27170ef7ca944ba40af578476d72 /drivers/net/ucc_geth.c | |
parent | 0527a1a8440a20b3d0fd1d0c9e75a6f38a9d5315 (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 spin_lock_irq() and spin_unlock_irq()
in the NETPOLL API callbacks causes the interrupts to get enabled and
can lead to kernel instability.
The solution is to use spin_lock_irqsave() and spin_unlock_restore()
to prevent the irqs from getting enabled while in netpoll_send_skb().
Call trace:
netpoll_send_skb()
{
-> local_irq_save(flags)
---> dev->ndo_start_xmit(skb, dev)
---> spin_lock_irq()
---> spin_unlock_irq() *******here would enable the interrupt.
...
-> local_irq_restore(flags)
}
Signed-off-by: Dongdong Deng <dongdong.deng@windriver.com>
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Acked-by: Bruce Ashfield <bruce.ashfield@windriver.com>
Acked-by: Matt Mackall <mpm@selenic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ucc_geth.c')
-rw-r--r-- | drivers/net/ucc_geth.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 3b957e6412ee..8a7b8c7bd781 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -3111,10 +3111,11 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3111 | u8 __iomem *bd; /* BD pointer */ | 3111 | u8 __iomem *bd; /* BD pointer */ |
3112 | u32 bd_status; | 3112 | u32 bd_status; |
3113 | u8 txQ = 0; | 3113 | u8 txQ = 0; |
3114 | unsigned long flags; | ||
3114 | 3115 | ||
3115 | ugeth_vdbg("%s: IN", __func__); | 3116 | ugeth_vdbg("%s: IN", __func__); |
3116 | 3117 | ||
3117 | spin_lock_irq(&ugeth->lock); | 3118 | spin_lock_irqsave(&ugeth->lock, flags); |
3118 | 3119 | ||
3119 | dev->stats.tx_bytes += skb->len; | 3120 | dev->stats.tx_bytes += skb->len; |
3120 | 3121 | ||
@@ -3171,7 +3172,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3171 | uccf = ugeth->uccf; | 3172 | uccf = ugeth->uccf; |
3172 | out_be16(uccf->p_utodr, UCC_FAST_TOD); | 3173 | out_be16(uccf->p_utodr, UCC_FAST_TOD); |
3173 | #endif | 3174 | #endif |
3174 | spin_unlock_irq(&ugeth->lock); | 3175 | spin_unlock_irqrestore(&ugeth->lock, flags); |
3175 | 3176 | ||
3176 | return 0; | 3177 | return 0; |
3177 | } | 3178 | } |