Netdev List
 help / color / mirror / Atom feed
* Patch for stable: bridge: Pull ip header into skb->data before looking into ip header.
From: Bandi,Sarveshwar @ 2013-01-11  6:58 UTC (permalink / raw)
  To: davem@davemloft.net; +Cc: netdev@vger.kernel.org

Dave,
  Can you please queue the following patch for linux 3.x stable trees?

commit 6caab7b0544e83e6c160b5e80f5a4a7dd69545c7
Author: Sarveshwar Bandi <sarveshwar.bandi@emulex.com>
Date:   Wed Oct 10 01:15:01 2012 +0000

    bridge: Pull ip header into skb->data before looking into ip header.

    If lower layer driver leaves the ip header in the skb fragment, it needs to
    be first pulled into skb->data before inspecting ip header length or ip version
    number.

    Signed-off-by: Sarveshwar Bandi <sarveshwar.bandi@emulex.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

Thanks,
Sarvesh

^ permalink raw reply

* Re: [patch] tg3: missing break statement in tg3_get_5720_nvram_info()
From: David Miller @ 2013-01-11  7:00 UTC (permalink / raw)
  To: dan.carpenter
  Cc: mchan, mcarlson, grant.likely, rob.herring, netdev,
	devicetree-discuss, kernel-janitors
In-Reply-To: <20130111065733.GG13207@elgon.mountain>

From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Fri, 11 Jan 2013 09:57:33 +0300

> There is a missing break statement so FLASH_5762_EEPROM_HD gets treated
> like FLASH_5762_EEPROM_LD.
> 
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>

Applied, thanks Dan.

^ permalink raw reply

* Re: [PATCH 2/2] ipv6: fix packet corruption when Dest/RT2 options are used
From: Romain KUNTZ @ 2013-01-11  7:27 UTC (permalink / raw)
  To: netdev; +Cc: yoshfuji, davem, Steffen Klassert, Romain KUNTZ
In-Reply-To: <C7895CAA-0AF7-4EED-B9E7-9D8E4A21442B@ipflavors.com>

On Jan 5, 2013, at 17:19 , Romain KUNTZ <r.kuntz@ipflavors.com> wrote:
> Commit 299b0767 (ipv6: Fix IPsec slowpath fragmentation problem)
> has introduced a bug that provokes corrupted packets when Destination
> Options or Routing Header Type 2 are used (such as with Mobile IPv6):
> rt->rt6i_nfheader_len should be substracted to rt->dst.header_len,
> and not to exthdrlen.
> 
> This patch reverts to the original and correct behavior. Successfully
> tested with and without IPsec activated for MH packets.
> 
> Signed-off-by: Romain Kuntz <r.kuntz@ipflavors.com>
> Acked-by: Steffen Klassert <steffen.klassert@secunet.com>
> ---
> net/ipv6/ip6_output.c |    4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index 5552d13..0c7c03d 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -1213,10 +1213,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
> 		if (dst_allfrag(rt->dst.path))
> 			cork->flags |= IPCORK_ALLFRAG;
> 		cork->length = 0;
> -		exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len;
> +		exthdrlen = (opt ? opt->opt_flen : 0);
> 		length += exthdrlen;
> 		transhdrlen += exthdrlen;
> -		dst_exthdrlen = rt->dst.header_len;
> +		dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
> 	} else {
> 		rt = (struct rt6_info *)cork->dst;
> 		fl6 = &inet->cork.fl.u.ip6;
> -- 
> 1.7.2.5

Resending this one adding the 'Acked-by: Steffen Klassert'.

Romain

^ permalink raw reply

* Re: [RFCv2 00/12] Introduce host-side virtio queue and CAIF Virtio.
From: Michael S. Tsirkin @ 2013-01-11  7:31 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Sjur Brændeland, Linus Walleij, virtualization, netdev
In-Reply-To: <87sj681wou.fsf@rustcorp.com.au>

On Fri, Jan 11, 2013 at 09:18:33AM +1030, Rusty Russell wrote:
> "Michael S. Tsirkin" <mst@redhat.com> writes:
> > On Thu, Jan 10, 2013 at 09:00:55PM +1030, Rusty Russell wrote:
> >> Not sure why vhost/net doesn't built a packet and feed it in
> >> netif_rx_ni().  This is what tun seems to do, and with this code it
> >> should be fairly optimal.
> >
> > Because we want to use NAPI.
> 
> Not quite what I was asking; it was more a question of why we're using a
> raw socket, when we trivially have a complete skb already which we
> should be able to feed to Linux like any network packet.
> 
> And that path is pretty well optimized...
> 
> Cheers,
> Rusty.


Oh for some reason I thought you were talking about virtio.
I don't really understand what you are saying here - vhost
actually calls out to tun to build and submit the skb.

-- 
MST

^ permalink raw reply

* Re: [RFC PATCH 0/2] make mac programming for virtio net more robust
From: Michael S. Tsirkin @ 2013-01-11  7:46 UTC (permalink / raw)
  To: Rusty Russell
  Cc: akong, kvm, virtualization, qemu-devel, netdev, David Miller
In-Reply-To: <87fw281mr8.fsf@rustcorp.com.au>

On Fri, Jan 11, 2013 at 12:53:07PM +1030, Rusty Russell wrote:
> "Michael S. Tsirkin" <mst@redhat.com> writes:
> 
> > On Thu, Jan 10, 2013 at 10:45:39PM +0800, akong@redhat.com wrote:
> >> From: Amos Kong <akong@redhat.com>
> >> 
> >> Currenly mac is programmed byte by byte. This means that we
> >> have an intermediate step where mac is wrong. 
> >> 
> >> Second patch introduced a new vq control command to set mac
> >> address in one time.
> >
> > As you mention we could alternatively do it without
> > new commands, simply add a feature bit that says that MACs are
> > in the mac table.
> > This would be a much bigger patch, and I'm fine with either way.
> > Rusty what do you think?
> 
> Hmm, mac filtering and "my mac address" are not quite the same thing.  I
> don't know if it matters for anyone: does it?
> The mac address is abused
> for things like identifying machines, etc.

I don't know either. I think net core differentiates between mac and
uc_list because linux has to know which mac to use when building
up packets, so at some level, I agree it might be useful to identify the
machine.

BTW netdev/davem should have been copied on this, Amos I think it's a
good idea to remember to do it next time you post.

> 
> If we keep it as a separate concept, Amos' patch seems to make sense.

Yes. It also keeps the patch small, I just thought I'd mention the
option.

> 
> Cheers,
> Rusty.

-- 
MST

^ permalink raw reply

* Re: [RFC PATCH] ah4/esp4: set transport header correctly for IPsec tunnel mode.
From: Steffen Klassert @ 2013-01-11  7:53 UTC (permalink / raw)
  To: roy.qing.li; +Cc: netdev
In-Reply-To: <1356682036-25642-1-git-send-email-roy.qing.li@gmail.com>

On Fri, Dec 28, 2012 at 04:07:16PM +0800, roy.qing.li@gmail.com wrote:
> From: Li RongQing <roy.qing.li@gmail.com>
> 
> IPsec tunnel does not set ECN field to CE in inner header when
> the ECN field in the outer header is CE, and the ECN field in
> the inner header is ECT(0) or ECT(1).
> 
> The cause is ipip_hdr() does not return the correct address of
> inner header since skb->transport-header is not the inner header
> after esp_input_done2(), or ah_input().
> 
> Signed-off-by: Li RongQing <roy.qing.li@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH] ah6/esp6: set transport header correctly for IPsec tunnel mode.
From: Steffen Klassert @ 2013-01-11  7:54 UTC (permalink / raw)
  To: roy.qing.li; +Cc: netdev
In-Reply-To: <1357630872-1942-1-git-send-email-roy.qing.li@gmail.com>

On Tue, Jan 08, 2013 at 03:41:12PM +0800, roy.qing.li@gmail.com wrote:
> From: Li RongQing <roy.qing.li@gmail.com>
> 
> IPsec tunnel does not set ECN field to CE in inner header when
> the ECN field in the outer header is CE, and the ECN field in
> the inner header is ECT(0) or ECT(1).
> 
> The cause is ipip6_hdr() does not return the correct address of
> inner header since skb->transport-header is not the inner header
> after esp6_input_done2(), or ah6_input().
> 
> Signed-off-by: Li RongQing <roy.qing.li@gmail.com>

Also applied, thanks a lot!

^ permalink raw reply

* [PATCH] xfrm: check if packet is overdue on asynchronous code path
From: roy.qing.li @ 2013-01-11  8:12 UTC (permalink / raw)
  To: netdev; +Cc: steffen.klassert

From: Li RongQing <roy.qing.li@gmail.com>

Currently checking is only done on synchronous code path,
we should do the same checking on asynchronous code path.

Signed-off-by: Li RongQing <roy.qing.li@gmail.com>
---
 net/xfrm/xfrm_input.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index ab2bb42..d034324 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -199,6 +199,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 
 resume:
 		spin_lock(&x->lock);
+
+		if (async && xfrm_state_check_expire(x)) {
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED);
+			goto drop_unlock;
+		}
+
 		if (nexthdr <= 0) {
 			if (nexthdr == -EBADMSG) {
 				xfrm_audit_state_icvfail(x, skb,
-- 
1.7.10.4

^ permalink raw reply related

* Re: [PATCH] ax88179_178a: ASIX AX88179_178A USB 3.0/2.0 to gigabit ethernet adapter driver
From: Christian Riesch @ 2013-01-11  8:18 UTC (permalink / raw)
  To: freddy; +Cc: Ming Lei, davem, linux-kernel, louis, netdev, linux-usb
In-Reply-To: <CACVXFVMdgx1we67poF5yU5pAYRYoA9Ao1EJqQgGBaaORuARFQQ@mail.gmail.com>

Hi,

On 2013-01-11 03:45, Ming Lei wrote:
> Cc netdev and usb lists.
>
>
> On Fri, Jan 11, 2013 at 9:17 AM,  <freddy@asix.com.tw> wrote:
>> From: Freddy Xin <freddy@asix.com.tw>
>>
>> This patch adds a driver for ASIX's AX88179 family of USB 3.0/2.0
>> to gigabit ethernet adapters. It's based on the AX88xxx driver but
>> the usb commands used to access registers for AX88179 are completely different.
>> This driver had been verified on x86 system with AX88179/AX88178A and
>> Sitcomm LN-032 USB dongles.
>>
>> Signed-off-by: Freddy Xin <freddy@asix.com.tw>
>> ---
>>   drivers/net/usb/Kconfig        |   18 +
>>   drivers/net/usb/Makefile       |    1 +
>>   drivers/net/usb/ax88179_178a.c | 1457 ++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 1476 insertions(+)
>>   create mode 100644 drivers/net/usb/ax88179_178a.c
>>

[...]

>> diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
>> new file mode 100644
>> index 0000000..47504ea
>> --- /dev/null
>> +++ b/drivers/net/usb/ax88179_178a.c
[...]
>> +static int ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
>> +                           u16 size, void *data)
>> +{
>> +       int ret;
>> +       ret = usbnet_read_cmd(dev, cmd,
>> +                              USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
>> +                              value, index, data, size);
>> +
>> +       if (ret != size && ret >= 0)
>> +               return -EINVAL;
>> +       return ret;
>> +}
>> +
>> +static int ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
>> +                            u16 size, void *data)
>> +{
>> +       return usbnet_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR
>> +                               | USB_RECIP_DEVICE, value, index, data, size);
>> +}
>> +
>> +static void
>> +ax88179_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
>> +                                   u16 size, void *data)
>> +{
>> +       usbnet_write_cmd_async(dev, cmd,
>> +                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
>> +                              value, index, data, size);
>> +}
>> +

ax88179_read_cmd, ax88179_write_cmd, and ax88179_write_cmd_async 
duplicate code from asix_common.c.

[...]

>> +static int ax88179_get_eeprom(struct net_device *net,
>> +                             struct ethtool_eeprom *eeprom, u8 *data)
>> +{
>> +       struct usbnet *dev = netdev_priv(net);
>> +       u16 *ebuf = (u16 *)data;
>> +       int i;
>> +
>> +       /* Crude hack to ensure that we don't overwrite memory
>> +        * if an odd length is supplied

Have a look at asix_get_eeprom() in asix_common.c for a better 
implementation. There is also code for programming the eeprom 
(asix_set_eeprom in asix_common.c), can this be used for the 
AX88179/178A as well?

Regards, Christian

>> +        */
>> +       if (eeprom->len % 2)
>> +               return -EINVAL;
>> +
>> +       /* ax8817x returns 2 bytes from eeprom on read */
>> +       for (i = 0; i < eeprom->len / 2; i++) {
>> +               if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM,
>> +                       eeprom->offset + i, 1, 2, &ebuf[i]) < 0)
>> +                       return -EINVAL;
>> +       }
>> +       return 0;
>> +}
>> +

^ permalink raw reply

* Re: [PATCH] xfrm: check if packet is overdue on asynchronous code path
From: Steffen Klassert @ 2013-01-11  8:29 UTC (permalink / raw)
  To: roy.qing.li; +Cc: netdev
In-Reply-To: <1357891965-8047-1-git-send-email-roy.qing.li@gmail.com>

On Fri, Jan 11, 2013 at 04:12:45PM +0800, roy.qing.li@gmail.com wrote:
> From: Li RongQing <roy.qing.li@gmail.com>
> 
> Currently checking is only done on synchronous code path,
> we should do the same checking on asynchronous code path.

We do this check already before we enter the asynchronous code path,
there is no need to do this check again.

^ permalink raw reply

* Re: [PATCH V3 1/2] virtio-net: fix the set affinity bug when CPU IDs are not consecutive
From: Jason Wang @ 2013-01-11  8:37 UTC (permalink / raw)
  To: Ben Hutchings, Michael S. Tsirkin
  Cc: netdev, linux-kernel, virtualization, Eric Dumazet
In-Reply-To: <1357845142.2712.11.camel@bwh-desktop.uk.solarflarecom.com>

On 01/11/2013 03:12 AM, Ben Hutchings wrote:
> On Thu, 2013-01-10 at 11:19 +1030, Rusty Russell wrote:
>> Wanlong Gao <gaowanlong@cn.fujitsu.com> writes:
>>> On 01/09/2013 07:31 AM, Rusty Russell wrote:
>>>> Wanlong Gao <gaowanlong@cn.fujitsu.com> writes:
>>>>>   */
>>>>>  static u16 virtnet_select_queue(struct net_device *dev, struct sk_buff *skb)
>>>>>  {
>>>>> -	int txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
>>>>> -		  smp_processor_id();
>>>>> +	int txq = 0;
>>>>> +
>>>>> +	if (skb_rx_queue_recorded(skb))
>>>>> +		txq = skb_get_rx_queue(skb);
>>>>> +	else if ((txq = per_cpu(vq_index, smp_processor_id())) == -1)
>>>>> +		txq = 0;
>>>> You should use __get_cpu_var() instead of smp_processor_id() here, ie:
>>>>
>>>>         else if ((txq = __get_cpu_var(vq_index)) == -1)
>>>>
>>>> And AFAICT, no reason to initialize txq to 0 to start with.
>>>>
>>>> So:
>>>>
>>>>         int txq;
>>>>
>>>>         if (skb_rx_queue_recorded(skb))
>>>> 		txq = skb_get_rx_queue(skb);
>>>>         else {
>>>>                 txq = __get_cpu_var(vq_index);
>>>>                 if (txq == -1)
>>>>                         txq = 0;
>>>>         }
>>> Got it, thank you.
>>>
>>>> Now, just to confirm, I assume this can happen even if we use vq_index,
>>>> right, because of races with virtnet_set_channels?
>>> I still can't understand this race, could you explain more? thank you.
>> I assume that someone can call virtnet_set_channels() while we are
>> inside virtnet_select_queue(), so they reduce dev->real_num_tx_queues,
>> causing virtnet_set_channels to do:
>>
>> 	while (unlikely(txq >= dev->real_num_tx_queues))
>> 		txq -= dev->real_num_tx_queues;
>>
>> Otherwise, when is this loop called?
> In fact, this race can result in the TX scheduler using a queue that has
> been disabled, or other weirdness (consider what happens if
> real_num_tx_queues increases between those two uses).
>
> virtnet_set_channels() really must disable TX temporarily:
>
> 	netif_tx_lock(dev);
> 	netif_device_detach(dev);
> 	netif_tx_unlock(dev);
> 	...
> 	netif_device_attach(dev);
>
> Ben.
>

Michael, I think the future plan is trying to use multiqueue by default
instead of doing switching between the modes? If yes, we can temporarily
disable the tx instead of doing extra hacks.

^ permalink raw reply

* Re: [PATCH 3.8-rc] tuntap: refuse to re-attach to different tun_struct
From: Jason Wang @ 2013-01-11  8:38 UTC (permalink / raw)
  To: David Miller; +Cc: stefanha, mst, netdev, linux-kernel
In-Reply-To: <20130110.211237.653335807366477404.davem@davemloft.net>

On 01/11/2013 01:12 PM, David Miller wrote:
> From: Jason Wang <jasowang@redhat.com>
> Date: Fri, 11 Jan 2013 09:29:20 +0800
>
>> On 01/11/2013 06:39 AM, David Miller wrote:
>>> From: Stefan Hajnoczi <stefanha@redhat.com>
>>> Date: Thu, 10 Jan 2013 08:59:48 +0100
>>>
>>>> Multiqueue tun devices support detaching a tun_file from its tun_struct
>>>> and re-attaching at a later point in time.  This allows users to disable
>>>> a specific queue temporarily.
>>>>
>>>> ioctl(TUNSETIFF) allows the user to specify the network interface to
>>>> attach by name.  This means the user can attempt to attach to interface
>>>> "B" after detaching from interface "A".
>>>>
>>>> The driver is not designed to support this so check we are re-attaching
>>>> to the right tun_struct.  Failure to do so may lead to oops.
>>>>
>>>> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
>>> Applied.
>> Hi David:
>>
>> Any chance that I can have a respin on this patch, there's still a bug
>> after this patch. Or I just can send a patch on top?
> If I've applied it, there is no reverting.

Get it, will send patch on top.

Thanks

^ permalink raw reply

* Re: [PATCH V4 1/2] virtio-net: fix the set affinity bug when CPU IDs are not consecutive
From: Jason Wang @ 2013-01-11  8:44 UTC (permalink / raw)
  To: Wanlong Gao
  Cc: Michael S. Tsirkin, netdev, linux-kernel, virtualization,
	Eric Dumazet
In-Reply-To: <1357883793-15199-1-git-send-email-gaowanlong@cn.fujitsu.com>

On 01/11/2013 01:56 PM, Wanlong Gao wrote:
> As Michael mentioned, set affinity and select queue will not work very
> well when CPU IDs are not consecutive, this can happen with hot unplug.
> Fix this bug by traversal the online CPUs, and create a per cpu variable
> to find the mapping from CPU to the preferable virtual-queue.

Looks like ixgbe is trying to handling a similar issue recently by
trying to reuse XPS when the channels and cpus are not equal. I wonder
whether we can use the same method.
>
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Jason Wang <jasowang@redhat.com>
> Cc: Eric Dumazet <erdnetdev@gmail.com>
> Cc: virtualization@lists.linux-foundation.org
> Cc: netdev@vger.kernel.org
> Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com>
> ---
> V3->V4:
> 	move vq_index into virtnet_info	(Jason)
> 	change the mapping value when not setting affinity (Jason)
> 	address the comments about select_queue (Rusty)
> Not Addressed yet:
> 	race between select_queue and set_channels need discuss more
> 	but not the same problem with this (Rusty)
>
>  drivers/net/virtio_net.c | 53 ++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 42 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index a6fcf15..ca17a58 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -123,6 +123,9 @@ struct virtnet_info {
>  
>  	/* Does the affinity hint is set for virtqueues? */
>  	bool affinity_hint_set;
> +
> +	/* Per-cpu variable to show the mapping from CPU to virtqueue */
> +	int __percpu *vq_index;
>  };
>  
>  struct skb_vnet_hdr {
> @@ -1016,6 +1019,7 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
>  static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
>  {
>  	int i;
> +	int cpu;
>  
>  	/* In multiqueue mode, when the number of cpu is equal to the number of
>  	 * queue pairs, we let the queue pairs to be private to one cpu by
> @@ -1029,16 +1033,29 @@ static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
>  			return;
>  	}
>  
> -	for (i = 0; i < vi->max_queue_pairs; i++) {
> -		int cpu = set ? i : -1;
> -		virtqueue_set_affinity(vi->rq[i].vq, cpu);
> -		virtqueue_set_affinity(vi->sq[i].vq, cpu);
> -	}
> +	if (set) {
> +		i = 0;
> +		for_each_online_cpu(cpu) {
> +			virtqueue_set_affinity(vi->rq[i].vq, cpu);
> +			virtqueue_set_affinity(vi->sq[i].vq, cpu);
> +			*per_cpu_ptr(vi->vq_index, cpu) = i;
> +			i++;
> +		}
>  
> -	if (set)
>  		vi->affinity_hint_set = true;
> -	else
> +	} else {
> +		for(i = 0; i < vi->max_queue_pairs; i++) {
> +			virtqueue_set_affinity(vi->rq[i].vq, -1);
> +			virtqueue_set_affinity(vi->sq[i].vq, -1);
> +		}
> +
> +		i = 0;
> +		for_each_online_cpu(cpu)
> +			*per_cpu_ptr(vi->vq_index, cpu) =
> +				++i % vi->curr_queue_pairs;
> +
>  		vi->affinity_hint_set = false;
> +	}
>  }
>  
>  static void virtnet_get_ringparam(struct net_device *dev,
> @@ -1127,12 +1144,19 @@ static int virtnet_change_mtu(struct net_device *dev, int new_mtu)
>  
>  /* To avoid contending a lock hold by a vcpu who would exit to host, select the
>   * txq based on the processor id.
> - * TODO: handle cpu hotplug.
>   */
>  static u16 virtnet_select_queue(struct net_device *dev, struct sk_buff *skb)
>  {
> -	int txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
> -		  smp_processor_id();
> +	int txq;
> +	struct virtnet_info *vi = netdev_priv(dev);
> +
> +	if (skb_rx_queue_recorded(skb)) {
> +		txq = skb_get_rx_queue(skb);
> +	} else {
> +		txq = *__this_cpu_ptr(vi->vq_index);
> +		if (txq == -1)
> +			txq = 0;
> +	}
>  
>  	while (unlikely(txq >= dev->real_num_tx_queues))
>  		txq -= dev->real_num_tx_queues;
> @@ -1453,6 +1477,10 @@ static int virtnet_probe(struct virtio_device *vdev)
>  	if (vi->stats == NULL)
>  		goto free;
>  
> +	vi->vq_index = alloc_percpu(int);
> +	if (vi->vq_index == NULL)
> +		goto free_stats;
> +
>  	mutex_init(&vi->config_lock);
>  	vi->config_enable = true;
>  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
> @@ -1476,7 +1504,7 @@ static int virtnet_probe(struct virtio_device *vdev)
>  	/* Allocate/initialize the rx/tx queues, and invoke find_vqs */
>  	err = init_vqs(vi);
>  	if (err)
> -		goto free_stats;
> +		goto free_index;
>  
>  	netif_set_real_num_tx_queues(dev, 1);
>  	netif_set_real_num_rx_queues(dev, 1);
> @@ -1520,6 +1548,8 @@ free_recv_bufs:
>  free_vqs:
>  	cancel_delayed_work_sync(&vi->refill);
>  	virtnet_del_vqs(vi);
> +free_index:
> +	free_percpu(vi->vq_index);
>  free_stats:
>  	free_percpu(vi->stats);
>  free:
> @@ -1554,6 +1584,7 @@ static void virtnet_remove(struct virtio_device *vdev)
>  
>  	flush_work(&vi->config_work);
>  
> +	free_percpu(vi->vq_index);
>  	free_percpu(vi->stats);
>  	free_netdev(vi->dev);
>  }

^ permalink raw reply

* Re: [tcpdump-workers] [PATCH net 1/2] net: dev_queue_xmit_nit: fix skb->vlan_tci field value
From: Daniel Borkmann @ 2013-01-11  8:46 UTC (permalink / raw)
  To: Paul Pearce
  Cc: Michael Richardson, Eric Dumazet, Ani Sinha, Jiri Pirko, netdev,
	edumazet, tcpdump-workers
In-Reply-To: <CAOUgPvSpMmsLpiwmnxwFx9p+B=KOG5VqjNvu_+54hLcBPNK4Cg@mail.gmail.com>

On 01/11/2013 03:37 AM, Paul Pearce wrote:
>>> My opinion as a kernel developer is that the network tap is here to have
>>> a copy of the exact frame given to the _device_.

Agreed.

>> Good: as someone who spends lots of time with tcpdump doing both network
>> and protocol diagnostics, it's really important to see exactly there.
>> If that means turning off some hardware offload in order to get the
>> intact 1p header, then that may be fine for many situations.
>> (At 10G, on a live router... well...)
>
> I agree as well.
>
> But I think Ani's point was that for RX packets, as of commit
> bcc6d47903612c3861201cc3a866fb604f26b8b2, the filters are not
> getting exactly what's "on the wire." Independent of hardware
> acceleration the vlan headers are being stripped off and skb->vlan_tci
> is being set. That's was the origin of this whole mess.
>
> The msg from that commit reads in part:
>> Vlan untagging happens early in __netif_receive_skb so the rest of
>> code (ptype_all handlers, rx_handlers) see the skb like it was
>> untagged by hw.
>
> His confusion (which I share) is why it's acceptable to have this
> behavior of removing headers and setting skb->vlan_tci (regardless of
> hardware acceleration) on the RX path but not also set skb->vlan_tci
> on the TX path.
>
> Indepdent of proposed userspace or PACKET_AUXDATA solutions,
> clarification on the RX skb->vlan_tci behavior would be appreciated.
>
> My knowledge of this code is quite limited so it's entirely possible
> I'm off base here. If so please tell me.

While we're at the topic, though it's slightly unrelated this particular
problem, but related to capturing VLANs and ``what's seen on the wire'',
since it was mentioned.

For different NICs/drivers you might get different default behaviours, and
mostly it's the case (I assume, correct me if I'm wrong) that libpcap has
to ``un-untag'' the VLAN headers in user space, doing a memmove(3) for each
stripped VLAN packet in order to ``fix'' this.

Because of this hack, I even got a report of a user recently, that in
Wireshark, he saw a QinQ header, although it should just have been one
VLAN encapsulation (AR8131 driver with ethtool -K eth0 rxvlan off) as he
saw with netsniff-ng (no memmove(3) done there). (I didn't further follow
or verify this report though.)

^ permalink raw reply

* [PATCH 1/2] tuntap: forbid calling TUNSETIFF when detached
From: Jason Wang @ 2013-01-11  8:50 UTC (permalink / raw)
  To: davem, mst, netdev, linux-kernel; +Cc: Jason Wang, Stefan Hajnoczi

Michael points out that even after Stefan's fix the TUNSETIFF is still allowed
to create a new tap device. This because we only check tfile->tun but the
tfile->detached were introduced. Fix this by failing early in tun_set_iff() if
the file is detached. After this fix, there's no need to do the check again in
tun_set_iff(), so this patch removes it.

Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 drivers/net/tun.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 99b58d8..9a46d70 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -491,8 +491,6 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
 	err = -EINVAL;
 	if (rcu_dereference_protected(tfile->tun, lockdep_rtnl_is_held()))
 		goto out;
-	if (tfile->detached && tun != tfile->detached)
-		goto out;
 
 	err = -EBUSY;
 	if (!(tun->flags & TUN_TAP_MQ) && tun->numqueues == 1)
@@ -1546,6 +1544,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 	struct net_device *dev;
 	int err;
 
+	if (rcu_dereference_protected(tfile->detached, lockdep_rtnl_is_held()))
+		return -EINVAL;
+
 	dev = __dev_get_by_name(net, ifr->ifr_name);
 	if (dev) {
 		if (ifr->ifr_flags & IFF_TUN_EXCL)
-- 
1.7.1

^ permalink raw reply related

* [PATCH 2/2] tuntap: fix leaking reference count
From: Jason Wang @ 2013-01-11  8:50 UTC (permalink / raw)
  To: davem, mst, netdev, linux-kernel; +Cc: Jason Wang
In-Reply-To: <1357894242-25020-1-git-send-email-jasowang@redhat.com>

Reference count leaking of both module and sock were found:

- When a detached file were closed, its sock refcnt from device were not
  released, solving this by add the sock_put().
- The module were hold or drop unconditionally in TUNSETPERSIST, which means we
  if we set the persist flag for N times, we need unset it for another N
  times. Solving this by only hold or drop an reference when there's a flag
  change and also drop the reference count when the persist device is deleted.

Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 drivers/net/tun.c |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 9a46d70..d690dc8 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -429,8 +429,10 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
 		/* Drop read queue */
 		skb_queue_purge(&tfile->sk.sk_receive_queue);
 		tun_set_real_num_queues(tun);
-	} else if (tfile->detached && clean)
+	} else if (tfile->detached && clean) {
 		tun = tun_enable_queue(tfile);
+		sock_put(&tfile->sk);
+	}
 
 	if (clean) {
 		if (tun && tun->numqueues == 0 && tun->numdisabled == 0 &&
@@ -481,6 +483,9 @@ static void tun_detach_all(struct net_device *dev)
 		sock_put(&tfile->sk);
 	}
 	BUG_ON(tun->numdisabled != 0);
+
+	if (tun->flags & TUN_PERSIST)
+		module_put(THIS_MODULE);
 }
 
 static int tun_attach(struct tun_struct *tun, struct file *file)
@@ -1881,10 +1886,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 		/* Disable/Enable persist mode. Keep an extra reference to the
 		 * module to prevent the module being unprobed.
 		 */
-		if (arg) {
+		if (arg && !(tun->flags & TUN_PERSIST)) {
 			tun->flags |= TUN_PERSIST;
 			__module_get(THIS_MODULE);
-		} else {
+		}
+		if (!arg && (tun->flags & TUN_PERSIST)) {
 			tun->flags &= ~TUN_PERSIST;
 			module_put(THIS_MODULE);
 		}
-- 
1.7.1

^ permalink raw reply related

* [PATCH net] qlge: remove NETIF_F_TSO6 flag
From: Cong Wang @ 2013-01-11  8:52 UTC (permalink / raw)
  To: netdev
  Cc: Jitendra Kalsaria, Ron Mercer, linux-driver, David S. Miller,
	Cong Wang

It is werid that qlge driver supports NETIF_F_TSO6 but
not NETIF_F_IPV6_CSUM. This also causes some kernel warning [1]
when VLAN device setups on a qlge interface.

I think the qlge hardware doesn't support NETIF_F_IPV6_CSUM,
so we have to just remove the NETIF_F_TSO6 flag.

After this patch, the TCP/IPv6 traffic becomes normal again,
no kernel warnings any more.

NOTE: I only tested it on 2.6.32 kernel, even if the upstream
kernel could fix this automatically (it is hard to track NETIF*
flags), removing it is also safe.

1. https://bugzilla.redhat.com/show_bug.cgi?id=891839

Cc: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Cc: Ron Mercer <ron.mercer@qlogic.com>
Cc: linux-driver@qlogic.com
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>

---
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index f80cd97..3e73742 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -4678,7 +4678,7 @@ static int qlge_probe(struct pci_dev *pdev,
 	qdev = netdev_priv(ndev);
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 	ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
-		NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN |
+		NETIF_F_TSO | NETIF_F_TSO_ECN |
 		NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM;
 	ndev->features = ndev->hw_features |
 		NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;

^ permalink raw reply related

* RE: [PATCH/RFC] ipv6: fib: Drop cached routes with dead neighbours on fib GC
From: David Laight @ 2013-01-11  8:57 UTC (permalink / raw)
  To: David Miller, roland; +Cc: netdev, roland
In-Reply-To: <20130110.141847.265135906896223944.davem@davemloft.net>

> Another reason we must make ipv6 like ipv4, which looks up neighbours
> on demand at packet output time rather than caching them in the route
> entries.

Presumable the neighbour could be left cached in the route entry
provided the code checks that the cached entry is still valid
and does a relookup if not (rather than a send-blackhole).

	David

^ permalink raw reply

* [PATCH v3] net, wireless: overwrite default_ethtool_ops
From: Stanislaw Gruszka @ 2013-01-11  9:19 UTC (permalink / raw)
  To: netdev, David S. Miller
  Cc: Eric Dumazet, Ben Greear, Bjørn Mork, linux-wireless,
	Ben Hutchings, Michał Mirosław, Johannes Berg

Since:

commit 2c60db037034d27f8c636403355d52872da92f81
Author: Eric Dumazet <edumazet@google.com>
Date:   Sun Sep 16 09:17:26 2012 +0000

    net: provide a default dev->ethtool_ops

wireless core does not correctly assign ethtool_ops.

After alloc_netdev*() call, some cfg80211 drivers provide they own
ethtool_ops, but some do not. For them, wireless core provide generic
cfg80211_ethtool_ops, which is assigned in NETDEV_REGISTER notify call:

        if (!dev->ethtool_ops)
                dev->ethtool_ops = &cfg80211_ethtool_ops;

But after Eric's commit, dev->ethtool_ops is no longer NULL (on cfg80211
drivers without custom ethtool_ops), but points to &default_ethtool_ops.

In order to fix the problem, provide function which will overwrite
default_ethtool_ops and use it by wireless core.

Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
v1 -> v2: change order of default_ethtool_ops initialization to avoid
the problem. Change the subject accordingly.

v2 -> v3: provide function to overwrite default_ethtool_ops, describe
problem a bit more detailed in the changelog

 include/linux/netdevice.h |    3 +++
 net/core/dev.c            |    8 ++++++++
 net/wireless/core.c       |    3 +--
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c599e47..9ef07d0 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -60,6 +60,9 @@ struct wireless_dev;
 #define SET_ETHTOOL_OPS(netdev,ops) \
 	( (netdev)->ethtool_ops = (ops) )
 
+extern void netdev_set_default_ethtool_ops(struct net_device *dev,
+					   const struct ethtool_ops *ops);
+
 /* hardware address assignment types */
 #define NET_ADDR_PERM		0	/* address is permanent (default) */
 #define NET_ADDR_RANDOM		1	/* address is generated randomly */
diff --git a/net/core/dev.c b/net/core/dev.c
index 515473e..f64e439 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6121,6 +6121,14 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
 
 static const struct ethtool_ops default_ethtool_ops;
 
+void netdev_set_default_ethtool_ops(struct net_device *dev,
+				    const struct ethtool_ops *ops)
+{
+	if (dev->ethtool_ops == &default_ethtool_ops)
+		dev->ethtool_ops = ops;
+}
+EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops);
+
 /**
  *	alloc_netdev_mqs - allocate network device
  *	@sizeof_priv:	size of private data to allocate space for
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 747dd93..7cbd3bf 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -858,8 +858,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 		/* allow mac80211 to determine the timeout */
 		wdev->ps_timeout = -1;
 
-		if (!dev->ethtool_ops)
-			dev->ethtool_ops = &cfg80211_ethtool_ops;
+		netdev_set_default_ethtool_ops(dev, &cfg80211_ethtool_ops);
 
 		if ((wdev->iftype == NL80211_IFTYPE_STATION ||
 		     wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
-- 
1.7.1

^ permalink raw reply related

* [PATCH] mm: compaction: Partially revert capture of suitable high-order page
From: Mel Gorman @ 2013-01-11  9:27 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Eric Wong, Eric Dumazet, Rik van Riel, Minchan Kim,
	Linus Torvalds, linux-mm, netdev, linux-kernel

Eric Wong reported on 3.7 and 3.8-rc2 that ppoll() got stuck when waiting
for POLLIN on a local TCP socket. It was easier to trigger if there was disk
IO and dirty pages at the same time and he bisected it to commit 1fb3f8ca
"mm: compaction: capture a suitable high-order page immediately when it
is made available".

The intention of that patch was to improve high-order allocations under
memory pressure after changes made to reclaim in 3.6 drastically hurt
THP allocations but the approach was flawed. For Eric, the problem was
that page->pfmemalloc was not being cleared for captured pages leading to
a poor interaction with swap-over-NFS support causing the packets to be
dropped. However, I identified a few more problems with the patch including
the fact that it can increase contention on zone->lock in some cases which
could result in async direct compaction being aborted early.

In retrospect the capture patch took the wrong approach. What it should
have done is mark the pageblock being migrated as MIGRATE_ISOLATE if it
was allocating for THP and avoided races that way. While the patch was
showing to improve allocation success rates at the time, the benefit is
marginal given the relative complexity and it should be revisited from
scratch in the context of the other reclaim-related changes that have taken
place since the patch was first written and tested. This patch partially
reverts commit 1fb3f8ca "mm: compaction: capture a suitable high-order
page immediately when it is made available".

Reported-and-tested-by: Eric Wong <normalperson@yhbt.net>
Tested-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
 include/linux/compaction.h |    4 +-
 include/linux/mm.h         |    1 -
 mm/compaction.c            |   92 +++++++-------------------------------------
 mm/internal.h              |    1 -
 mm/page_alloc.c            |   35 ++++-------------
 5 files changed, 23 insertions(+), 110 deletions(-)

diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index 6ecb6dc..cc7bdde 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -22,7 +22,7 @@ extern int sysctl_extfrag_handler(struct ctl_table *table, int write,
 extern int fragmentation_index(struct zone *zone, unsigned int order);
 extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
 			int order, gfp_t gfp_mask, nodemask_t *mask,
-			bool sync, bool *contended, struct page **page);
+			bool sync, bool *contended);
 extern int compact_pgdat(pg_data_t *pgdat, int order);
 extern void reset_isolation_suitable(pg_data_t *pgdat);
 extern unsigned long compaction_suitable(struct zone *zone, int order);
@@ -75,7 +75,7 @@ static inline bool compaction_restarting(struct zone *zone, int order)
 #else
 static inline unsigned long try_to_compact_pages(struct zonelist *zonelist,
 			int order, gfp_t gfp_mask, nodemask_t *nodemask,
-			bool sync, bool *contended, struct page **page)
+			bool sync, bool *contended)
 {
 	return COMPACT_CONTINUE;
 }
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 6320407..66e2f7c 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -455,7 +455,6 @@ void put_pages_list(struct list_head *pages);
 
 void split_page(struct page *page, unsigned int order);
 int split_free_page(struct page *page);
-int capture_free_page(struct page *page, int alloc_order, int migratetype);
 
 /*
  * Compound pages have a destructor function.  Provide a
diff --git a/mm/compaction.c b/mm/compaction.c
index 6b807e4..2c57043 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -816,6 +816,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
 static int compact_finished(struct zone *zone,
 			    struct compact_control *cc)
 {
+	unsigned int order;
 	unsigned long watermark;
 
 	if (fatal_signal_pending(current))
@@ -850,22 +851,16 @@ static int compact_finished(struct zone *zone,
 		return COMPACT_CONTINUE;
 
 	/* Direct compactor: Is a suitable page free? */
-	if (cc->page) {
-		/* Was a suitable page captured? */
-		if (*cc->page)
+	for (order = cc->order; order < MAX_ORDER; order++) {
+		struct free_area *area = &zone->free_area[order];
+
+		/* Job done if page is free of the right migratetype */
+		if (!list_empty(&area->free_list[cc->migratetype]))
+			return COMPACT_PARTIAL;
+
+		/* Job done if allocation would set block type */
+		if (cc->order >= pageblock_order && area->nr_free)
 			return COMPACT_PARTIAL;
-	} else {
-		unsigned int order;
-		for (order = cc->order; order < MAX_ORDER; order++) {
-			struct free_area *area = &zone->free_area[cc->order];
-			/* Job done if page is free of the right migratetype */
-			if (!list_empty(&area->free_list[cc->migratetype]))
-				return COMPACT_PARTIAL;
-
-			/* Job done if allocation would set block type */
-			if (cc->order >= pageblock_order && area->nr_free)
-				return COMPACT_PARTIAL;
-		}
 	}
 
 	return COMPACT_CONTINUE;
@@ -921,60 +916,6 @@ unsigned long compaction_suitable(struct zone *zone, int order)
 	return COMPACT_CONTINUE;
 }
 
-static void compact_capture_page(struct compact_control *cc)
-{
-	unsigned long flags;
-	int mtype, mtype_low, mtype_high;
-
-	if (!cc->page || *cc->page)
-		return;
-
-	/*
-	 * For MIGRATE_MOVABLE allocations we capture a suitable page ASAP
-	 * regardless of the migratetype of the freelist is is captured from.
-	 * This is fine because the order for a high-order MIGRATE_MOVABLE
-	 * allocation is typically at least a pageblock size and overall
-	 * fragmentation is not impaired. Other allocation types must
-	 * capture pages from their own migratelist because otherwise they
-	 * could pollute other pageblocks like MIGRATE_MOVABLE with
-	 * difficult to move pages and making fragmentation worse overall.
-	 */
-	if (cc->migratetype == MIGRATE_MOVABLE) {
-		mtype_low = 0;
-		mtype_high = MIGRATE_PCPTYPES;
-	} else {
-		mtype_low = cc->migratetype;
-		mtype_high = cc->migratetype + 1;
-	}
-
-	/* Speculatively examine the free lists without zone lock */
-	for (mtype = mtype_low; mtype < mtype_high; mtype++) {
-		int order;
-		for (order = cc->order; order < MAX_ORDER; order++) {
-			struct page *page;
-			struct free_area *area;
-			area = &(cc->zone->free_area[order]);
-			if (list_empty(&area->free_list[mtype]))
-				continue;
-
-			/* Take the lock and attempt capture of the page */
-			if (!compact_trylock_irqsave(&cc->zone->lock, &flags, cc))
-				return;
-			if (!list_empty(&area->free_list[mtype])) {
-				page = list_entry(area->free_list[mtype].next,
-							struct page, lru);
-				if (capture_free_page(page, cc->order, mtype)) {
-					spin_unlock_irqrestore(&cc->zone->lock,
-									flags);
-					*cc->page = page;
-					return;
-				}
-			}
-			spin_unlock_irqrestore(&cc->zone->lock, flags);
-		}
-	}
-}
-
 static int compact_zone(struct zone *zone, struct compact_control *cc)
 {
 	int ret;
@@ -1054,9 +995,6 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
 				goto out;
 			}
 		}
-
-		/* Capture a page now if it is a suitable size */
-		compact_capture_page(cc);
 	}
 
 out:
@@ -1069,8 +1007,7 @@ out:
 
 static unsigned long compact_zone_order(struct zone *zone,
 				 int order, gfp_t gfp_mask,
-				 bool sync, bool *contended,
-				 struct page **page)
+				 bool sync, bool *contended)
 {
 	unsigned long ret;
 	struct compact_control cc = {
@@ -1080,7 +1017,6 @@ static unsigned long compact_zone_order(struct zone *zone,
 		.migratetype = allocflags_to_migratetype(gfp_mask),
 		.zone = zone,
 		.sync = sync,
-		.page = page,
 	};
 	INIT_LIST_HEAD(&cc.freepages);
 	INIT_LIST_HEAD(&cc.migratepages);
@@ -1110,7 +1046,7 @@ int sysctl_extfrag_threshold = 500;
  */
 unsigned long try_to_compact_pages(struct zonelist *zonelist,
 			int order, gfp_t gfp_mask, nodemask_t *nodemask,
-			bool sync, bool *contended, struct page **page)
+			bool sync, bool *contended)
 {
 	enum zone_type high_zoneidx = gfp_zone(gfp_mask);
 	int may_enter_fs = gfp_mask & __GFP_FS;
@@ -1136,7 +1072,7 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
 		int status;
 
 		status = compact_zone_order(zone, order, gfp_mask, sync,
-						contended, page);
+						contended);
 		rc = max(status, rc);
 
 		/* If a normal allocation would succeed, stop compacting */
@@ -1192,7 +1128,6 @@ int compact_pgdat(pg_data_t *pgdat, int order)
 	struct compact_control cc = {
 		.order = order,
 		.sync = false,
-		.page = NULL,
 	};
 
 	return __compact_pgdat(pgdat, &cc);
@@ -1203,7 +1138,6 @@ static int compact_node(int nid)
 	struct compact_control cc = {
 		.order = -1,
 		.sync = true,
-		.page = NULL,
 	};
 
 	return __compact_pgdat(NODE_DATA(nid), &cc);
diff --git a/mm/internal.h b/mm/internal.h
index d597f94..9ba2110 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -135,7 +135,6 @@ struct compact_control {
 	int migratetype;		/* MOVABLE, RECLAIMABLE etc */
 	struct zone *zone;
 	bool contended;			/* True if a lock was contended */
-	struct page **page;		/* Page captured of requested size */
 };
 
 unsigned long
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 4ba5e37..7e4ae85 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1389,14 +1389,8 @@ void split_page(struct page *page, unsigned int order)
 		set_page_refcounted(page + i);
 }
 
-/*
- * Similar to the split_page family of functions except that the page
- * required at the given order and being isolated now to prevent races
- * with parallel allocators
- */
-int capture_free_page(struct page *page, int alloc_order, int migratetype)
+static int __isolate_free_page(struct page *page, unsigned int order)
 {
-	unsigned int order;
 	unsigned long watermark;
 	struct zone *zone;
 	int mt;
@@ -1404,7 +1398,6 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
 	BUG_ON(!PageBuddy(page));
 
 	zone = page_zone(page);
-	order = page_order(page);
 	mt = get_pageblock_migratetype(page);
 
 	if (mt != MIGRATE_ISOLATE) {
@@ -1413,7 +1406,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
 		if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
 			return 0;
 
-		__mod_zone_freepage_state(zone, -(1UL << alloc_order), mt);
+		__mod_zone_freepage_state(zone, -(1UL << order), mt);
 	}
 
 	/* Remove page from free list */
@@ -1421,11 +1414,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
 	zone->free_area[order].nr_free--;
 	rmv_page_order(page);
 
-	if (alloc_order != order)
-		expand(zone, page, alloc_order, order,
-			&zone->free_area[order], migratetype);
-
-	/* Set the pageblock if the captured page is at least a pageblock */
+	/* Set the pageblock if the isolated page is at least a pageblock */
 	if (order >= pageblock_order - 1) {
 		struct page *endpage = page + (1 << order) - 1;
 		for (; page < endpage; page += pageblock_nr_pages) {
@@ -1436,7 +1425,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
 		}
 	}
 
-	return 1UL << alloc_order;
+	return 1UL << order;
 }
 
 /*
@@ -1454,10 +1443,9 @@ int split_free_page(struct page *page)
 	unsigned int order;
 	int nr_pages;
 
-	BUG_ON(!PageBuddy(page));
 	order = page_order(page);
 
-	nr_pages = capture_free_page(page, order, 0);
+	nr_pages = __isolate_free_page(page, order);
 	if (!nr_pages)
 		return 0;
 
@@ -2163,8 +2151,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
 	bool *contended_compaction, bool *deferred_compaction,
 	unsigned long *did_some_progress)
 {
-	struct page *page = NULL;
-
 	if (!order)
 		return NULL;
 
@@ -2176,16 +2162,12 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
 	current->flags |= PF_MEMALLOC;
 	*did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask,
 						nodemask, sync_migration,
-						contended_compaction, &page);
+						contended_compaction);
 	current->flags &= ~PF_MEMALLOC;
 
-	/* If compaction captured a page, prep and use it */
-	if (page) {
-		prep_new_page(page, order, gfp_mask);
-		goto got_page;
-	}
-
 	if (*did_some_progress != COMPACT_SKIPPED) {
+		struct page *page;
+
 		/* Page migration frees to the PCP lists but we want merging */
 		drain_pages(get_cpu());
 		put_cpu();
@@ -2195,7 +2177,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
 				alloc_flags & ~ALLOC_NO_WATERMARKS,
 				preferred_zone, migratetype);
 		if (page) {
-got_page:
 			preferred_zone->compact_blockskip_flush = false;
 			preferred_zone->compact_considered = 0;
 			preferred_zone->compact_defer_shift = 0;

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply related

* RE: [PATCH] ax88179_178a: ASIX AX88179_178A USB 3.0/2.0 to gigabit ethernet adapter driver
From: Freddy @ 2013-01-11  9:30 UTC (permalink / raw)
  To: 'Christian Riesch'
  Cc: 'Ming Lei', davem, linux-kernel, louis, netdev, linux-usb
In-Reply-To: <50EFCAE6.9070306@omicron.at>

Hi,

>> +static int ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16
index,
>> +                           u16 size, void *data) {
>> +       int ret;
>> +       ret = usbnet_read_cmd(dev, cmd,
>> +                              USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_DEVICE,
>> +                              value, index, data, size);
>> +
>> +       if (ret != size && ret >= 0)
>> +               return -EINVAL;
>> +       return ret;
>> +}
>> +
>> +static int ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16
index,
>> +                            u16 size, void *data) {
>> +       return usbnet_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR
>> +                               | USB_RECIP_DEVICE, value, index, 
>> +data, size); }
>> +
>> +static void
>> +ax88179_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16
index,
>> +                                   u16 size, void *data) {
>> +       usbnet_write_cmd_async(dev, cmd,
>> +                              USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_DEVICE,
>> +                              value, index, data, size); }
>> +

ax88179_read_cmd, ax88179_write_cmd, and ax88179_write_cmd_async duplicate
code from asix_common.c.

Do you mean that I should merge this driver into asix_common and
asix_devices, or just reuse the functions that had been implemented?

[...]

>> +static int ax88179_get_eeprom(struct net_device *net,
>> +                             struct ethtool_eeprom *eeprom, u8 
>> +*data) {
>> +       struct usbnet *dev = netdev_priv(net);
>> +       u16 *ebuf = (u16 *)data;
>> +       int i;
>> +
>> +       /* Crude hack to ensure that we don't overwrite memory
>> +        * if an odd length is supplied

Have a look at asix_get_eeprom() in asix_common.c for a better
implementation. There is also code for programming the eeprom
(asix_set_eeprom in asix_common.c), can this be used for the AX88179/178A as
well?

Thanks, I will check whether the eeprom access functions in asix_common.c
can be used in the driver or not.

Regards, Freddy

>> +        */
>> +       if (eeprom->len % 2)
>> +               return -EINVAL;
>> +
>> +       /* ax8817x returns 2 bytes from eeprom on read */
>> +       for (i = 0; i < eeprom->len / 2; i++) {
>> +               if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM,
>> +                       eeprom->offset + i, 1, 2, &ebuf[i]) < 0)
>> +                       return -EINVAL;
>> +       }
>> +       return 0;
>> +}
>> +

^ permalink raw reply

* Re: ppoll() stuck on POLLIN while TCP peer is sending
From: Mel Gorman @ 2013-01-11  9:30 UTC (permalink / raw)
  To: Eric Wong
  Cc: linux-mm, netdev, linux-kernel, Rik van Riel, Minchan Kim,
	Eric Dumazet, Andrew Morton, Linus Torvalds
In-Reply-To: <20130111005105.GA15023@dcvr.yhbt.net>

On Fri, Jan 11, 2013 at 12:51:05AM +0000, Eric Wong wrote:
> Mel Gorman <mgorman@suse.de> wrote:
> > mm: compaction: Partially revert capture of suitable high-order page
> 
> <snip>
>  
> > Reported-by: Eric Wong <normalperson@yhbt.net>
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Mel Gorman <mgorman@suse.de>
> 
> Thanks, my original use case and test works great after several hours!
> 
> Tested-by: Eric Wong <normalperson@yhbt.net>
> 

Thanks very much Eric. I've resent the patch to Andrew so it should make
its way to mainline. It'll fail to apply to 3.7-stable but I should get
a notification from Greg when that happens and fix it up.

> Unfortunately, I also hit a new bug in 3.8 (not in 3.7.x).  based on Eric
> Dumazet's observations, sk_stream_wait_memory may be to blame.
> Fortunately this is easier to reproduce (I've cc-ed participants
> on this thread already): <20130111004915.GA15415@dcvr.yhbt.net>

It looks like the relevant fix for this has already been written by Eric
Dumazet and picked up by David Miller.

-- 
Mel Gorman
SUSE Labs

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* [net-next 00/15][pull request] Intel Wired LAN Driver Updates
From: Jeff Kirsher @ 2013-01-11 10:23 UTC (permalink / raw)
  To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann

This series contains updates to e1000e only.

The following are changes since commit 1def9238d4aa2146924994aa4b7dc861f03b9362:
  net_sched: more precise pkt_len computation
and are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next master

Bruce Allan (15):
  e1000e: SerDes autoneg flow control
  e1000e: Acquire/release semaphore when writing each EEPROM page
  e1000e: Invalid Image CSUM bit changed for I217
  e1000e: helper functions for accessing EMI registers
  e1000e: 82577: workaround for link drop issue
  e1000e: fix enabling of EEE on 82579 and I217
  e1000e: unexpected "Reset adapter" message when cable pulled
  e1000e: add missing bailout on error
  e1000e: resolve checkpatch PREFER_PR_LEVEL warning
  e1000e: cleanup redundant statistics counter
  e1000e: cleanup unusual comment placement
  e1000e: cleanup unnecessary line wrap
  e1000e: cleanup magic number
  e1000e: cleanup code duplication
  e1000e: merge multiple conditional statements into one

 drivers/net/ethernet/intel/e1000e/defines.h |  10 +-
 drivers/net/ethernet/intel/e1000e/e1000.h   |   2 +-
 drivers/net/ethernet/intel/e1000e/ethtool.c |   1 -
 drivers/net/ethernet/intel/e1000e/hw.h      |   4 +
 drivers/net/ethernet/intel/e1000e/ich8lan.c | 213 +++++++++++++++++++++-------
 drivers/net/ethernet/intel/e1000e/mac.c     | 125 ++++++++++++++++
 drivers/net/ethernet/intel/e1000e/netdev.c  |  67 ++++-----
 drivers/net/ethernet/intel/e1000e/nvm.c     |  26 ++--
 drivers/net/ethernet/intel/e1000e/param.c   |   3 +-
 9 files changed, 340 insertions(+), 111 deletions(-)

-- 
1.7.11.7

^ permalink raw reply

* [net-next 02/15] e1000e: Acquire/release semaphore when writing each EEPROM page
From: Jeff Kirsher @ 2013-01-11 10:23 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1357899831-4168-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

When data blocks are written to the EEPROM, the HW/SW/FW semaphore must be
held for the duration.  With large data blocks on 80003es2lan, 82571 and
82572, this can take too long and cause the firmware to take ownership of
the semaphore and consequently ownership of writes to the EEPROM.
Instead, acquire and release the semaphore for each page of the block
written.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/nvm.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c
index b646880..71938ed 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.c
+++ b/drivers/net/ethernet/intel/e1000e/nvm.c
@@ -359,7 +359,7 @@ s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 {
 	struct e1000_nvm_info *nvm = &hw->nvm;
-	s32 ret_val;
+	s32 ret_val = -E1000_ERR_NVM;
 	u16 widx = 0;
 
 	/* A check for invalid values:  offset too large, too many words,
@@ -371,16 +371,18 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 		return -E1000_ERR_NVM;
 	}
 
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
 	while (widx < words) {
 		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
 
-		ret_val = e1000_ready_nvm_eeprom(hw);
+		ret_val = nvm->ops.acquire(hw);
 		if (ret_val)
-			goto release;
+			return ret_val;
+
+		ret_val = e1000_ready_nvm_eeprom(hw);
+		if (ret_val) {
+			nvm->ops.release(hw);
+			return ret_val;
+		}
 
 		e1000_standby_nvm(hw);
 
@@ -413,12 +415,10 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 				break;
 			}
 		}
+		usleep_range(10000, 20000);
+		nvm->ops.release(hw);
 	}
 
-	usleep_range(10000, 20000);
-release:
-	nvm->ops.release(hw);
-
 	return ret_val;
 }
 
-- 
1.7.11.7

^ permalink raw reply related

* [net-next 01/15] e1000e: SerDes autoneg flow control
From: Jeff Kirsher @ 2013-01-11 10:23 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1357899831-4168-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

Enables flow control to be set in SerDes autoneg mode. This is what is
done for copper, but relies on a different set of register/bit checks
since this is all done within the Mac registers.

Remove inapplicable comment in defines.h

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/defines.h |   6 +-
 drivers/net/ethernet/intel/e1000e/hw.h      |   4 +
 drivers/net/ethernet/intel/e1000e/mac.c     | 125 ++++++++++++++++++++++++++++
 3 files changed, 132 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index 02a12b6..2073532 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -241,9 +241,9 @@
 #define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
 #define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
 
-/* Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
+#define E1000_PCS_LCTL_FORCE_FCTRL	0x80
+
+#define E1000_PCS_LSTS_AN_COMPLETE	0x10000
 
 /* Device Status */
 #define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index cf21777..06239fe 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -191,6 +191,10 @@ enum e1e_registers {
 	E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */
 	E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */
 	E1000_ICRXOC   = 0x04124, /* Irq Cause Receiver Overrun Count */
+	E1000_PCS_LCTL = 0x04208, /* PCS Link Control - RW */
+	E1000_PCS_LSTAT = 0x0420C, /* PCS Link Status - RO */
+	E1000_PCS_ANADV = 0x04218, /* AN advertisement - RW */
+	E1000_PCS_LPAB = 0x0421C, /* Link Partner Ability - RW */
 	E1000_RXCSUM   = 0x05000, /* Rx Checksum Control - RW */
 	E1000_RFCTL    = 0x05008, /* Receive Filter Control */
 	E1000_MTA      = 0x05200, /* Multicast Table Array - RW Array */
diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c
index 54d9daf..0fa4c06 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.c
+++ b/drivers/net/ethernet/intel/e1000e/mac.c
@@ -1021,6 +1021,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
 {
 	struct e1000_mac_info *mac = &hw->mac;
 	s32 ret_val = 0;
+	u32 pcs_status_reg, pcs_adv_reg, pcs_lp_ability_reg, pcs_ctrl_reg;
 	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
 	u16 speed, duplex;
 
@@ -1185,6 +1186,130 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
 		}
 	}
 
+	/* Check for the case where we have SerDes media and auto-neg is
+	 * enabled.  In this case, we need to check and see if Auto-Neg
+	 * has completed, and if so, how the PHY and link partner has
+	 * flow control configured.
+	 */
+	if ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
+	    mac->autoneg) {
+		/* Read the PCS_LSTS and check to see if AutoNeg
+		 * has completed.
+		 */
+		pcs_status_reg = er32(PCS_LSTAT);
+
+		if (!(pcs_status_reg & E1000_PCS_LSTS_AN_COMPLETE)) {
+			e_dbg("PCS Auto Neg has not completed.\n");
+			return ret_val;
+		}
+
+		/* The AutoNeg process has completed, so we now need to
+		 * read both the Auto Negotiation Advertisement
+		 * Register (PCS_ANADV) and the Auto_Negotiation Base
+		 * Page Ability Register (PCS_LPAB) to determine how
+		 * flow control was negotiated.
+		 */
+		pcs_adv_reg = er32(PCS_ANADV);
+		pcs_lp_ability_reg = er32(PCS_LPAB);
+
+		/* Two bits in the Auto Negotiation Advertisement Register
+		 * (PCS_ANADV) and two bits in the Auto Negotiation Base
+		 * Page Ability Register (PCS_LPAB) determine flow control
+		 * for both the PHY and the link partner.  The following
+		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+		 * 1999, describes these PAUSE resolution bits and how flow
+		 * control is determined based upon these settings.
+		 * NOTE:  DC = Don't Care
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
+		 *   0   |    1    |   0   |   DC    | e1000_fc_none
+		 *   0   |    1    |   1   |    0    | e1000_fc_none
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 *   1   |    0    |   0   |   DC    | e1000_fc_none
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *   1   |    1    |   0   |    0    | e1000_fc_none
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 *
+		 * Are both PAUSE bits set to 1?  If so, this implies
+		 * Symmetric Flow Control is enabled at both ends.  The
+		 * ASM_DIR bits are irrelevant per the spec.
+		 *
+		 * For Symmetric Flow Control:
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *
+		 */
+		if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
+		    (pcs_lp_ability_reg & E1000_TXCW_PAUSE)) {
+			/* Now we need to check if the user selected Rx ONLY
+			 * of pause frames.  In this case, we had to advertise
+			 * FULL flow control because we could not advertise Rx
+			 * ONLY. Hence, we must now check to see if we need to
+			 * turn OFF the TRANSMISSION of PAUSE frames.
+			 */
+			if (hw->fc.requested_mode == e1000_fc_full) {
+				hw->fc.current_mode = e1000_fc_full;
+				e_dbg("Flow Control = FULL.\n");
+			} else {
+				hw->fc.current_mode = e1000_fc_rx_pause;
+				e_dbg("Flow Control = Rx PAUSE frames only.\n");
+			}
+		}
+		/* For receiving PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 */
+		else if (!(pcs_adv_reg & E1000_TXCW_PAUSE) &&
+			 (pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
+			 (pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
+			 (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_tx_pause;
+			e_dbg("Flow Control = Tx PAUSE frames only.\n");
+		}
+		/* For transmitting PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 */
+		else if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
+			 (pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
+			 !(pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
+			 (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_rx_pause;
+			e_dbg("Flow Control = Rx PAUSE frames only.\n");
+		} else {
+			/* Per the IEEE spec, at this point flow control
+			 * should be disabled.
+			 */
+			hw->fc.current_mode = e1000_fc_none;
+			e_dbg("Flow Control = NONE.\n");
+		}
+
+		/* Now we call a subroutine to actually force the MAC
+		 * controller to use the correct flow control settings.
+		 */
+		pcs_ctrl_reg = er32(PCS_LCTL);
+		pcs_ctrl_reg |= E1000_PCS_LCTL_FORCE_FCTRL;
+		ew32(PCS_LCTL, pcs_ctrl_reg);
+
+		ret_val = e1000e_force_mac_fc(hw);
+		if (ret_val) {
+			e_dbg("Error forcing flow control settings\n");
+			return ret_val;
+		}
+	}
+
 	return 0;
 }
 
-- 
1.7.11.7

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox