Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c3b9d34 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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 6c9ae016
Loading
Loading
Loading
Loading
+17 −5
Original line number Original line Diff line number Diff line
@@ -1042,14 +1042,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;
@@ -1066,7 +1066,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;
}
}
@@ -4445,12 +4445,20 @@ out:
	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;
@@ -4512,8 +4520,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) {
				if (likely(polling))
					netif_receive_skb(skb);
					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++;