aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/r8169.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-03-30 22:08:31 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-01 21:41:35 -0400
commit630b943c182d1aed69f244405131902fbcba7ec6 (patch)
tree8681938a3c4922405e8df6a61b7152bfd1e96ea4 /drivers/net/r8169.c
parent5d944c640b4ae5f37c537acf491c2f0eb89fa0d6 (diff)
r8169: Fix rtl8169_rx_interrupt()
In case a reset is performed, rtl8169_rx_interrupt() is called from process context instead of softirq context. Special care must be taken to call appropriate network core services (netif_rx() instead of netif_receive_skb()). VLAN handling also corrected. Reported-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Tested-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Diagnosed-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/r8169.c')
-rw-r--r--drivers/net/r8169.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 964305c7f9f..f7ffa5d8ffe 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1054,14 +1054,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev,
1054} 1054}
1055 1055
1056static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, 1056static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
1057 struct sk_buff *skb) 1057 struct sk_buff *skb, int polling)
1058{ 1058{
1059 u32 opts2 = le32_to_cpu(desc->opts2); 1059 u32 opts2 = le32_to_cpu(desc->opts2);
1060 struct vlan_group *vlgrp = tp->vlgrp; 1060 struct vlan_group *vlgrp = tp->vlgrp;
1061 int ret; 1061 int ret;
1062 1062
1063 if (vlgrp && (opts2 & RxVlanTag)) { 1063 if (vlgrp && (opts2 & RxVlanTag)) {
1064 vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff)); 1064 __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);
1065 ret = 0; 1065 ret = 0;
1066 } else 1066 } else
1067 ret = -1; 1067 ret = -1;
@@ -1078,7 +1078,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
1078} 1078}
1079 1079
1080static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, 1080static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
1081 struct sk_buff *skb) 1081 struct sk_buff *skb, int polling)
1082{ 1082{
1083 return -1; 1083 return -1;
1084} 1084}
@@ -4467,12 +4467,20 @@ out:
4467 return done; 4467 return done;
4468} 4468}
4469 4469
4470/*
4471 * Warning : rtl8169_rx_interrupt() might be called :
4472 * 1) from NAPI (softirq) context
4473 * (polling = 1 : we should call netif_receive_skb())
4474 * 2) from process context (rtl8169_reset_task())
4475 * (polling = 0 : we must call netif_rx() instead)
4476 */
4470static int rtl8169_rx_interrupt(struct net_device *dev, 4477static int rtl8169_rx_interrupt(struct net_device *dev,
4471 struct rtl8169_private *tp, 4478 struct rtl8169_private *tp,
4472 void __iomem *ioaddr, u32 budget) 4479 void __iomem *ioaddr, u32 budget)
4473{ 4480{
4474 unsigned int cur_rx, rx_left; 4481 unsigned int cur_rx, rx_left;
4475 unsigned int delta, count; 4482 unsigned int delta, count;
4483 int polling = (budget != ~(u32)0) ? 1 : 0;
4476 4484
4477 cur_rx = tp->cur_rx; 4485 cur_rx = tp->cur_rx;
4478 rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; 4486 rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
@@ -4534,8 +4542,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
4534 skb_put(skb, pkt_size); 4542 skb_put(skb, pkt_size);
4535 skb->protocol = eth_type_trans(skb, dev); 4543 skb->protocol = eth_type_trans(skb, dev);
4536 4544
4537 if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0) 4545 if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) {
4538 netif_receive_skb(skb); 4546 if (likely(polling))
4547 netif_receive_skb(skb);
4548 else
4549 netif_rx(skb);
4550 }
4539 4551
4540 dev->stats.rx_bytes += pkt_size; 4552 dev->stats.rx_bytes += pkt_size;
4541 dev->stats.rx_packets++; 4553 dev->stats.rx_packets++;