Skip to content

Commit

Permalink
r8169: Fix rtl8169_rx_interrupt()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Apr 2, 2010
1 parent 5d944c6 commit 630b943
Showing 1 changed file with 17 additions and 5 deletions.
22 changes: 17 additions & 5 deletions drivers/net/r8169.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct sk_buff *skb)
struct sk_buff *skb, int polling)
{
u32 opts2 = le32_to_cpu(desc->opts2);
struct vlan_group *vlgrp = tp->vlgrp;
int ret;

if (vlgrp && (opts2 & RxVlanTag)) {
vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff));
__vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);
ret = 0;
} else
ret = -1;
Expand All @@ -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,
struct sk_buff *skb)
struct sk_buff *skb, int polling)
{
return -1;
}
Expand Down Expand Up @@ -4467,12 +4467,20 @@ static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff,
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,
struct rtl8169_private *tp,
void __iomem *ioaddr, u32 budget)
{
unsigned int cur_rx, rx_left;
unsigned int delta, count;
int polling = (budget != ~(u32)0) ? 1 : 0;

cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
Expand Down Expand Up @@ -4534,8 +4542,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);

if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)
netif_receive_skb(skb);
if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) {
if (likely(polling))
netif_receive_skb(skb);
else
netif_rx(skb);
}

dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++;
Expand Down

0 comments on commit 630b943

Please sign in to comment.