Commit 630b943c authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

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: default avatarSergey Senozhatsky <sergey.senozhatsky@gmail.com>
Tested-by: default avatarSergey Senozhatsky <sergey.senozhatsky@gmail.com>
Diagnosed-by: default avatarOleg Nesterov <oleg@redhat.com>
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5d944c64
...@@ -1054,14 +1054,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev, ...@@ -1054,14 +1054,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev,
} }
static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
struct sk_buff *skb) struct sk_buff *skb, int polling)
{ {
u32 opts2 = le32_to_cpu(desc->opts2); u32 opts2 = le32_to_cpu(desc->opts2);
struct vlan_group *vlgrp = tp->vlgrp; struct vlan_group *vlgrp = tp->vlgrp;
int ret; int ret;
if (vlgrp && (opts2 & RxVlanTag)) { if (vlgrp && (opts2 & RxVlanTag)) {
vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff)); __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);
ret = 0; ret = 0;
} else } else
ret = -1; ret = -1;
...@@ -1078,7 +1078,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp, ...@@ -1078,7 +1078,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
} }
static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
struct sk_buff *skb) struct sk_buff *skb, int polling)
{ {
return -1; return -1;
} }
...@@ -4467,12 +4467,20 @@ static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff, ...@@ -4467,12 +4467,20 @@ static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff,
return done; return done;
} }
/*
* Warning : rtl8169_rx_interrupt() might be called :
* 1) from NAPI (softirq) context
* (polling = 1 : we should call netif_receive_skb())
* 2) from process context (rtl8169_reset_task())
* (polling = 0 : we must call netif_rx() instead)
*/
static int rtl8169_rx_interrupt(struct net_device *dev, static int rtl8169_rx_interrupt(struct net_device *dev,
struct rtl8169_private *tp, struct rtl8169_private *tp,
void __iomem *ioaddr, u32 budget) void __iomem *ioaddr, u32 budget)
{ {
unsigned int cur_rx, rx_left; unsigned int cur_rx, rx_left;
unsigned int delta, count; unsigned int delta, count;
int polling = (budget != ~(u32)0) ? 1 : 0;
cur_rx = tp->cur_rx; cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
...@@ -4534,8 +4542,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev, ...@@ -4534,8 +4542,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
skb_put(skb, pkt_size); skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0) if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) {
netif_receive_skb(skb); if (likely(polling))
netif_receive_skb(skb);
else
netif_rx(skb);
}
dev->stats.rx_bytes += pkt_size; dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++; dev->stats.rx_packets++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment