diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-04-30 19:20:39 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-30 19:20:39 -0400 |
commit | 6c3b9d3458a8272f1e4c6aed9e8325136f6380f9 (patch) | |
tree | d13521a00efb89156e86acf9535784c45c4a1c9b | |
parent | 6c9ae016a8e2aff931391d3baa9ce6cb0ffa633c (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>
-rw-r--r-- | drivers/net/r8169.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4748c21eb72e..dd8106ff35aa 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -1042,14 +1042,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev, | |||
1042 | } | 1042 | } |
1043 | 1043 | ||
1044 | static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, | 1044 | static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, |
1045 | struct sk_buff *skb) | 1045 | struct sk_buff *skb, int polling) |
1046 | { | 1046 | { |
1047 | u32 opts2 = le32_to_cpu(desc->opts2); | 1047 | u32 opts2 = le32_to_cpu(desc->opts2); |
1048 | struct vlan_group *vlgrp = tp->vlgrp; | 1048 | struct vlan_group *vlgrp = tp->vlgrp; |
1049 | int ret; | 1049 | int ret; |
1050 | 1050 | ||
1051 | if (vlgrp && (opts2 & RxVlanTag)) { | 1051 | if (vlgrp && (opts2 & RxVlanTag)) { |
1052 | vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff)); | 1052 | __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling); |
1053 | ret = 0; | 1053 | ret = 0; |
1054 | } else | 1054 | } else |
1055 | ret = -1; | 1055 | ret = -1; |
@@ -1066,7 +1066,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp, | |||
1066 | } | 1066 | } |
1067 | 1067 | ||
1068 | static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, | 1068 | static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, |
1069 | struct sk_buff *skb) | 1069 | struct sk_buff *skb, int polling) |
1070 | { | 1070 | { |
1071 | return -1; | 1071 | return -1; |
1072 | } | 1072 | } |
@@ -4445,12 +4445,20 @@ out: | |||
4445 | return done; | 4445 | return done; |
4446 | } | 4446 | } |
4447 | 4447 | ||
4448 | /* | ||
4449 | * Warning : rtl8169_rx_interrupt() might be called : | ||
4450 | * 1) from NAPI (softirq) context | ||
4451 | * (polling = 1 : we should call netif_receive_skb()) | ||
4452 | * 2) from process context (rtl8169_reset_task()) | ||
4453 | * (polling = 0 : we must call netif_rx() instead) | ||
4454 | */ | ||
4448 | static int rtl8169_rx_interrupt(struct net_device *dev, | 4455 | static int rtl8169_rx_interrupt(struct net_device *dev, |
4449 | struct rtl8169_private *tp, | 4456 | struct rtl8169_private *tp, |
4450 | void __iomem *ioaddr, u32 budget) | 4457 | void __iomem *ioaddr, u32 budget) |
4451 | { | 4458 | { |
4452 | unsigned int cur_rx, rx_left; | 4459 | unsigned int cur_rx, rx_left; |
4453 | unsigned int delta, count; | 4460 | unsigned int delta, count; |
4461 | int polling = (budget != ~(u32)0) ? 1 : 0; | ||
4454 | 4462 | ||
4455 | cur_rx = tp->cur_rx; | 4463 | cur_rx = tp->cur_rx; |
4456 | rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; | 4464 | rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; |
@@ -4512,8 +4520,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev, | |||
4512 | skb_put(skb, pkt_size); | 4520 | skb_put(skb, pkt_size); |
4513 | skb->protocol = eth_type_trans(skb, dev); | 4521 | skb->protocol = eth_type_trans(skb, dev); |
4514 | 4522 | ||
4515 | if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0) | 4523 | if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) { |
4516 | netif_receive_skb(skb); | 4524 | if (likely(polling)) |
4525 | netif_receive_skb(skb); | ||
4526 | else | ||
4527 | netif_rx(skb); | ||
4528 | } | ||
4517 | 4529 | ||
4518 | dev->stats.rx_bytes += pkt_size; | 4530 | dev->stats.rx_bytes += pkt_size; |
4519 | dev->stats.rx_packets++; | 4531 | dev->stats.rx_packets++; |