Netdev List
 help / color / mirror / Atom feed
* 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: [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: [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: [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: [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

* 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

* [patch] tg3: missing break statement in tg3_get_5720_nvram_info()
From: Dan Carpenter @ 2013-01-11  6:57 UTC (permalink / raw)
  To: Michael Chan
  Cc: Matt Carlson, Grant Likely, Rob Herring, netdev,
	devicetree-discuss, kernel-janitors

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>
---
Only needed in linux-next.

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index bc4d989..642764e 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -13726,8 +13726,10 @@ static void tg3_get_5720_nvram_info(struct tg3 *tp)
 		switch (nvmpinstrp) {
 		case FLASH_5762_EEPROM_HD:
 			nvmpinstrp = FLASH_5720_EEPROM_HD;
+			break;
 		case FLASH_5762_EEPROM_LD:
 			nvmpinstrp = FLASH_5720_EEPROM_LD;
+			break;
 		}
 	}
 

^ permalink raw reply related

* Re: 3.8-rc2/rc3 write() blocked on CLOSE_WAIT TCP socket
From: David Miller @ 2013-01-11  6:49 UTC (permalink / raw)
  To: eric.dumazet
  Cc: normalperson, netdev, mgorman, linux-mm, linux-kernel, riel,
	minchan, akpm, torvalds
In-Reply-To: <1357870727.27446.2988.camel@edumazet-glaptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Thu, 10 Jan 2013 18:18:47 -0800

> [PATCH] tcp: accept RST without ACK flag
> 
> commit c3ae62af8e755 (tcp: should drop incoming frames without ACK flag
> set) added a regression on the handling of RST messages.
> 
> RST should be allowed to come even without ACK bit set. We validate
> the RST by checking the exact sequence, as requested by RFC 793 and 
> 5961 3.2, in tcp_validate_incoming()
> 
> Reported-by: Eric Wong <normalperson@yhbt.net>
> Signed-off-by: Eric Dumazet <edumazet@google.com>

Applied, thanks Eric.

--
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

* Re: [PATCH v2 00/10] Make XPS usable within ixgbe
From: David Miller @ 2013-01-11  6:47 UTC (permalink / raw)
  To: alexander.h.duyck; +Cc: netdev, bhutchings, therbert, ycai, eric.dumazet
In-Reply-To: <20130110184115.29578.85768.stgit@ahduyck-cp1.jf.intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>
Date: Thu, 10 Jan 2013 10:56:03 -0800

> The following patch series makes it so that the ixgbe driver can support
> ATR even when the number of queues is less than the number of CPUs.  To do
> this I have updated the kernel to support letting drivers set their own XPS
> configuration.  To do this it was necessary to move the code out of the
> sysfs specific code and into the dev specific regions.
> 
> It has been almost 6 months since the last time I released these patches.  I
> have been meaning to get back to them but I just haven't had a chance to get
> this work done until recently.
> 
> Only the core net patches are meant for acceptance at this time.  I will
> submit the ixgbe patches through Jeff Kirsher's tree.  For this reason I have
> tagged the ixgbe related patches as RFC.

Patches 1-5 look fine, all applied, thanks.

^ permalink raw reply

* [PATCH V4 2/2] virtio-net: reset virtqueue affinity when doing cpu hotplug
From: Wanlong Gao @ 2013-01-11  5:56 UTC (permalink / raw)
  To: linux-kernel; +Cc: Michael S. Tsirkin, netdev, virtualization, Eric Dumazet
In-Reply-To: <1357883793-15199-1-git-send-email-gaowanlong@cn.fujitsu.com>

Add a cpu notifier to virtio-net, so that we can reset the
virtqueue affinity if the cpu hotplug happens. It improve
the performance through enabling or disabling the virtqueue
affinity after doing cpu hotplug.

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>
---
 drivers/net/virtio_net.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index ca17a58..e0b1f25 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -26,6 +26,7 @@
 #include <linux/scatterlist.h>
 #include <linux/if_vlan.h>
 #include <linux/slab.h>
+#include <linux/cpu.h>
 
 static int napi_weight = 128;
 module_param(napi_weight, int, 0444);
@@ -126,6 +127,9 @@ struct virtnet_info {
 
 	/* Per-cpu variable to show the mapping from CPU to virtqueue */
 	int __percpu *vq_index;
+
+	/* CPU hot plug notifier */
+	struct notifier_block nb;
 };
 
 struct skb_vnet_hdr {
@@ -1058,6 +1062,23 @@ static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
 	}
 }
 
+static int virtnet_cpu_callback(struct notifier_block *nfb,
+			        unsigned long action, void *hcpu)
+{
+	struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
+	switch(action) {
+	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
+	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
+		virtnet_set_affinity(vi, true);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
 static void virtnet_get_ringparam(struct net_device *dev,
 				struct ethtool_ringparam *ring)
 {
@@ -1527,6 +1548,13 @@ static int virtnet_probe(struct virtio_device *vdev)
 		}
 	}
 
+	vi->nb.notifier_call = &virtnet_cpu_callback;
+	err = register_hotcpu_notifier(&vi->nb);
+	if (err) {
+		pr_debug("virtio_net: registering cpu notifier failed\n");
+		goto free_recv_bufs;
+	}
+
 	/* Assume link up if device can't report link status,
 	   otherwise get link status from config. */
 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1573,6 +1601,8 @@ static void virtnet_remove(struct virtio_device *vdev)
 {
 	struct virtnet_info *vi = vdev->priv;
 
+	unregister_hotcpu_notifier(&vi->nb);
+
 	/* Prevent config work handler from accessing the device. */
 	mutex_lock(&vi->config_lock);
 	vi->config_enable = false;
-- 
1.8.1

^ permalink raw reply related

* [PATCH V4 1/2] virtio-net: fix the set affinity bug when CPU IDs are not consecutive
From: Wanlong Gao @ 2013-01-11  5:56 UTC (permalink / raw)
  To: linux-kernel; +Cc: Michael S. Tsirkin, netdev, virtualization, Eric Dumazet

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.

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);
 }
-- 
1.8.1

^ permalink raw reply related

* Re: [PATCH] ax88179_178a: ASIX AX88179_178A USB 3.0/2.0 to gigabit ethernet adapter driver
From: David Miller @ 2013-01-11  5:14 UTC (permalink / raw)
  To: ming.lei; +Cc: freddy, linux-kernel, louis, netdev, linux-usb
In-Reply-To: <CACVXFVMdgx1we67poF5yU5pAYRYoA9Ao1EJqQgGBaaORuARFQQ@mail.gmail.com>

From: Ming Lei <ming.lei@canonical.com>
Date: Fri, 11 Jan 2013 10:45:38 +0800

> Cc netdev and usb lists.

That doesn't work for patches, sorry.  It will have to be submitted
freshly and cleanly to the appropriate lists, not as a quoted reply.

^ permalink raw reply

* Re: [PATCH 3.8-rc] tuntap: refuse to re-attach to different tun_struct
From: David Miller @ 2013-01-11  5:12 UTC (permalink / raw)
  To: jasowang; +Cc: stefanha, mst, netdev, linux-kernel
In-Reply-To: <50EF6AF0.1020005@redhat.com>

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.

^ permalink raw reply

* Re: [PATCH 0/3] ixgbe: request_firmware for configuration parameters
From: Shannon Nelson @ 2013-01-11  3:55 UTC (permalink / raw)
  To: netdev; +Cc: davem, dwmw2, jeffrey.t.kirsher, linux-kernel
In-Reply-To: <20130111020046.15463.72333.stgit@starfish.jf.intel.com>

On Thu, Jan 10, 2013 at 6:02 PM, Shannon Nelson
<shannon.nelson@intel.com> wrote:
[...]
>
> In these RFC patches for ixgbe,
>

Yeah, these should have the "RFC" in the Subject line.  Sorry about that.
sln

-- 
==============================================
Mr. Shannon Nelson         Parents can't afford to be squeamish.

^ permalink raw reply

* Re: [PATCH 1/2] usbnet: allow status interrupt URB to always be active
From: Ming Lei @ 2013-01-11  3:06 UTC (permalink / raw)
  To: Dan Williams
  Cc: Oliver Neukum, Elina Pasheva, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Rory Filer, Phil Sutter
In-Reply-To: <1357349193.19684.3.camel-wKZy7rqYPVb5EHUCmHmTqw@public.gmane.org>

On Sat, Jan 5, 2013 at 9:26 AM, Dan Williams <dcbw-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> On Fri, 2013-01-04 at 23:16 +0100, Oliver Neukum wrote:
>> On Friday 04 January 2013 10:48:16 Dan Williams wrote:
>> > Some drivers (ex sierra_net) need the status interrupt URB
>> > active even when the device is closed, because they receive
>> > custom indications from firmware.  Allow sub-drivers to set
>> > a flag that submits the status interrupt URB on probe and
>> > keeps the URB alive over device open/close.  The URB is still
>> > killed/re-submitted for suspend/resume, as before.
>> >
>> > Signed-off-by: Dan Williams <dcbw-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> > ---
>> > Oliver: alternatively, is there a problem with *always*
>> > submitting the interrupt URB, and then simply not calling
>> > the subdriver's .status function when the netdev is
>> > closed?  That would be a much simpler patch.
>>
>> That is quite radical. We have no idea what a device
>> does when we do not react to a status update. I would
>> much prefer to not take the risk.
>> Besides, we don't use bandwidth if we don't have to.
>
> Ok, so scratch the alternative.  Thus, does the posted patch look like
> the right course of action?
>
> If I wasn't clear enough before, sierra_net needs to listen to the
> status interrupt URB to receive the custom Restart indication as part of
> the driver's device setup.  Thus for sierra_net at least, tying the

I am curious who are interested in the 'custom Restart indication'
information after the interface is closed.

If sierra_net provides ways(such as read registers) to query the
indication event, you can just query the information and setup
the device in driver_info->reset() during device open, so you can
avoid submitting interrupt URB always.

> status interrupt URB submission to device open/close isn't right.

In theory, drivers should support to report its link status
even it is closed, but looks no much actual usage, so guys opt to
submit the interrupt URB only after it is opened.


Thanks,
--
Ming Lei
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: 3.8-rc2/rc3 write() blocked on CLOSE_WAIT TCP socket
From: Eric Wong @ 2013-01-11  2:50 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Miller, netdev, Mel Gorman, linux-mm, linux-kernel,
	Rik van Riel, Minchan Kim, Andrew Morton, Linus Torvalds
In-Reply-To: <1357870727.27446.2988.camel@edumazet-glaptop>

Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Yes, thats definitely the problem, sorry for that.
> 
> 
> [PATCH] tcp: accept RST without ACK flag
> 
> commit c3ae62af8e755 (tcp: should drop incoming frames without ACK flag
> set) added a regression on the handling of RST messages.
> 
> RST should be allowed to come even without ACK bit set. We validate
> the RST by checking the exact sequence, as requested by RFC 793 and 
> 5961 3.2, in tcp_validate_incoming()
> 
> Reported-by: Eric Wong <normalperson@yhbt.net>
> Signed-off-by: Eric Dumazet <edumazet@google.com>

All good here, thanks for the quick turnaround!

Tested-by: Eric Wong <normalperson@yhbt.net>

(I originally thought the FIFOs were part of the problem, so I left
 that in my test case)

--
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

* Re: [PATCH] ax88179_178a: ASIX AX88179_178A USB 3.0/2.0 to gigabit ethernet adapter driver
From: Ming Lei @ 2013-01-11  2:45 UTC (permalink / raw)
  To: freddy; +Cc: davem, linux-kernel, louis, netdev, linux-usb
In-Reply-To: <1357867046-22918-1-git-send-email-freddy@asix.com.tw>

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/Kconfig b/drivers/net/usb/Kconfig
> index ef97621..75af401 100644
> --- a/drivers/net/usb/Kconfig
> +++ b/drivers/net/usb/Kconfig
> @@ -158,6 +158,24 @@ config USB_NET_AX8817X
>           This driver creates an interface named "ethX", where X depends on
>           what other networking devices you have in use.
>
> +config USB_NET_AX88179_178A
> +       tristate "ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet"
> +       depends on USB_USBNET
> +       select CRC32
> +       select PHYLIB
> +       default y
> +       help
> +         This option adds support for ASIX AX88179 based USB 3.0/2.0
> +         to Gigabit Ethernet adapters.
> +
> +         This driver should work with at least the following devices:
> +           * ASIX AX88179
> +           * ASIX AX88178A
> +           * Sitcomm LN-032
> +
> +         This driver creates an interface named "ethX", where X depends on
> +         what other networking devices you have in use.
> +
>  config USB_NET_CDCETHER
>         tristate "CDC Ethernet support (smart devices such as cable modems)"
>         depends on USB_USBNET
> diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
> index 4786913..ce01578 100644
> --- a/drivers/net/usb/Makefile
> +++ b/drivers/net/usb/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_RTL8150)       += rtl8150.o
>  obj-$(CONFIG_USB_HSO)          += hso.o
>  obj-$(CONFIG_USB_NET_AX8817X)  += asix.o
>  asix-y := asix_devices.o asix_common.o ax88172a.o
> +obj-$(CONFIG_USB_NET_AX88179_178A)     += ax88179_178a.o
>  obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
>  obj-$(CONFIG_USB_NET_CDC_EEM)  += cdc_eem.o
>  obj-$(CONFIG_USB_NET_DM9601)   += dm9601.o
> 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
> @@ -0,0 +1,1457 @@
> +/*
> + * ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet Devices
> + *
> + * Copyright (C) 20011-2012 ASIX
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/etherdevice.h>
> +#include <linux/mii.h>
> +#include <linux/usb.h>
> +#include <linux/crc32.h>
> +#include <linux/usb/usbnet.h>
> +
> +
> +#define AX88179_PHY_ID                         0x03
> +#define AX_EEPROM_LEN                          0x100
> +#define AX_MCAST_FILTER_SIZE                   8
> +#define AX_MAX_MCAST                           64
> +#define AX_RX_CHECKSUM                         1
> +#define AX_TX_CHECKSUM                         2
> +#define AX_INT_PPLS_LINK                       BIT(0)
> +#define AX_RXHDR_L4_TYPE_UDP                   1
> +#define AX_RXHDR_L4_TYPE_TCP                   4
> +#define AX_ACCESS_MAC                          0x01
> +#define AX_ACCESS_PHY                          0x02
> +#define AX_ACCESS_EEPROM                       0x04
> +#define AX_ACCESS_EFUSE                                0x05
> +#define AX_PAUSE_WATERLVL_HIGH                 0x54
> +#define AX_PAUSE_WATERLVL_LOW                  0x55
> +
> +#define PHYSICAL_LINK_STATUS                   0x02
> +       #define AX_USB_SS               0x04
> +       #define AX_USB_HS               0x02
> +       #define AX_USB_FS               0x01
> +
> +#define GENERAL_STATUS                         0x03
> +/* Check AX88179 version. UA1:Bit2 = 0,  UA2:Bit2 = 1 */
> +       #define AX_SECLD                0x04
> +
> +#define AX_SROM_ADDR                           0x07
> +#define AX_SROM_CMD                            0x0a
> +       #define EEP_RD                  0x04
> +       #define EEP_BUSY                0x10
> +
> +
> +#define AX_SROM_DATA_LOW                       0x08
> +#define AX_SROM_DATA_HIGH                      0x09
> +
> +#define AX_RX_CTL                              0x0b
> +       #define AX_RX_CTL_DROPCRCERR    0x0100
> +       #define AX_RX_CTL_IPE           0x0200
> +       #define AX_RX_CTL_START         0x0080
> +       #define AX_RX_CTL_AP            0x0020
> +       #define AX_RX_CTL_AM            0x0010
> +       #define AX_RX_CTL_AB            0x0008
> +       #define AX_RX_CTL_AMALL         0x0002
> +       #define AX_RX_CTL_PRO           0x0001
> +       #define AX_RX_CTL_STOP          0x0000
> +
> +#define AX_NODE_ID                             0x10
> +#define AX_MULTI_FILTER_ARRY                   0x16
> +
> +#define AX_MEDIUM_STATUS_MODE                  0x22
> +       #define AX_MEDIUM_GIGAMODE      0x01
> +       #define AX_MEDIUM_FULL_DUPLEX   0x02
> +       #define AX_MEDIUM_ALWAYS_ONE    0x04
> +       #define AX_MEDIUM_RXFLOW_CTRLEN 0x10
> +       #define AX_MEDIUM_TXFLOW_CTRLEN 0x20
> +       #define AX_MEDIUM_RECEIVE_EN    0x100
> +       #define AX_MEDIUM_PS            0x200
> +
> +#define AX_MONITOR_MODE                                0x24
> +       #define AX_MONITOR_MODE_RWLC    0x02
> +       #define AX_MONITOR_MODE_RWMP    0x04
> +       #define AX_MONITOR_MODE_PMEPOL  0x20
> +       #define AX_MONITOR_MODE_PMETYPE 0x40
> +
> +#define AX_GPIO_CTRL                           0x25
> +       #define AX_GPIO_CTRL_GPIO3EN    0x80
> +       #define AX_GPIO_CTRL_GPIO2EN    0x40
> +       #define AX_GPIO_CTRL_GPIO1EN    0x20
> +
> +#define AX_PHYPWR_RSTCTL                       0x26
> +       #define AX_PHYPWR_RSTCTL_BZ     0x0010
> +       #define AX_PHYPWR_RSTCTL_IPRL   0x0020
> +       #define AX_PHYPWR_RSTCTL_AT     0x1000
> +
> +#define AX_RX_BULKIN_QCTRL                     0x2e
> +#define AX_CLK_SELECT                          0x33
> +       #define AX_CLK_SELECT_BCS       0x01
> +       #define AX_CLK_SELECT_ACS       0x02
> +       #define AX_CLK_SELECT_ULR       0x08
> +
> +#define AX_RXCOE_CTL                           0x34
> +       #define AX_RXCOE_IP             0x01
> +       #define AX_RXCOE_TCP            0x02
> +       #define AX_RXCOE_UDP            0x04
> +       #define AX_RXCOE_TCPV6          0x20
> +       #define AX_RXCOE_UDPV6          0x40
> +
> +#define AX_TXCOE_CTL                           0x35
> +       #define AX_TXCOE_IP             0x01
> +       #define AX_TXCOE_TCP            0x02
> +       #define AX_TXCOE_UDP            0x04
> +       #define AX_TXCOE_TCPV6          0x20
> +       #define AX_TXCOE_UDPV6          0x40
> +
> +#define AX_LEDCTRL                             0x73
> +
> +#define GMII_PHY_CONTROL                       0x00
> +       #define GMII_CONTROL_1000MB     0x0040
> +       #define GMII_CONTROL_ENAUTO     0x1000
> +       #define GMII_CONTROL_START_AUTO 0x0200
> +       #define GMII_CONTROL_FULLDUPLEX 0x0100
> +
> +#define GMII_PHY_PHYSR                         0x11
> +       #define GMII_PHY_PHYSR_SMASK    0xc000
> +       #define GMII_PHY_PHYSR_GIGA     0x8000
> +       #define GMII_PHY_PHYSR_100      0x4000
> +       #define GMII_PHY_PHYSR_FULL     0x2000
> +       #define GMII_PHY_PHYSR_LINK     0x400
> +
> +#define GMII_LED_ACTIVE                                0x1a
> +       #define GMII_LED_ACTIVE_MASK    0xff8fd
> +       #define GMII_LED0_ACTIVE        BIT(4)
> +       #define GMII_LED1_ACTIVE        BIT(5)
> +       #define GMII_LED2_ACTIVE        BIT(6)
> +
> +#define GMII_LED_LINK                          0x1c
> +       #define GMII_LED_LINK_MASK      0xf888
> +
> +       #define GMII_LED0_LINK_10       BIT(0)
> +       #define GMII_LED0_LINK_100      BIT(1)
> +       #define GMII_LED0_LINK_1000     BIT(2)
> +       #define GMII_LED1_LINK_10       BIT(4)
> +       #define GMII_LED1_LINK_100      BIT(5)
> +       #define GMII_LED1_LINK_1000     BIT(6)
> +       #define GMII_LED2_LINK_10       BIT(8)
> +       #define GMII_LED2_LINK_100      BIT(9)
> +       #define GMII_LED2_LINK_1000     BIT(10)
> +
> +       #define LED0_ACTIVE             BIT(0)
> +       #define LED0_LINK_10            BIT(1)
> +       #define LED0_LINK_100           BIT(2)
> +       #define LED0_LINK_1000          BIT(3)
> +       #define LED0_FD                 BIT(4)
> +       #define LED0_USB3_MASK          0x001f
> +
> +       #define LED1_ACTIVE             BIT(5)
> +       #define LED1_LINK_10            BIT(6)
> +       #define LED1_LINK_100           BIT(7)
> +       #define LED1_LINK_1000          BIT(8)
> +       #define LED1_FD                 BIT(9)
> +       #define LED1_USB3_MASK          0x03e0
> +
> +       #define LED2_ACTIVE             BIT(10)
> +       #define LED2_LINK_1000          BIT(13)
> +       #define LED2_LINK_100           BIT(12)
> +       #define LED2_LINK_10            BIT(11)
> +       #define LED2_FD                 BIT(14)
> +       #define LED_VALID               BIT(15)
> +       #define LED2_USB3_MASK          0x7c00
> +
> +#define GMII_PHYPAGE                           0x1e
> +#define GMII_PHY_PAGE_SELECT                   0x1f
> +       #define GMII_PHY_PGSEL_EXT      0x0007
> +       #define GMII_PHY_PGSEL_PAGE0    0X0000
> +
> +struct ax88179_data {
> +       u16 rxctl;
> +};
> +
> +struct ax88179_int_data {
> +       u16 res1;
> +       u8 link;
> +       u16 res2;
> +       u8 status;
> +       u16 res3;
> +} __packed;
> +
> +struct {unsigned char ctrl, timer_l, timer_h, size, ifg; }
> +AX88179_BULKIN_SIZE[] =        {
> +       {7, 0xa3, 0,    0x14, 0xff},
> +       {7, 0x1e, 5,    0x18, 0xff},
> +       {7, 0xae, 7,    0x18, 0xff},
> +       {7, 0xcc, 0x4c, 0x18, 8},
> +};
> +
> +struct ax88179_rx_pkt_header {
> +
> +       u8      l4_csum_err:1,
> +               l3_csum_err:1,
> +               l4_type:3,
> +               l3_type:2,
> +               ce:1;
> +
> +       u8      vlan_ind:3,
> +               rx_ok:1,
> +               pri:3,
> +               bmc:1;
> +
> +       u16     len:13,
> +               crc:1,
> +               mii:1,
> +               drop:1;
> +
> +} __packed;
> +
> +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);
> +}
> +
> +static void ax88179_status(struct usbnet *dev, struct urb *urb)
> +{
> +       struct ax88179_int_data *event;
> +       int link;
> +
> +       if (urb->actual_length < 8)
> +               return;
> +
> +       event = urb->transfer_buffer;
> +       link = event->link & AX_INT_PPLS_LINK;
> +       if (netif_carrier_ok(dev->net) != link) {
> +               if (link)
> +                       usbnet_defer_kevent(dev, EVENT_LINK_RESET);
> +               else
> +                       netif_carrier_off(dev->net);
> +               netdev_info(dev->net, "ax8817X - Link status is: %d\n", link);
> +       }
> +}
> +
> +static int ax88179_mdio_read(struct net_device *netdev, int phy_id, int loc)
> +{
> +       struct usbnet *dev = netdev_priv(netdev);
> +       __u16 *res;
> +       u16 ret;
> +
> +       res = kmalloc(2, GFP_ATOMIC);

You needn't to allocate several bytes just for transferring one command
any more since usbnet_{read|write}_cmd() has handled that already,
so one simple stack variable is OK.

Also GFP_ATOMIC should be changed to GFP_KERNEL.

> +       if (!res)
> +               return 0;
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, res);
> +
> +       ret = *res & 0xffff;
> +       kfree(res);
> +
> +       return le16_to_cpu(ret);
> +}
> +
> +static void
> +ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
> +{
> +       struct usbnet *dev = netdev_priv(netdev);
> +       __le16 *res;
> +
> +       res = kmalloc(2, GFP_ATOMIC);

Same with above.

> +       if (!res)
> +               return;
> +
> +       *res = cpu_to_le16(val);
> +
> +       ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, res);
> +
> +       kfree(res);
> +}
> +
> +static int ax88179_suspend(struct usb_interface *intf, pm_message_t message)
> +{
> +       struct usbnet *dev = usb_get_intfdata(intf);
> +       u16 *tmp16;
> +
> +       usbnet_suspend(intf, message);
> +
> +       tmp16 = kmalloc(2, GFP_KERNEL);

Same with above.

> +       if (!tmp16)
> +               return 0;
> +
> +       /* Disable RX path */
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                               AX_MEDIUM_STATUS_MODE, 2, 2, tmp16);
> +       *tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                               AX_MEDIUM_STATUS_MODE, 2, 2, tmp16);
> +
> +       /* Force bulk-in zero length */
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
> +       *tmp16 |= AX_PHYPWR_RSTCTL_BZ | AX_PHYPWR_RSTCTL_IPRL;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
> +
> +       /* change clock */
> +       *tmp16 = 0;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp16);
> +
> +       /* Configure RX control register => stop operation */
> +       *tmp16 = AX_RX_CTL_STOP;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);

All the above ax88179_{write|read}_cmd in PM callback should be converted
to its _nopm version, see example in drivers/net/usb/smsc95xx.c. Otherwise,
deadlock will be caused during runtime PM.

> +       kfree(tmp16);
> +       return 0;
> +}
> +
> +/* This function is used to enable the autodetach function. */
> +/* This function is determined by offset 0x43 of EEPROM */
> +static int ax88179_auto_detach(struct usbnet *dev, int flags)
> +{
> +       u16 *tmp;
> +
> +       tmp = kmalloc(2, flags);
> +       if (!tmp)
> +               return -ENOMEM;
> +
> +       if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM, 0x43, 1, 2, tmp) < 0) {
> +               kfree(tmp);
> +               return 0;
> +       }
> +
> +       if ((*tmp == 0xFFFF) || (!(*tmp & 0x0100))) {
> +               kfree(tmp);
> +               return 0;
> +       }
> +
> +       /* Enable Auto Detach bit */
> +       *tmp = 0;
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
> +       *tmp |= AX_CLK_SELECT_ULR;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp);
> +       *tmp |= AX_PHYPWR_RSTCTL_AT;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp);
> +       kfree(tmp);
> +
> +       return 0;
> +}

Considered that ax88179_auto_detach() is called in both non-PM and
PM path, so it is better to pass one 'in_pm' parameter to support the
two cases, see example of smsc95xx_start_rx_path().

> +
> +static int ax88179_resume(struct usb_interface *intf)
> +{
> +       struct usbnet *dev = usb_get_intfdata(intf);
> +       u16 *tmp16;
> +
> +       tmp16 = kmalloc(2, GFP_KERNEL);

Same with above.

> +       if (!tmp16)
> +               return usbnet_resume(intf);
> +
> +       netif_carrier_off(dev->net);
> +
> +       /* Power up ethernet PHY */
> +       *tmp16 = 0;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
> +       udelay(1000);
> +       *tmp16 = AX_PHYPWR_RSTCTL_IPRL;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
> +       msleep(200);
> +
> +       /* Ethernet PHY Auto Detach*/
> +       ax88179_auto_detach(dev, GFP_ATOMIC);
> +
> +       /* enable clock */
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC,  AX_CLK_SELECT, 1, 1, tmp16);
> +       *tmp16 |= AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp16);
> +       msleep(100);
> +
> +       /* Configure RX control register => start operation */
> +       *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
> +                               AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);

All the above ax88179_{write|read}_cmd in PM callback should be converted
to its _nopm version, see example in drivers/net/usb/smsc95xx.c. Otherwise,
deadlock will be caused during runtime PM.

> +
> +       kfree(tmp16);
> +       return usbnet_resume(intf);
> +}
> +
> +static void
> +ax88179_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
> +{
> +       struct usbnet *dev = netdev_priv(net);
> +       u8 *opt;
> +
> +       wolinfo->supported = 0;
> +       wolinfo->wolopts = 0;
> +
> +       opt = kmalloc(1, GFP_KERNEL);

Same with above.

> +       if (!opt)
> +               return;
> +
> +       if (ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                               AX_MONITOR_MODE, 1, 1, opt) < 0) {
> +               kfree(opt);
> +               return;
> +       }
> +
> +       wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
> +
> +       if (*opt & AX_MONITOR_MODE_RWLC)
> +               wolinfo->wolopts |= WAKE_PHY;
> +       if (*opt & AX_MONITOR_MODE_RWMP)
> +               wolinfo->wolopts |= WAKE_MAGIC;
> +
> +       kfree(opt);
> +}
> +
> +static int
> +ax88179_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
> +{
> +       struct usbnet *dev = netdev_priv(net);
> +       u8 *opt;
> +
> +       opt = kmalloc(1, GFP_KERNEL);

Same with above.

> +       if (!opt)
> +               return -ENOMEM;
> +
> +       *opt = 0;
> +       if (ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                               AX_MONITOR_MODE, 1, 1, opt) < 0) {
> +               kfree(opt);
> +               return 0;
> +       }
> +
> +       if (wolinfo->wolopts & WAKE_PHY)
> +               *opt |= AX_MONITOR_MODE_RWLC;
> +       else
> +               *opt &= ~AX_MONITOR_MODE_RWLC;
> +
> +       if (wolinfo->wolopts & WAKE_MAGIC)
> +               *opt |= AX_MONITOR_MODE_RWMP;
> +       else
> +               *opt &= ~AX_MONITOR_MODE_RWMP;
> +
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, opt);
> +       kfree(opt);
> +
> +       return 0;
> +}
> +
> +static int ax88179_get_eeprom_len(struct net_device *net)
> +{
> +       return AX_EEPROM_LEN;
> +}
> +
> +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
> +        */
> +       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;
> +}
> +
> +static int ax88179_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
> +{
> +       struct usbnet *dev = netdev_priv(net);
> +       return mii_ethtool_gset(&dev->mii, cmd);
> +}
> +
> +static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
> +{
> +       struct usbnet *dev = netdev_priv(net);
> +       return mii_ethtool_sset(&dev->mii, cmd);
> +}
> +
> +
> +static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
> +{
> +       struct usbnet *dev = netdev_priv(net);
> +       return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
> +}
> +
> +static struct ethtool_ops ax88179_ethtool_ops = {
> +       .get_link               = ethtool_op_get_link,
> +       .get_msglevel           = usbnet_get_msglevel,
> +       .set_msglevel           = usbnet_set_msglevel,
> +       .get_wol                = ax88179_get_wol,
> +       .set_wol                = ax88179_set_wol,
> +       .get_eeprom_len         = ax88179_get_eeprom_len,
> +       .get_eeprom             = ax88179_get_eeprom,
> +       .get_settings           = ax88179_get_settings,
> +       .set_settings           = ax88179_set_settings,
> +       .nway_reset             = usbnet_nway_reset,
> +};
> +
> +static void ax88179_set_multicast(struct net_device *net)
> +{
> +       struct usbnet *dev = netdev_priv(net);
> +       struct ax88179_data *data = (struct ax88179_data *)dev->data;
> +       u8 *m_filter = ((u8 *)dev->data) + 12;
> +       u16 rx_ctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_CTL_IPE);
> +       int mc_count;
> +
> +       mc_count = netdev_mc_count(net);
> +
> +       if (net->flags & IFF_PROMISC) {
> +               rx_ctl |= AX_RX_CTL_PRO;
> +       } else if (net->flags & IFF_ALLMULTI
> +                  || mc_count > AX_MAX_MCAST) {
> +               rx_ctl |= AX_RX_CTL_AMALL;
> +       } else if (mc_count == 0) {
> +               /* just broadcast and directed */
> +       } else {
> +               /* We use the 20 byte dev->data for our 8 byte filter buffer
> +                * to avoid allocating memory that is tricky to free later
> +                */
> +               u32 crc_bits;
> +               struct netdev_hw_addr *ha;
> +               memset(m_filter, 0, AX_MCAST_FILTER_SIZE);
> +               netdev_for_each_mc_addr(ha, net) {
> +                       crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
> +                       *(m_filter + (crc_bits >> 3)) |=
> +                               1 << (crc_bits & 7);
> +               }
> +
> +               ax88179_write_cmd_async(dev, AX_ACCESS_MAC,
> +                       AX_MULTI_FILTER_ARRY, AX_MCAST_FILTER_SIZE,
> +                                       AX_MCAST_FILTER_SIZE, m_filter);
> +
> +               rx_ctl |= AX_RX_CTL_AM;
> +       }
> +
> +       data->rxctl = rx_ctl;
> +       ax88179_write_cmd_async(dev, AX_ACCESS_MAC,
> +                                       AX_RX_CTL, 2, 2, &data->rxctl);
> +}
> +
> +static struct net_device_stats *ax88179_get_stats(struct net_device *net)
> +{
> +       return &net->stats;
> +}
> +
> +static int
> +ax88179_set_features(struct net_device *net, netdev_features_t features)
> +{
> +       u8 *tmp;
> +       struct usbnet *dev = netdev_priv(net);
> +       netdev_features_t changed = net->features ^ features;
> +
> +       tmp = kmalloc(1, GFP_KERNEL);

Same with above.

> +       if (!tmp)
> +               return -ENOMEM;
> +
> +       if (changed & NETIF_F_TSO)
> +               net->features ^= NETIF_F_TSO;
> +
> +       if (changed & NETIF_F_SG)
> +               net->features ^= NETIF_F_SG;
> +
> +       if (changed & NETIF_F_IP_CSUM) {
> +
> +               ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
> +
> +               *tmp ^= AX_TXCOE_TCP | AX_TXCOE_UDP;
> +
> +               ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
> +
> +               net->features ^= NETIF_F_IP_CSUM;
> +       }
> +
> +       if (changed & NETIF_F_IPV6_CSUM) {
> +               ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
> +
> +               *tmp ^= AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
> +
> +               ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
> +
> +               net->features ^= NETIF_F_IPV6_CSUM;
> +       }
> +
> +       if (changed & NETIF_F_RXCSUM) {
> +               ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
> +
> +               *tmp ^= AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
> +                               AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
> +
> +               ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
> +
> +               net->features ^= NETIF_F_RXCSUM;
> +       }
> +
> +       kfree(tmp);
> +
> +       return 0;
> +}
> +
> +static int ax88179_set_mac_addr(struct net_device *net, void *p)
> +{
> +       struct usbnet *dev = netdev_priv(net);
> +       struct sockaddr *addr = p;
> +
> +       memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
> +
> +       /* Set the MAC address */
> +       return ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
> +                                               ETH_ALEN, net->dev_addr);
> +}
> +
> +static const struct net_device_ops ax88179_netdev_ops = {
> +       .ndo_open               = usbnet_open,
> +       .ndo_stop               = usbnet_stop,
> +       .ndo_start_xmit         = usbnet_start_xmit,
> +       .ndo_tx_timeout         = usbnet_tx_timeout,
> +       .ndo_change_mtu         = usbnet_change_mtu,
> +       .ndo_get_stats          = ax88179_get_stats,
> +       .ndo_set_mac_address    = ax88179_set_mac_addr,
> +       .ndo_validate_addr      = eth_validate_addr,
> +       .ndo_do_ioctl           = ax88179_ioctl,
> +       .ndo_set_rx_mode        = ax88179_set_multicast,
> +       .ndo_set_features       = ax88179_set_features,
> +};
> +
> +static int ax88179_check_eeprom(struct usbnet *dev, int flags)
> +{
> +       u8 i;
> +       u8 buf;
> +       u8 *eeprom;
> +       u16 csum, delay = HZ / 10;
> +       unsigned long jtimeout;
> +
> +       eeprom = kmalloc(20, flags);

Same with above, also I am wondering if the 'flags' parameter is needed
since ax88179_write_cmd() should be called only in process context.

> +       if (!eeprom)
> +               return -ENOMEM;
> +
> +       /* Read EEPROM content */
> +       for (i = 0; i < 6; i++) {
> +               buf = i;
> +               if (ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                                       AX_SROM_ADDR, 1, 1, &buf) < 0) {
> +                       kfree(eeprom);
> +                       return -EINVAL;
> +               }
> +
> +               buf = EEP_RD;
> +               if (ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                                       AX_SROM_CMD, 1, 1, &buf) < 0) {
> +                       kfree(eeprom);
> +                       return -EINVAL;
> +               }
> +
> +               jtimeout = jiffies + delay;
> +               do {
> +                       ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                                               AX_SROM_CMD, 1, 1, &buf);
> +
> +                       if (time_after(jiffies, jtimeout)) {
> +                               kfree(eeprom);
> +                               return -EINVAL;
> +                       }
> +               } while (buf & EEP_BUSY);
> +
> +               ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                               AX_SROM_DATA_LOW, 2, 2, eeprom + (i * 2));
> +
> +               if ((i == 0) && (*eeprom == 0xFF)) {
> +                       kfree(eeprom);
> +                       return -EINVAL;
> +               }
> +       }
> +
> +       csum = *(eeprom + 6) + *(eeprom + 7) + *(eeprom + 8) + *(eeprom + 9);
> +       csum = (csum >> 8) + (csum & 0xff);
> +
> +       if ((csum + *(eeprom + 10)) != 0xff) {
> +               kfree(eeprom);
> +               return -EINVAL;
> +       }
> +
> +       kfree(eeprom);
> +       return 0;
> +}
> +
> +static int ax88179_check_efuse(struct usbnet *dev, u16 *ledmode, int flags)
> +{
> +       u8      i;
> +       u8      *efuse;
> +       u16     csum = 0;
> +
> +       efuse = kzalloc(64, flags);

Same with above.

> +       if (!efuse)
> +               return -ENOMEM;
> +
> +       if (ax88179_read_cmd(dev, AX_ACCESS_EFUSE, 0, 64, 64, efuse) < 0) {
> +               kfree(efuse);
> +               return -EINVAL;
> +       }
> +
> +       if (*efuse == 0xFF) {
> +               kfree(efuse);
> +               return -EINVAL;
> +       }
> +
> +       for (i = 0; i < 64; i++)
> +               csum = csum + *(efuse + i);
> +
> +       while (csum > 255)
> +               csum = (csum & 0x00FF) + ((csum >> 8) & 0x00FF);
> +
> +       if (csum != 0xFF) {
> +               kfree(efuse);
> +               return -EINVAL;
> +       }
> +
> +       memcpy((u8 *)ledmode, efuse + 51, 2);
> +       kfree(efuse);
> +       return 0;
> +
> +}
> +
> +static int ax88179_convert_old_led(struct usbnet *dev, u8 efuse, u16 *ledvalue)
> +{
> +       u16 led;
> +
> +       /* Loaded the old eFuse LED Mode */
> +       if (efuse) {
> +               if (ax88179_read_cmd(dev, AX_ACCESS_EFUSE,
> +                                       0x18, 1, 2, &led) < 0)
> +                       return -EINVAL;
> +               led &= 0xFF;
> +       } else {
> +               if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM,
> +                                       0x3C, 1, 2, &led) < 0)
> +                       return -EINVAL;
> +               led >>= 8;
> +       }
> +
> +       switch (led) {
> +       case 0xFF:
> +               led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 |
> +                       LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 |
> +                       LED2_LINK_100 | LED2_LINK_1000 | LED_VALID;
> +               break;
> +       case 0xFE:
> +               led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | LED_VALID;
> +               break;
> +       case 0xFD:
> +               led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 |
> +                       LED2_LINK_10 | LED_VALID;
> +               break;
> +       case 0xFC:
> +               led = LED0_ACTIVE | LED1_ACTIVE | LED1_LINK_1000 | LED2_ACTIVE |
> +                               LED2_LINK_100 | LED2_LINK_10 | LED_VALID;
> +               break;
> +       default:
> +               led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 |
> +                       LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 |
> +                       LED2_LINK_100 | LED2_LINK_1000 | LED_VALID;
> +               break;
> +       }
> +
> +       memcpy((u8 *)ledvalue, &led, 2);
> +       return 0;
> +}
> +
> +static int ax88179_led_setting(struct usbnet *dev, int flags)
> +{
> +       u8 ledfd, value = 0;
> +       u16 tmp, ledact, ledlink, ledvalue = 0, delay = HZ / 10;
> +       unsigned long jtimeout;
> +
> +       /* Check AX88179 version. UA1 or UA2*/
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC, GENERAL_STATUS, 1, 1, &value);
> +
> +       if (!(value & AX_SECLD)) {      /* UA1 */
> +               value = AX_GPIO_CTRL_GPIO3EN | AX_GPIO_CTRL_GPIO2EN |
> +                                       AX_GPIO_CTRL_GPIO1EN;
> +               if (ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                               AX_GPIO_CTRL, 1, 1, &value) < 0)
> +                       return -EINVAL;
> +       }
> +
> +       /* Check EEPROM */
> +       if (!ax88179_check_eeprom(dev, flags)) {
> +               value = 0x42;
> +               if (ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                               AX_SROM_ADDR, 1, 1, &value) < 0)
> +                       return -EINVAL;
> +
> +               value = EEP_RD;
> +               if (ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                               AX_SROM_CMD, 1, 1, &value) < 0)
> +                       return -EINVAL;
> +
> +               jtimeout = jiffies + delay;
> +               do {
> +                       ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                               AX_SROM_CMD, 1, 1, &value);
> +
> +                       if (time_after(jiffies, jtimeout))
> +                               return -EINVAL;
> +               } while (value & EEP_BUSY);
> +
> +               ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                               AX_SROM_DATA_HIGH, 1, 1, &value);
> +               ledvalue = (value << 8);
> +               ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                               AX_SROM_DATA_LOW, 1, 1, &value);
> +               ledvalue |= value;
> +
> +               /* load internal ROM for defaule setting */
> +               if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0))
> +                       ax88179_convert_old_led(dev, 0, &ledvalue);
> +       }
> +
> +       /* Check eFuse */
> +       else if (!ax88179_check_efuse(dev, &ledvalue, flags)) {
> +               if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0))
> +                       ax88179_convert_old_led(dev, 0, &ledvalue);
> +       } else
> +               ax88179_convert_old_led(dev, 0, &ledvalue);
> +
> +       tmp = GMII_PHY_PGSEL_EXT;
> +       ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
> +                                               GMII_PHY_PAGE_SELECT, 2, &tmp);
> +
> +       tmp = 0x2c;
> +       ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
> +                                               GMII_PHYPAGE, 2, &tmp);
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
> +                                               GMII_LED_ACTIVE, 2, &ledact);
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
> +                                               GMII_LED_LINK, 2, &ledlink);
> +
> +       ledact &= GMII_LED_ACTIVE_MASK;
> +       ledlink &= GMII_LED_LINK_MASK;
> +
> +
> +       if (ledvalue & LED0_ACTIVE)
> +               ledact |= GMII_LED0_ACTIVE;
> +
> +       if (ledvalue & LED1_ACTIVE)
> +               ledact |= GMII_LED1_ACTIVE;
> +
> +       if (ledvalue & LED2_ACTIVE)
> +               ledact |= GMII_LED2_ACTIVE;
> +
> +       if (ledvalue & LED0_LINK_10)
> +               ledlink |= GMII_LED0_LINK_10;
> +
> +       if (ledvalue & LED1_LINK_10)
> +               ledlink |= GMII_LED1_LINK_10;
> +
> +       if (ledvalue & LED2_LINK_10)
> +               ledlink |= GMII_LED2_LINK_10;
> +
> +       if (ledvalue & LED0_LINK_100)
> +               ledlink |= GMII_LED0_LINK_100;
> +
> +       if (ledvalue & LED1_LINK_100)
> +               ledlink |= GMII_LED1_LINK_100;
> +
> +       if (ledvalue & LED2_LINK_100)
> +               ledlink |= GMII_LED2_LINK_100;
> +
> +       if (ledvalue & LED0_LINK_1000)
> +               ledlink |= GMII_LED0_LINK_1000;
> +
> +       if (ledvalue & LED1_LINK_1000)
> +               ledlink |= GMII_LED1_LINK_1000;
> +
> +       if (ledvalue & LED2_LINK_1000)
> +               ledlink |= GMII_LED2_LINK_1000;
> +
> +
> +       tmp = ledact;
> +       ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
> +                                               GMII_LED_ACTIVE, 2, &tmp);
> +
> +       tmp = ledlink;
> +       ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
> +                                               GMII_LED_LINK, 2, &tmp);
> +
> +       tmp = GMII_PHY_PGSEL_PAGE0;
> +       ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
> +                                               GMII_PHY_PAGE_SELECT, 2, &tmp);
> +
> +       /* LED full duplex setting */
> +       ledfd = 0;
> +       if (ledvalue & LED0_FD)
> +               ledfd |= 0x01;
> +       else if ((ledvalue & LED0_USB3_MASK) == 0)
> +               ledfd |= 0x02;
> +
> +       if (ledvalue & LED1_FD)
> +               ledfd |= 0x04;
> +       else if ((ledvalue & LED1_USB3_MASK) == 0)
> +               ledfd |= 0x08;
> +
> +       if (ledvalue & LED2_FD)
> +               ledfd |= 0x10;
> +       else if ((ledvalue & LED2_USB3_MASK) == 0)
> +               ledfd |= 0x20;
> +
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_LEDCTRL, 1, 1, &ledfd);
> +       return 0;
> +}
> +
> +static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
> +{
> +       void *buf;
> +       u16 *tmp16;
> +       u8 *tmp;
> +       struct ax88179_data *ax179_data =
> +                       (struct ax88179_data *)dev->data;
> +
> +       usbnet_get_endpoints(dev, intf);
> +
> +       buf = kmalloc(6, GFP_KERNEL);

Same with above.

> +       if (!buf) {
> +               netdev_err(dev->net, "Cannot allocate memory for buffer");
> +               return -ENOMEM;
> +       }
> +       tmp16 = (u16 *)buf;
> +       tmp = (u8 *)buf;
> +
> +       memset(ax179_data, 0, sizeof(*ax179_data));
> +
> +       /* Power up ethernet PHY */
> +       *tmp16 = 0;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
> +       *tmp16 = AX_PHYPWR_RSTCTL_IPRL;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
> +       msleep(200);
> +
> +       *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
> +       msleep(100);
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN,
> +                                               dev->net->dev_addr);
> +       memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN);
> +
> +       /* RX bulk configuration */
> +       memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
> +       dev->rx_urb_size = 1024 * 20;
> +
> +       *tmp = 0x34;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
> +
> +       *tmp = 0x52;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                       AX_PAUSE_WATERLVL_HIGH, 1, 1, tmp);
> +
> +       dev->net->hard_header_len += 12;
> +       dev->net->netdev_ops = &ax88179_netdev_ops;
> +       dev->net->ethtool_ops = &ax88179_ethtool_ops;
> +       dev->net->needed_headroom = 8;
> +
> +       /* Initialize MII structure */
> +       dev->mii.dev = dev->net;
> +       dev->mii.mdio_read = ax88179_mdio_read;
> +       dev->mii.mdio_write = ax88179_mdio_write;
> +       dev->mii.phy_id_mask = 0xff;
> +       dev->mii.reg_num_mask = 0xff;
> +       dev->mii.phy_id = 0x03;
> +       dev->mii.supports_gmii = 1;
> +
> +       dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> +                       NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
> +
> +       dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> +                       NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
> +
> +       /* Enable checksum offload */
> +       *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
> +                               AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
> +
> +       *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
> +                               AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
> +
> +       /* Configure RX control register => start operation */
> +       *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
> +                       AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, 0x0b, 2, 2, tmp16);
> +
> +       *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
> +                                               AX_MONITOR_MODE_RWMP;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp);
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp);
> +
> +       /* Configure default medium type => giga */
> +       *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
> +                AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_ALWAYS_ONE |
> +                AX_MEDIUM_FULL_DUPLEX | AX_MEDIUM_GIGAMODE;
> +
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                               AX_MEDIUM_STATUS_MODE, 2, 2, tmp16);
> +
> +       ax88179_led_setting(dev, GFP_KERNEL);
> +
> +       /* Restart autoneg */
> +       mii_nway_restart(&dev->mii);
> +
> +       netif_carrier_off(dev->net);
> +       kfree(buf);
> +       return 0;
> +}
> +
> +static void ax88179_unbind(struct usbnet *dev, struct usb_interface *intf)
> +{
> +       u16 tmp16;
> +
> +       /* Configure RX control register => stop operation */
> +       tmp16 = AX_RX_CTL_STOP;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
> +
> +       tmp16 = 0x0;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                       AX_CLK_SELECT, 1, 1, &tmp16);
> +
> +       /* Power down ethernet PHY */
> +       tmp16 = 0;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                       AX_PHYPWR_RSTCTL, 2, 2, &tmp16);
> +}
> +
> +static void
> +ax88179_rx_checksum(struct sk_buff *skb, struct ax88179_rx_pkt_header *pkt_hdr)
> +{
> +       skb->ip_summed = CHECKSUM_NONE;
> +
> +       /* checksum error bit is set */
> +       if (pkt_hdr->l3_csum_err || pkt_hdr->l4_csum_err)
> +               return;
> +
> +       /* It must be a TCP or UDP packet with a valid checksum */
> +       if ((pkt_hdr->l4_type == AX_RXHDR_L4_TYPE_TCP) ||
> +           (pkt_hdr->l4_type == AX_RXHDR_L4_TYPE_UDP))
> +               skb->ip_summed = CHECKSUM_UNNECESSARY;
> +}
> +
> +static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> +{
> +       struct sk_buff *ax_skb;
> +       int pkt_cnt;
> +       u32 rx_hdr;
> +       u16 hdr_off;
> +       struct ax88179_rx_pkt_header *pkt_hdr;
> +
> +       skb_trim(skb, skb->len - 4);
> +       memcpy(&rx_hdr, skb_tail_pointer(skb), sizeof(rx_hdr));
> +       le32_to_cpus(&rx_hdr);
> +
> +       pkt_cnt = (u16)rx_hdr;
> +       hdr_off = (u16)(rx_hdr >> 16);
> +       pkt_hdr = (struct ax88179_rx_pkt_header *)(skb->data + hdr_off);
> +
> +       while (pkt_cnt--) {
> +
> +               u16 pkt_len;
> +
> +               le32_to_cpus((u32 *)pkt_hdr);
> +               pkt_len = pkt_hdr->len;
> +
> +               /* Check CRC or runt packet */
> +               if (pkt_hdr->crc || pkt_hdr->drop) {
> +                       skb_pull(skb, (pkt_len + 7) & 0xFFF8);
> +                       pkt_hdr++;
> +                       continue;
> +               }
> +
> +               if (pkt_cnt == 0) {
> +                       /* Skip IP alignment psudo header */
> +                       skb_pull(skb, 2);
> +
> +                       skb->len = pkt_len;
> +
> +                       skb_set_tail_pointer(skb, pkt_len);
> +
> +                       skb->truesize = pkt_len + sizeof(struct sk_buff);
> +
> +                       ax88179_rx_checksum(skb, pkt_hdr);
> +
> +                       return 2;
> +               }
> +
> +               ax_skb = skb_clone(skb, GFP_ATOMIC);
> +               if (ax_skb) {
> +                       ax_skb->len = pkt_len;
> +                       ax_skb->data = skb->data + 2;
> +
> +                       skb_set_tail_pointer(ax_skb, pkt_len);
> +
> +                       ax_skb->truesize = pkt_len + sizeof(struct sk_buff);
> +
> +                       ax88179_rx_checksum(ax_skb, pkt_hdr);
> +
> +                       usbnet_skb_return(dev, ax_skb);
> +               } else {
> +                       return 0;
> +               }
> +
> +               skb_pull(skb, (pkt_len + 7) & 0xFFF8);
> +               pkt_hdr++;
> +       }
> +       return 0;
> +}
> +
> +static struct sk_buff *
> +ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
> +{
> +       u32 tx_hdr1, tx_hdr2;
> +       int frame_size = dev->maxpacket;
> +       int mss = skb_shinfo(skb)->gso_size;
> +       int headroom;
> +       int tailroom;
> +
> +       tx_hdr1 = skb->len;
> +       tx_hdr2 = mss;
> +       if (((skb->len + 8) % frame_size) == 0) {
> +               tx_hdr2 |= 0x80008000;  /* Enable padding */
> +               skb->len += 2;
> +       }
> +
> +       skb_linearize(skb);
> +       headroom = skb_headroom(skb);
> +       tailroom = skb_tailroom(skb);
> +
> +       if (!skb_header_cloned(skb) && !skb_cloned(skb) &&
> +                               (headroom + tailroom) >= 8) {
> +               if (headroom < 8) {
> +                       skb->data = memmove(skb->head + 8, skb->data, skb->len);
> +                       skb_set_tail_pointer(skb, skb->len);
> +               }
> +       } else {
> +               struct sk_buff *skb2;
> +               skb2 = skb_copy_expand(skb, 8, 0, flags);
> +               dev_kfree_skb_any(skb);
> +               skb = skb2;
> +               if (!skb)
> +                       return NULL;
> +       }
> +
> +       skb_push(skb, 4);
> +       cpu_to_le32s(&tx_hdr2);
> +
> +       skb_copy_to_linear_data(skb, &tx_hdr2, 4);
> +
> +       skb_push(skb, 4);
> +       cpu_to_le32s(&tx_hdr1);
> +
> +       skb_copy_to_linear_data(skb, &tx_hdr1, 4);
> +
> +       return skb;
> +}
> +
> +static int ax88179_link_reset(struct usbnet *dev)
> +{
> +       struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
> +       u8 *tmp, link_sts;
> +       u16 mode, tmp16, delay = HZ / 10;
> +       u32 tmp32 = 0x40000000;
> +       unsigned long jtimeout;
> +
> +       jtimeout = jiffies + delay;
> +
> +       while (tmp32 & 0x40000000) {
> +               mode = 0;
> +               ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                               AX_RX_CTL, 2, 2, &mode);
> +               ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                               AX_RX_CTL, 2, 2, &ax179_data->rxctl);
> +
> +               /*link up, check the usb device control TX FIFO full or empty*/
> +               ax88179_read_cmd(dev, 0x81, 0x8c, 0, 4, &tmp32);
> +
> +               if (time_after(jiffies, jtimeout))
> +                       return 0;
> +       }
> +
> +       mode = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
> +                  AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_ALWAYS_ONE;
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                       PHYSICAL_LINK_STATUS, 1, 1, &link_sts);
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
> +                                       GMII_PHY_PHYSR, 2, &tmp16);
> +
> +       tmp = kmalloc(5, GFP_KERNEL);

Same with above.

> +       if (!tmp)
> +               return -ENOMEM;
> +
> +       if (!(tmp16 & GMII_PHY_PHYSR_LINK)) {
> +               kfree(tmp);
> +               return 0;
> +       } else if (GMII_PHY_PHYSR_GIGA == (tmp16 & GMII_PHY_PHYSR_SMASK)) {
> +               mode |= AX_MEDIUM_GIGAMODE;
> +               if (link_sts & AX_USB_SS)
> +                       memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
> +               else if (link_sts & AX_USB_HS)
> +                       memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5);
> +               else
> +                       memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
> +       } else if (GMII_PHY_PHYSR_100 == (tmp16 & GMII_PHY_PHYSR_SMASK)) {
> +               mode |= AX_MEDIUM_PS;
> +               if (link_sts & (AX_USB_SS | AX_USB_HS))
> +                       memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5);
> +               else
> +                       memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
> +       } else {
> +               memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
> +       }
> +
> +       /* RX bulk configuration */
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
> +
> +       if (tmp16 & GMII_PHY_PHYSR_FULL)
> +               mode |= AX_MEDIUM_FULL_DUPLEX;
> +
> +       dev->rx_urb_size = (1024 * (*(tmp + 3)));
> +
> +       mode |= 0x08;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +               AX_MEDIUM_STATUS_MODE, 2, 2, &mode);
> +
> +       netif_carrier_on(dev->net);
> +       kfree(tmp);
> +       return 0;
> +}
> +
> +static int ax88179_reset(struct usbnet *dev)
> +{
> +       void *buf;
> +       u16 *tmp16;
> +       u8 *tmp;
> +
> +       buf = kmalloc(6, GFP_KERNEL);
> +       if (!buf)
> +               return -ENOMEM;
> +
> +       tmp16 = (u16 *)buf;
> +       tmp = (u8 *)buf;
> +
> +       /* Power up ethernet PHY */
> +       *tmp16 = 0;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
> +       *tmp16 = AX_PHYPWR_RSTCTL_IPRL;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
> +       msleep(200);
> +       *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
> +       msleep(100);
> +
> +       /* Ethernet PHY Auto Detach*/
> +       ax88179_auto_detach(dev, GFP_KERNEL);
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
> +                                               ETH_ALEN, dev->net->dev_addr);
> +       memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN);
> +
> +       /* RX bulk configuration */
> +       memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
> +
> +       dev->rx_urb_size = 1024 * 20;
> +
> +       *tmp = 0x34;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
> +
> +       *tmp = 0x52;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                               AX_PAUSE_WATERLVL_HIGH, 1, 1, tmp);
> +
> +       dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> +                       NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
> +
> +       dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> +                       NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
> +
> +       /* Enable checksum offload */
> +       *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
> +                               AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
> +
> +       *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
> +                               AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
> +
> +       /* Configure RX control register => start operation */
> +       *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
> +                       AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, 0x0b, 2, 2, tmp16);
> +
> +       *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
> +                                               AX_MONITOR_MODE_RWMP;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp);
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp);
> +
> +       /* Configure default medium type => giga */
> +       *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
> +                AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_ALWAYS_ONE |
> +                AX_MEDIUM_FULL_DUPLEX | AX_MEDIUM_GIGAMODE;
> +
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                       AX_MEDIUM_STATUS_MODE, 2, 2, tmp16);
> +
> +       ax88179_led_setting(dev, GFP_KERNEL);
> +
> +       /* Restart autoneg */
> +       mii_nway_restart(&dev->mii);
> +
> +       netif_carrier_off(dev->net);
> +
> +       kfree(buf);
> +
> +       return 0;
> +}
> +
> +static int ax88179_stop(struct usbnet *dev)
> +{
> +       u16 tmp16;
> +
> +       ax88179_read_cmd(dev, AX_ACCESS_MAC,
> +                       AX_MEDIUM_STATUS_MODE, 2, 2, &tmp16);
> +       tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
> +       ax88179_write_cmd(dev, AX_ACCESS_MAC,
> +                       AX_MEDIUM_STATUS_MODE, 2, 2, &tmp16);
> +
> +       return 0;
> +}
> +
> +static const struct driver_info ax88179_info = {
> +       .description = "ASIX AX88179 USB 3.0 Gigibit Ethernet",
> +       .bind = ax88179_bind,
> +       .unbind = ax88179_unbind,
> +       .status = ax88179_status,
> +       .link_reset = ax88179_link_reset,
> +       .reset = ax88179_reset,
> +       .stop = ax88179_stop,
> +       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
> +       .rx_fixup = ax88179_rx_fixup,
> +       .tx_fixup = ax88179_tx_fixup,
> +};
> +
> +static const struct driver_info ax88178a_info = {
> +       .description = "ASIX AX88178A USB 2.0 Gigibit Ethernet",
> +       .bind = ax88179_bind,
> +       .unbind = ax88179_unbind,
> +       .status = ax88179_status,
> +       .link_reset = ax88179_link_reset,
> +       .reset = ax88179_reset,
> +       .stop = ax88179_stop,
> +       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
> +       .rx_fixup = ax88179_rx_fixup,
> +       .tx_fixup = ax88179_tx_fixup,
> +};
> +
> +static const struct driver_info sitecom_info = {
> +       .description = "Sitecom USB 3.0 to Gigabit Adapter",
> +       .bind = ax88179_bind,
> +       .unbind = ax88179_unbind,
> +       .status = ax88179_status,
> +       .link_reset = ax88179_link_reset,
> +       .reset = ax88179_reset,
> +       .stop = ax88179_stop,
> +       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
> +       .rx_fixup = ax88179_rx_fixup,
> +       .tx_fixup = ax88179_tx_fixup,
> +};
> +
> +static const struct usb_device_id products[] = {
> +{
> +       /* ASIX AX88179 10/100/1000 */
> +       USB_DEVICE(0x0b95, 0x1790),
> +       .driver_info = (unsigned long)&ax88179_info,
> +}, {
> +       /* ASIX AX88178A 10/100/1000 */
> +       USB_DEVICE(0x0b95, 0x178a),
> +       .driver_info = (unsigned long)&ax88178a_info,
> +}, {
> +       /* Sitecom USB 3.0 to Gigabit Adapter */
> +       USB_DEVICE(0x0df6, 0x0072),
> +       .driver_info = (unsigned long) &sitecom_info,
> +},
> +       { },
> +};
> +MODULE_DEVICE_TABLE(usb, products);
> +
> +static struct usb_driver asix_driver = {
> +       .name =         "ax88179_178a",
> +       .id_table =     products,
> +       .probe =        usbnet_probe,
> +       .suspend =      ax88179_suspend,
> +       .resume =       ax88179_resume,
> +       .disconnect =   usbnet_disconnect,
> +};
> +
> +static int __init asix_init(void)
> +{
> +       return usb_register(&asix_driver);
> +}
> +module_init(asix_init);
> +
> +static void __exit asix_exit(void)
> +{
> +       usb_deregister(&asix_driver);
> +}
> +module_exit(asix_exit);
> +
> +MODULE_DESCRIPTION("ASIX AX88179/178A based USB 3.0/2.0 Gigabit Ethernet Devices");
> +MODULE_LICENSE("GPL");

Thanks,
--
Ming Lei

^ permalink raw reply

* Re: 3.8-rc2/rc3 write() blocked on CLOSE_WAIT TCP socket
From: Neal Cardwell @ 2013-01-11  2:40 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Eric Wong, David Miller, Netdev, Mel Gorman, linux-mm, LKML,
	Rik van Riel, Minchan Kim, Andrew Morton, Linus Torvalds
In-Reply-To: <1357870727.27446.2988.camel@edumazet-glaptop>

On Thu, Jan 10, 2013 at 9:18 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> On Thu, 2013-01-10 at 18:01 -0800, Eric Dumazet wrote:
>
>> Hmm, it might be commit c3ae62af8e755ea68380fb5ce682e60079a4c388
>> tcp: should drop incoming frames without ACK flag set
>>
>> It seems RST should be allowed to not have ACK set.
>>
>> I'll send a fix, thanks !
>
> Yes, thats definitely the problem, sorry for that.
>
>
> [PATCH] tcp: accept RST without ACK flag
>
> commit c3ae62af8e755 (tcp: should drop incoming frames without ACK flag
> set) added a regression on the handling of RST messages.
>
> RST should be allowed to come even without ACK bit set. We validate
> the RST by checking the exact sequence, as requested by RFC 793 and
> 5961 3.2, in tcp_validate_incoming()
>
> Reported-by: Eric Wong <normalperson@yhbt.net>
> Signed-off-by: Eric Dumazet <edumazet@google.com>

Acked-by: Neal Cardwell <ncardwell@google.com>

neal

^ permalink raw reply

* Re: [tcpdump-workers] [PATCH net 1/2] net: dev_queue_xmit_nit: fix skb->vlan_tci field value
From: Paul Pearce @ 2013-01-11  2:37 UTC (permalink / raw)
  To: Michael Richardson
  Cc: Eric Dumazet, Ani Sinha, Jiri Pirko, netdev, edumazet,
	tcpdump-workers, dborkman
In-Reply-To: <32117.1357868869@sandelman.ca>

>> 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_.

> 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.
-Paul

^ permalink raw reply

* Re: 3.8-rc2/rc3 write() blocked on CLOSE_WAIT TCP socket
From: Eric Dumazet @ 2013-01-11  2:18 UTC (permalink / raw)
  To: Eric Wong, David Miller
  Cc: netdev, Mel Gorman, linux-mm, linux-kernel, Rik van Riel,
	Minchan Kim, Andrew Morton, Linus Torvalds
In-Reply-To: <1357869675.27446.2962.camel@edumazet-glaptop>

From: Eric Dumazet <edumazet@google.com>

On Thu, 2013-01-10 at 18:01 -0800, Eric Dumazet wrote:

> Hmm, it might be commit c3ae62af8e755ea68380fb5ce682e60079a4c388
> tcp: should drop incoming frames without ACK flag set
> 
> It seems RST should be allowed to not have ACK set.
> 
> I'll send a fix, thanks !

Yes, thats definitely the problem, sorry for that.


[PATCH] tcp: accept RST without ACK flag

commit c3ae62af8e755 (tcp: should drop incoming frames without ACK flag
set) added a regression on the handling of RST messages.

RST should be allowed to come even without ACK bit set. We validate
the RST by checking the exact sequence, as requested by RFC 793 and 
5961 3.2, in tcp_validate_incoming()

Reported-by: Eric Wong <normalperson@yhbt.net>
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/ipv4/tcp_input.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 38e1184..0905997 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5541,7 +5541,7 @@ slow_path:
 	if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
 		goto csum_error;
 
-	if (!th->ack)
+	if (!th->ack && !th->rst)
 		goto discard;
 
 	/*
@@ -5986,7 +5986,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			goto discard;
 	}
 
-	if (!th->ack)
+	if (!th->ack && !th->rst)
 		goto discard;
 
 	if (!tcp_validate_incoming(sk, skb, th, 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

* linux-next: build failure after merge of the net-next tree
From: Stephen Rothwell @ 2013-01-11  2:18 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: linux-next, linux-kernel, Greg KH, Sony Chacko, Sritej Velaga,
	Sucheta Chakraborty, Anirban Chakraborty

[-- Attachment #1: Type: text/plain, Size: 2021 bytes --]

Hi all,

After merging the net-next tree, today's linux-next build (x86_64
allmodconfig) failed like this:

drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c:1721:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'qlcnic_probe'
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c:1912:23: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'qlcnic_remove'

Caused by commits 7e2cf4feba05 ("qlcnic: change driver hardware interface
mechanism") and 13159183ec7a ("qlcnic: 83xx base driver") from the
net-next tree interacting with commit 54b956b90360 ("Remove __dev*
markings from init.h") from the drover-core.current tree.

I have added the following merge fix patch for today which could be added
directly to the scsi tree (please).

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Fri, 11 Jan 2013 13:15:05 +1100
Subject: [PATCH] qlcnic: remove new __dev* annotations

CONFIG_HOTPLUG is always true now and the __dev* macros have been removed.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index d331313..fb7ac8e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1717,7 +1717,7 @@ int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
 	return 0;
 }
 
-static int __devinit
+static int
 qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct net_device *netdev = NULL;
@@ -1909,7 +1909,7 @@ err_out_disable_pdev:
 	return err;
 }
 
-static void __devexit qlcnic_remove(struct pci_dev *pdev)
+static void qlcnic_remove(struct pci_dev *pdev)
 {
 	struct qlcnic_adapter *adapter;
 	struct net_device *netdev;
-- 
1.7.10.280.gaa39

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related

* linux-next: manual merge of the net-next tree with the net tree
From: Stephen Rothwell @ 2013-01-11  2:03 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: linux-next, linux-kernel, Yuval Mintz, Ariel Elior,
	Eilon Greenstein

[-- Attachment #1: Type: text/plain, Size: 2615 bytes --]

Hi all,

Today's linux-next merge of the net-next tree got a conflict in
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c between commit
4864a16ae69d ("bnx2x: Fix fastpath structures when memory allocation
fails") from the net tree and commit 8ca5e17e58c9 ("bnx2x: Support of PF
driver of a VF acquire request") from the net-next tree.

I fixed it up (see below) and can carry the fix as necessary (no action
is required).

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

diff --cc drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index f771ddf,00706c4..0000000
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@@ -87,30 -85,33 +85,58 @@@ static inline void bnx2x_move_fp(struc
  }
  
  /**
 + * bnx2x_shrink_eth_fp - guarantees fastpath structures stay intact
 + *
 + * @bp:	driver handle
 + * @delta:	number of eth queues which were not allocated
 + */
 +static void bnx2x_shrink_eth_fp(struct bnx2x *bp, int delta)
 +{
 +	int i, cos, old_eth_num = BNX2X_NUM_ETH_QUEUES(bp);
 +
 +	/* Queue pointer cannot be re-set on an fp-basis, as moving pointer
 +	 * backward along the array could cause memory to be overriden
 +	 */
 +	for (cos = 1; cos < bp->max_cos; cos++) {
 +		for (i = 0; i < old_eth_num - delta; i++) {
 +			struct bnx2x_fastpath *fp = &bp->fp[i];
 +			int new_idx = cos * (old_eth_num - delta) + i;
 +
 +			memcpy(&bp->bnx2x_txq[new_idx], fp->txdata_ptr[cos],
 +			       sizeof(struct bnx2x_fp_txdata));
 +			fp->txdata_ptr[cos] = &bp->bnx2x_txq[new_idx];
 +		}
 +	}
 +}
 +
++/**
+  * bnx2x_fill_fw_str - Fill buffer with FW version string.
+  *
+  * @bp:        driver handle
+  * @buf:       character buffer to fill with the fw name
+  * @buf_len:   length of the above buffer
+  *
+  */
+ void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len)
+ {
+ 	if (IS_PF(bp)) {
+ 		u8 phy_fw_ver[PHY_FW_VER_LEN];
+ 
+ 		phy_fw_ver[0] = '\0';
+ 		bnx2x_get_ext_phy_fw_version(&bp->link_params,
+ 					     phy_fw_ver, PHY_FW_VER_LEN);
+ 		strlcpy(buf, bp->fw_ver, buf_len);
+ 		snprintf(buf + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
+ 			 "bc %d.%d.%d%s%s",
+ 			 (bp->common.bc_ver & 0xff0000) >> 16,
+ 			 (bp->common.bc_ver & 0xff00) >> 8,
+ 			 (bp->common.bc_ver & 0xff),
+ 			 ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+ 	} else {
+ 		bnx2x_vf_fill_fw_str(bp, buf, buf_len);
+ 	}
+ }
+ 
  int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */
  
  /* free skb in the packet ring at pos idx

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* [PATCH 3/3] ixgbe: add interrupt control parameters
From: Shannon Nelson @ 2013-01-11  2:02 UTC (permalink / raw)
  To: netdev; +Cc: davem, dwmw2, jeffrey.t.kirsher, linux-kernel
In-Reply-To: <20130111020046.15463.72333.stgit@starfish.jf.intel.com>

MSIX is used by default in the driver, with MSI and legacy interrupt
handling as fallbacks.  These options allow for controlling which handling
will get used.

nomsi
nomsix
	Disable the use of MSI and/or MSIX interrupt handling

Signed-off-by: Shannon Nelson <shannon.nelson@intel.com>
Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Cc: David Woodhouse <dwmw2@infradead.org>
---

 drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c  |    6 ++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   15 +++++++++++++++
 2 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index 8c74f73..464d8cf 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -704,6 +704,9 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
 {
 	int err, vector_threshold;
 
+	if (!(adapter->flags & IXGBE_FLAG_MSIX_CAPABLE))
+		return;
+
 	/* We'll want at least 2 (vector_threshold):
 	 * 1) TxQ[0] + RxQ[0] handler
 	 * 2) Other (Link Status Change, etc.)
@@ -1107,6 +1110,9 @@ static void ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
 	ixgbe_set_num_queues(adapter);
 	adapter->num_q_vectors = 1;
 
+	if (!(adapter->flags & IXGBE_FLAG_MSI_CAPABLE))
+		return;
+
 	err = pci_enable_msi(adapter->pdev);
 	if (err) {
 		netif_printk(adapter, hw, KERN_DEBUG, adapter->netdev,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 9a94ca2..baa778e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -169,6 +169,8 @@ enum {
 #endif
 	Opt_FdirPballoc,
 	Opt_AtrSampleRate,
+	Opt_nomsix,
+	Opt_nomsi,
 };
 
 static const match_table_t tokens = {
@@ -182,6 +184,8 @@ static const match_table_t tokens = {
 #endif
 	{ Opt_FdirPballoc, "FdirPballoc=%u" },
 	{ Opt_AtrSampleRate, "AtrSampleRate=%u" },
+	{ Opt_nomsix, "nomsix" },
+	{ Opt_nomsi, "nomsi" },
 
 	/* terminator token */
 	{ 0, NULL },
@@ -194,6 +198,8 @@ MODULE_INFO(fw_option,
 MODULE_INFO(fw_option, "nodca : Disable Direct Cache Access");
 MODULE_INFO(fw_option, "FdirPballoc=N : Flow Director packet buffer allocation level - 1, 2, or 3");
 MODULE_INFO(fw_option, "AtrSampleRate=N : Software ATR Tx packet sample rate, 0-255");
+MODULE_INFO(fw_option, "nomsix : Disable the use of MSI-X interrupt handling");
+MODULE_INFO(fw_option, "nomsi  : Disable the use of MSI interrupt handling");
 
 /**
  * ixgbe_parse_option_line - find ixgbe options
@@ -300,6 +306,14 @@ static void ixgbe_parse_option_line(struct ixgbe_adapter *adapter,
 				e_dev_err("Bad AtrSampleRate %d\n", value);
 			break;
 
+		case Opt_nomsix:
+			adapter->flags &= ~IXGBE_FLAG_MSIX_CAPABLE;
+			break;
+
+		case Opt_nomsi:
+			adapter->flags &= ~IXGBE_FLAG_MSI_CAPABLE;
+			break;
+
 		default:
 			goto parse_error;
 			break;
@@ -4722,6 +4736,7 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
 	/* Set capability flags */
 	rss = min_t(int, IXGBE_MAX_RSS_INDICES, num_online_cpus());
 	adapter->ring_feature[RING_F_RSS].limit = rss;
+	adapter->flags |= (IXGBE_FLAG_MSIX_CAPABLE | IXGBE_FLAG_MSI_CAPABLE);
 	switch (hw->mac.type) {
 	case ixgbe_mac_82598EB:
 		if (hw->device_id == IXGBE_DEV_ID_82598AT)

^ permalink raw reply related

* [PATCH 2/3] ixgbe: add additional parameter options
From: Shannon Nelson @ 2013-01-11  2:02 UTC (permalink / raw)
  To: netdev; +Cc: davem, dwmw2, jeffrey.t.kirsher, linux-kernel
In-Reply-To: <20130111020046.15463.72333.stgit@starfish.jf.intel.com>

With the new userland ASCII parameter file available, add a few
new parameters for finer control of some driver activity.

dca=off	Disable DCA (Direct Cache Access) activity

FdirPballoc=N
	Flow Director packet buffer allocation control
	1 = 8k hash filters or 2k perfect filters
	2 = 16k hash filters or 4k perfect filters
	3 = 32k hash filters or 8k perfect filters

AtrSampleRate=N
	Set the Software ATR Tx packet sample rate to every Nth packet,
	from 0 (disabled) to 255.

Signed-off-by: Shannon Nelson <shannon.nelson@intel.com>
Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Cc: David Woodhouse <dwmw2@infradead.org>
---

 drivers/net/ethernet/intel/ixgbe/ixgbe.h      |    4 ++
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   63 +++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 8e78676..adfcd58 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -111,6 +111,10 @@
 #define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT  29
 #define IXGBE_TX_FLAGS_VLAN_SHIFT	16
 
+#define IXGBE_MAX_ATR_SAMPLE_RATE	255
+#define IXGBE_MIN_ATR_SAMPLE_RATE	1
+#define IXGBE_ATR_SAMPLE_RATE_OFF	0
+
 #define IXGBE_MAX_VF_MC_ENTRIES         30
 #define IXGBE_MAX_VF_FUNCTIONS          64
 #define IXGBE_MAX_VFTA_ENTRIES          128
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 1670fc7..9a94ca2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -164,6 +164,11 @@ enum {
 #ifdef CONFIG_PCI_IOV
 	Opt_max_vfs,
 #endif
+#ifdef CONFIG_IXGBE_DCA
+	Opt_no_dca,
+#endif
+	Opt_FdirPballoc,
+	Opt_AtrSampleRate,
 };
 
 static const match_table_t tokens = {
@@ -172,6 +177,11 @@ static const match_table_t tokens = {
 #ifdef CONFIG_PCI_IOV
 	{ Opt_max_vfs, "max_vfs=%u" },
 #endif
+#ifdef CONFIG_IXGBE_DCA
+	{ Opt_no_dca, "nodca" },
+#endif
+	{ Opt_FdirPballoc, "FdirPballoc=%u" },
+	{ Opt_AtrSampleRate, "AtrSampleRate=%u" },
 
 	/* terminator token */
 	{ 0, NULL },
@@ -181,6 +191,9 @@ MODULE_INFO(fw_option, "allow_unsupported_sfp : Allow unsupported and untested S
 MODULE_INFO(fw_option,
 	    "max_vfs=N : Maximum number of virtual functions per physical function (default=0) - 0 <= N < "
 	    xstr(IXGBE_MAX_VF_FUNCTIONS));
+MODULE_INFO(fw_option, "nodca : Disable Direct Cache Access");
+MODULE_INFO(fw_option, "FdirPballoc=N : Flow Director packet buffer allocation level - 1, 2, or 3");
+MODULE_INFO(fw_option, "AtrSampleRate=N : Software ATR Tx packet sample rate, 0-255");
 
 /**
  * ixgbe_parse_option_line - find ixgbe options
@@ -195,7 +208,7 @@ static void ixgbe_parse_option_line(struct ixgbe_adapter *adapter,
 	char *p;
 	char *next_option = config_line;
 	substring_t args[MAX_OPT_ARGS];
-	int value;
+	int value, x;
 
 	if (!config_line)
 		return;
@@ -239,6 +252,54 @@ static void ixgbe_parse_option_line(struct ixgbe_adapter *adapter,
 			break;
 
 #endif
+#ifdef CONFIG_IXGBE_DCA
+		case Opt_no_dca:
+			adapter->flags &= ~(IXGBE_FLAG_DCA_CAPABLE |
+					    IXGBE_FLAG_DCA_ENABLED);
+			break;
+
+#endif
+		case Opt_FdirPballoc:
+			if (match_int(args, &value))
+				goto parse_error;
+
+			x = adapter->fdir_pballoc;
+			if (adapter->hw.mac.type == ixgbe_mac_82598EB
+			    || value == IXGBE_FDIR_PBALLOC_NONE) {
+				adapter->fdir_pballoc = IXGBE_FDIR_PBALLOC_NONE;
+				x = 0;
+			} else if (value == IXGBE_FDIR_PBALLOC_256K) {
+				adapter->fdir_pballoc = IXGBE_FDIR_PBALLOC_256K;
+				x = 256;
+			} else if (value == IXGBE_FDIR_PBALLOC_128K) {
+				adapter->fdir_pballoc = IXGBE_FDIR_PBALLOC_128K;
+				x = 128;
+			} else if (value == IXGBE_FDIR_PBALLOC_64K) {
+				adapter->fdir_pballoc = IXGBE_FDIR_PBALLOC_64K;
+				x = 64;
+			} else {
+				e_dev_err("Bad FdirPballoc value %d\n", value);
+			}
+
+			e_dev_err(
+				"Flow Director will be allocated %dKB of packet buffer\n",
+				x);
+			break;
+
+		case Opt_AtrSampleRate:
+			if (match_int(args, &value))
+				goto parse_error;
+
+			if (adapter->hw.mac.type == ixgbe_mac_82598EB
+			    || value == IXGBE_ATR_SAMPLE_RATE_OFF)
+				adapter->atr_sample_rate = value;
+			else if (value >= IXGBE_MIN_ATR_SAMPLE_RATE
+				   && value <= IXGBE_MAX_ATR_SAMPLE_RATE)
+				adapter->atr_sample_rate = value;
+			else
+				e_dev_err("Bad AtrSampleRate %d\n", value);
+			break;
+
 		default:
 			goto parse_error;
 			break;

^ permalink raw reply related

* [PATCH 1/3] ixgbe: replace module options with configuration through request_firmware
From: Shannon Nelson @ 2013-01-11  2:02 UTC (permalink / raw)
  To: netdev; +Cc: davem, dwmw2, jeffrey.t.kirsher, linux-kernel
In-Reply-To: <20130111020046.15463.72333.stgit@starfish.jf.intel.com>

Replace the use of module parameters with data read from an ASCII parameter
file found through the request_firmware() framework.

The parameter file is an ASCII data file with lines in the form of
     <label>  <option>=<val>[,<option>=<val>...]
where the <label> specifies the driver name and/or a specific configuration
line to use and the following options define that configuration.  Blank
lines are ignored, as are line comments that start with '#'.

The parameter file is tagged as MODULE_FIRMWARE to be sure it gets
included when pulling the driver into an initrd image.  The possible
config options are tagged using MODULE_INFO to be sure there is still
some discoverability in configuration options.

Signed-off-by: Shannon Nelson <shannon.nelson@intel.com>
Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Cc: David Woodhouse <dwmw2@infradead.org>
---

 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |  229 ++++++++++++++++++++++---
 1 files changed, 203 insertions(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 20d6764..1670fc7 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -47,13 +47,16 @@
 #include <linux/if_bridge.h>
 #include <linux/prefetch.h>
 #include <scsi/fc/fc_fcoe.h>
+#include <linux/firmware.h>
+#include <linux/parser.h>
 
 #include "ixgbe.h"
 #include "ixgbe_common.h"
 #include "ixgbe_dcb_82599.h"
 #include "ixgbe_sriov.h"
 
-char ixgbe_driver_name[] = "ixgbe";
+#define IXGBE_DRIVER_NAME "ixgbe"
+char ixgbe_driver_name[] = IXGBE_DRIVER_NAME;
 static const char ixgbe_driver_string[] =
 			      "Intel(R) 10 Gigabit PCI Express Network Driver";
 #ifdef IXGBE_FCOE
@@ -127,28 +130,202 @@ static struct notifier_block dca_notifier = {
 };
 #endif
 
-#ifdef CONFIG_PCI_IOV
-static unsigned int max_vfs;
-module_param(max_vfs, uint, 0);
-MODULE_PARM_DESC(max_vfs,
-		 "Maximum number of virtual functions to allocate per physical function - default is zero and maximum value is 63");
-#endif /* CONFIG_PCI_IOV */
-
-static unsigned int allow_unsupported_sfp;
-module_param(allow_unsupported_sfp, uint, 0);
-MODULE_PARM_DESC(allow_unsupported_sfp,
-		 "Allow unsupported and untested SFP+ modules on 82599-based adapters");
-
 #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
-static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+/*
+ * Firmware parameter processing
+ *
+ * This requests a parameter configuration file through the kernel
+ * firmware management service.  The parameter file is an ASCII data
+ * file with lines in the form of
+ *      <label>  <option>=<val>[,<option>=<val>...]
+ * where the <label> specifies a specific configuration to use
+ * and the following options define that configuration.  Blank lines
+ * are ignored, as are line comments that start with '#'.
+ *
+ * For this driver, we use the driver name as the label for the basic
+ * configuration, then use the port MAC address for port specific
+ * override configuration.
+ */
+#define IXGBE_FIRMWARE_FILE        IXGBE_DRIVER_NAME ".conf"
+MODULE_FIRMWARE(IXGBE_FIRMWARE_FILE);
+
+#define xstr(s) str(s)
+#define str(s)  #s
+
+enum {
+	Opt_debug,
+	Opt_allow_unsupported_sfp,
+#ifdef CONFIG_PCI_IOV
+	Opt_max_vfs,
+#endif
+};
+
+static const match_table_t tokens = {
+	{ Opt_debug, "debug=%u" },
+	{ Opt_allow_unsupported_sfp, "allow_unsupported_sfp" },
+#ifdef CONFIG_PCI_IOV
+	{ Opt_max_vfs, "max_vfs=%u" },
+#endif
+
+	/* terminator token */
+	{ 0, NULL },
+};
+MODULE_INFO(fw_option, "debug=N : Debug level (0=none,...,16=all)");
+MODULE_INFO(fw_option, "allow_unsupported_sfp : Allow unsupported and untested SFP+ modules on 82599-based adapters");
+MODULE_INFO(fw_option,
+	    "max_vfs=N : Maximum number of virtual functions per physical function (default=0) - 0 <= N < "
+	    xstr(IXGBE_MAX_VF_FUNCTIONS));
+
+/**
+ * ixgbe_parse_option_line - find ixgbe options
+ * @adapter: pointer to ixgbe_adapter
+ * @config_line: line of option information
+ * @line_len: length of the config line
+ *
+ **/
+static void ixgbe_parse_option_line(struct ixgbe_adapter *adapter,
+				    char *config_line, int line_len)
+{
+	char *p;
+	char *next_option = config_line;
+	substring_t args[MAX_OPT_ARGS];
+	int value;
+
+	if (!config_line)
+		return;
+
+	while ((p = strsep(&next_option, ", \t\n")) != NULL) {
+		int token;
+
+		if (((p - config_line) >= line_len) || *p == '\0' || *p == '#')
+			break;
+
+		/*
+		 * Initialize args struct so we know whether arg was
+		 * found; some options take optional arguments.
+		 */
+		args[0].to = args[0].from = NULL;
+		token = match_token(p, tokens, args);
+		switch (token) {
+
+		case Opt_debug:
+			if (match_int(args, &value))
+				goto parse_error;
+			adapter->msg_enable = netif_msg_init(value,
+							    DEFAULT_MSG_ENABLE);
+			break;
+
+		case Opt_allow_unsupported_sfp:
+			adapter->hw.allow_unsupported_sfp = true;
+			break;
+
+#ifdef CONFIG_PCI_IOV
+		case Opt_max_vfs:
+			if (match_int(args, &value))
+				goto parse_error;
+
+			if (adapter->hw.mac.type != ixgbe_mac_82598EB) {
+				if (value < IXGBE_MAX_VF_FUNCTIONS)
+					adapter->num_vfs = value;
+				else
+					goto parse_error;
+			}
+			break;
+
+#endif
+		default:
+			goto parse_error;
+			break;
+		}
+	}
+
+	return;
+
+parse_error:
+	e_dev_err("options error '%s'\n", p);
+	return;
+}
+
+/**
+ * ixgbe_find_config_line - scan config file for labeled option line
+ * @fw: pointer to firmware data
+ * @label: label to search for
+ *
+ * Returns pointer to the configuration options found, or NULL
+ **/
+static char *ixgbe_find_config_line(const struct firmware *fw,
+				    const char *label)
+{
+	const char *p = fw->data;
+	const char *p_end = fw->data + fw->size;
+	int label_len = strlen(label);
+
+	while (p < p_end) {
+		/* ignore spaces and line comments */
+		p = skip_spaces(p);
+		if (p >= p_end)
+			break;
+		if (*p == '#')
+			goto scan_to_eol;
+
+		/* find tag match? */
+		if (!strncmp(p, label, min_t(int, label_len, (p_end - p)))) {
+
+			/* skip over the tag to find the options */
+			p += label_len;
+			p = skip_spaces(p);
+			if (p >= p_end)
+				break;
+			if (*p != '#')
+				return (char *)p;
+		}
+
+scan_to_eol:
+		while (p < p_end && *p != '\n')
+			p++;
+		if (p < p_end && *p == '\n')
+			p++;
+	}
+
+	return NULL;
+}
+
+/**
+ * ixgbe_check_options - find and check configuration parameters
+ * @adapter: pointer to ixgbe_adapter
+ * @label: the configuration tag to search for
+ **/
+void ixgbe_check_options(struct ixgbe_adapter *adapter, const char *label)
+{
+	char *config_line;
+	char *line_end;
+	int line_len, remaining;
+	int ret;
+	const struct firmware *fw;
+
+	ret = request_firmware(&fw, IXGBE_FIRMWARE_FILE, &adapter->pdev->dev);
+	if (ret)
+		return;
+
+	config_line = ixgbe_find_config_line(fw, label);
+	if (config_line) {
+		remaining = fw->size - (config_line - (char *)fw->data);
+		line_end = strnchr(config_line, remaining, '\n');
+		if (line_end)
+			line_len = line_end - config_line;
+		else
+			line_len = remaining;
+		ixgbe_parse_option_line(adapter, config_line, line_len);
+	}
+	release_firmware(fw);
+}
+
 static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
 {
 	if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
@@ -4572,12 +4749,6 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
 	hw->fc.disable_fc_autoneg =
 		(ixgbe_device_supports_autoneg_fc(hw) == 0) ? false : true;
 
-#ifdef CONFIG_PCI_IOV
-	/* assign number of SR-IOV VFs */
-	if (hw->mac.type != ixgbe_mac_82598EB)
-		adapter->num_vfs = (max_vfs > 63) ? 0 : max_vfs;
-
-#endif
 	/* enable itr by default in dynamic mode */
 	adapter->rx_itr_setting = 1;
 	adapter->tx_itr_setting = 1;
@@ -7197,6 +7368,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	u8 part_str[IXGBE_PBANUM_LENGTH];
 	unsigned int indices = num_possible_cpus();
 	unsigned int dcb_max = 0;
+	char mac_str[20];
 #ifdef IXGBE_FCOE
 	u16 device_caps;
 #endif
@@ -7279,7 +7451,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	adapter->pdev = pdev;
 	hw = &adapter->hw;
 	hw->back = adapter;
-	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
+	adapter->msg_enable = netif_msg_init(-1, DEFAULT_MSG_ENABLE);
 
 	hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
 			      pci_resource_len(pdev, 0));
@@ -7324,6 +7496,9 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (err)
 		goto err_sw_init;
 
+	/* look for generic options in userland config file */
+	ixgbe_check_options(adapter, ixgbe_driver_name);
+
 	/* Make it possible the adapter to be woken up via WOL */
 	switch (adapter->hw.mac.type) {
 	case ixgbe_mac_82599EB:
@@ -7344,12 +7519,14 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			e_crit(probe, "Fan has stopped, replace the adapter\n");
 	}
 
-	if (allow_unsupported_sfp)
-		hw->allow_unsupported_sfp = allow_unsupported_sfp;
-
 	/* reset_hw fills in the perm_addr as well */
 	hw->phy.reset_if_overtemp = true;
 	err = hw->mac.ops.reset_hw(hw);
+
+	/* look for mac specific options in userland config file */
+	snprintf(mac_str, sizeof(mac_str)-1, "%pM", adapter->hw.mac.addr);
+	ixgbe_check_options(adapter, mac_str);
+
 	hw->phy.reset_if_overtemp = false;
 	if (err == IXGBE_ERR_SFP_NOT_PRESENT &&
 	    hw->mac.type == ixgbe_mac_82598EB) {

^ 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