Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next 0/2] qlge: feature update
From: Jitendra Kalsaria @ 2013-08-22 19:54 UTC (permalink / raw)
  To: davem; +Cc: netdev, ron.mercer, Dept_NX_Linux_NIC_Driver, Jitendra Kalsaria

From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>

This patch series enhance the handling of nested vlan tags in Rx path.

Please apply it to net-next.

Jitendra Kalsaria (2):
  qlge: Enhance nested VLAN (Q-in-Q) handling.
  qlge: Update version to 1.0.0.33

 drivers/net/ethernet/qlogic/qlge/qlge.h      |    2 +-
 drivers/net/ethernet/qlogic/qlge/qlge_main.c |   87 ++++++++++++++++++++------
 2 files changed, 68 insertions(+), 21 deletions(-)

^ permalink raw reply

* Re: [PATCH 1/2] Revert "genetlink: fix family dump race"
From: Johannes Berg @ 2013-08-22 20:36 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, tgraf, Pravin Shelar
In-Reply-To: <20130822.132631.2273195424430844661.davem@davemloft.net>

On Thu, 2013-08-22 at 13:26 -0700, David Miller wrote:

> How to deal with the problem we were attempting to solve is still
> under discussion.  It seems that even if we go to RCU we must also
> address to module reference count issue.

Yes, that's a separate issue. However, I think we should also check in
more detail the dumpit locking issue Pravin pointed out - before his
changes there was indeed the genl lock used as the cb_mutex. As I've
said over in the other thread, I'm not sure that change was actually
useful - it sounded like he confused kernel sockets and userland sockets
here? (Or maybe I am?!)

OTOH, we've already fixed the race conditions that resulted from his
patch, at least in nl80211. You might remember the issue Linus ran into
with the attrbuf, it's looking like that issue was because he changed
generic netlink to no longer use the genl_lock as the cb_mutex.

> I think the existing locking is very messy, and RCU looks a lot
> cleaner and has potential for future improvements to the scalability
> of dumps.

I agree, though we're not all that interested in generic netlink family
scalability I think, we have less than a dozen families, so this
shouldn't really be an issue.

> So I'd like to propose that we combine Johannes's RCU conversion
> with some variant of the module reference count fix.
> 
> Can you guys work together and come up with something I can apply?

Sure, that in itself isn't really a problem, but if we don't take
Pravin's patch to "revert" the cb_mutex change in his parallel_ops
changes, then we definitely need to audit all generic netlink dumpit
implementations in all users to see if they have similar races to
nl80211. I originally thought that it was an nl80211 problem, but I'm
now convinced that it wasn't. Still the new code in nl80211 is probably
nicer, and we can probably make it parallel_ops now due to these changes
but I'm not convinced we can audit all genl families.

If it wasn't that so much time has already passed since the parallel_ops
changes I'd almost suggest reverting those altogether and addressing the
locking properly ...

johannes

^ permalink raw reply

* [PATCH net-next 1/2] qlge: Enhance nested VLAN (Q-in-Q) handling.
From: Jitendra Kalsaria @ 2013-08-22 19:54 UTC (permalink / raw)
  To: davem; +Cc: netdev, ron.mercer, Dept_NX_Linux_NIC_Driver, Jitendra Kalsaria
In-Reply-To: <1377201252-9283-1-git-send-email-jitendra.kalsaria@qlogic.com>

From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>

Adapter doesn’t handle packets with nested VLAN tags in
Rx path. Turn off VLAN tag stripping in the hardware and
let the stack handle stripping of VLAN tags in the Rx path.

Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlge/qlge_main.c |   79 +++++++++++++++++++-------
 1 files changed, 59 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index 2553cf4..f6f2c5f 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -87,6 +87,12 @@ MODULE_PARM_DESC(qlge_force_coredump,
 		"Option to allow force of firmware core dump. "
 		"Default is OFF - Do not allow.");
 
+static int qlge_hw_strip_vlan;
+module_param(qlge_hw_strip_vlan, int, 0);
+MODULE_PARM_DESC(qlge_hw_strip_vlan,
+		"Option to enable hardware to strip vlan tag. "
+		"Default is OFF - Hardware will not strip.");
+
 static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = {
 	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)},
 	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)},
@@ -1464,6 +1470,25 @@ static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err,
 	}
 }
 
+/*
+ * This routine will update the mac header length based on
+ * single or nested vlan tags if present
+ */
+static void ql_update_mac_hdr_len(struct ib_mac_iocb_rsp *ib_mac_rsp,
+				  void *page, size_t *len)
+{
+	u16 *tags;
+
+	if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && !qlge_hw_strip_vlan) {
+		tags = (u16 *)page;
+		if (tags[6] == htons(ETH_P_8021Q) &&
+		    tags[8] == htons(ETH_P_8021Q))
+			*len += 2 * VLAN_HLEN;
+		else
+			*len += VLAN_HLEN;
+	}
+}
+
 /* Process an inbound completion from an rx ring. */
 static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
 					struct rx_ring *rx_ring,
@@ -1523,6 +1548,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
 	void *addr;
 	struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
 	struct napi_struct *napi = &rx_ring->napi;
+	size_t hlen = ETH_HLEN;
 
 	skb = netdev_alloc_skb(ndev, length);
 	if (!skb) {
@@ -1540,25 +1566,28 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
 		goto err_out;
 	}
 
+	/* Update the MAC header length*/
+	ql_update_mac_hdr_len(ib_mac_rsp, addr, &hlen);
+
 	/* The max framesize filter on this chip is set higher than
 	 * MTU since FCoE uses 2k frames.
 	 */
-	if (skb->len > ndev->mtu + ETH_HLEN) {
+	if (skb->len > ndev->mtu + hlen) {
 		netif_err(qdev, drv, qdev->ndev,
 			  "Segment too small, dropping.\n");
 		rx_ring->rx_dropped++;
 		goto err_out;
 	}
-	memcpy(skb_put(skb, ETH_HLEN), addr, ETH_HLEN);
+	memcpy(skb_put(skb, hlen), addr, hlen);
 	netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
 		     "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n",
 		     length);
 	skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page,
-				lbq_desc->p.pg_chunk.offset+ETH_HLEN,
-				length-ETH_HLEN);
-	skb->len += length-ETH_HLEN;
-	skb->data_len += length-ETH_HLEN;
-	skb->truesize += length-ETH_HLEN;
+				lbq_desc->p.pg_chunk.offset + hlen,
+				length - hlen);
+	skb->len += length - hlen;
+	skb->data_len += length - hlen;
+	skb->truesize += length - hlen;
 
 	rx_ring->rx_packets++;
 	rx_ring->rx_bytes += skb->len;
@@ -1576,7 +1605,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
 				(ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {
 			/* Unfragmented ipv4 UDP frame. */
 			struct iphdr *iph =
-				(struct iphdr *) ((u8 *)addr + ETH_HLEN);
+				(struct iphdr *) ((u8 *)addr + hlen);
 			if (!(iph->frag_off &
 				htons(IP_MF|IP_OFFSET))) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1726,7 +1755,8 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
 	struct bq_desc *sbq_desc;
 	struct sk_buff *skb = NULL;
 	u32 length = le32_to_cpu(ib_mac_rsp->data_len);
-       u32 hdr_len = le32_to_cpu(ib_mac_rsp->hdr_len);
+	u32 hdr_len = le32_to_cpu(ib_mac_rsp->hdr_len);
+	size_t hlen = ETH_HLEN;
 
 	/*
 	 * Handle the header buffer if present.
@@ -1853,9 +1883,10 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
 			skb->data_len += length;
 			skb->truesize += length;
 			length -= length;
-			__pskb_pull_tail(skb,
-				(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ?
-				VLAN_ETH_HLEN : ETH_HLEN);
+			ql_update_mac_hdr_len(ib_mac_rsp,
+					      lbq_desc->p.pg_chunk.va,
+					      &hlen);
+			__pskb_pull_tail(skb, hlen);
 		}
 	} else {
 		/*
@@ -1910,8 +1941,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
 			length -= size;
 			i++;
 		}
-		__pskb_pull_tail(skb, (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ?
-				VLAN_ETH_HLEN : ETH_HLEN);
+		ql_update_mac_hdr_len(ib_mac_rsp, lbq_desc->p.pg_chunk.va,
+				      &hlen);
+		__pskb_pull_tail(skb, hlen);
 	}
 	return skb;
 }
@@ -2003,7 +2035,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
 	rx_ring->rx_packets++;
 	rx_ring->rx_bytes += skb->len;
 	skb_record_rx_queue(skb, rx_ring->cq_id);
-	if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && (vlan_id != 0))
+	if (vlan_id != 0xffff)
 		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
 	if (skb->ip_summed == CHECKSUM_UNNECESSARY)
 		napi_gro_receive(&rx_ring->napi, skb);
@@ -2017,7 +2049,8 @@ static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev,
 					struct ib_mac_iocb_rsp *ib_mac_rsp)
 {
 	u32 length = le32_to_cpu(ib_mac_rsp->data_len);
-	u16 vlan_id = (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ?
+	u16 vlan_id = ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) &&
+			qlge_hw_strip_vlan) ?
 			((le16_to_cpu(ib_mac_rsp->vlan_id) &
 			IB_MAC_IOCB_RSP_VLAN_MASK)) : 0xffff;
 
@@ -3704,8 +3737,12 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
 	ql_write32(qdev, SYS, mask | value);
 
 	/* Set the default queue, and VLAN behavior. */
-	value = NIC_RCV_CFG_DFQ | NIC_RCV_CFG_RV;
-	mask = NIC_RCV_CFG_DFQ_MASK | (NIC_RCV_CFG_RV << 16);
+	value = NIC_RCV_CFG_DFQ;
+	mask = NIC_RCV_CFG_DFQ_MASK;
+	if (qdev->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+		value |= NIC_RCV_CFG_RV;
+		mask |= (NIC_RCV_CFG_RV << 16);
+	}
 	ql_write32(qdev, NIC_RCV_CFG, (mask | value));
 
 	/* Set the MPI interrupt to enabled. */
@@ -4695,10 +4732,12 @@ static int qlge_probe(struct pci_dev *pdev,
 	ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
 		NETIF_F_TSO | NETIF_F_TSO_ECN |
 		NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_RXCSUM;
-	ndev->features = ndev->hw_features |
-		NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
+	ndev->features = ndev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
 	ndev->vlan_features = ndev->hw_features;
 
+	if (qlge_hw_strip_vlan)
+		ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+
 	if (test_bit(QL_DMA64, &qdev->flags))
 		ndev->features |= NETIF_F_HIGHDMA;
 
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH net-next 3/3] net: tcp_probe: add IPv6 support
From: David Miller @ 2013-08-22 20:43 UTC (permalink / raw)
  To: dborkman; +Cc: netdev
In-Reply-To: <1377107280-31091-4-git-send-email-dborkman@redhat.com>

From: Daniel Borkmann <dborkman@redhat.com>
Date: Wed, 21 Aug 2013 19:48:00 +0200

> +	union {
> +		struct sockaddr		raw;
> +		struct sockaddr_in	v4;
> +		struct sockaddr_in6	v6;
> +	}	src, dst;

This bloats up the tcp_log structure unnecessarily.  You have
absolutely no use for the port member, for example.

I know you want to use this so that you can be lazy and only
use the single printf format specifier.  Here, keeping the
tcp_log compact is more important.

^ permalink raw reply

* Can linux kernel bridge forward 802.1q tagged vlan packets?
From: Stephan von Krawczynski @ 2013-08-22 20:44 UTC (permalink / raw)
  To: bridge; +Cc: netdev

Hello all,

first it seemed a trivial question to me, but since I could not find anybody
being neither able to answer this question nor giving a short config example
I'd like to ask here, maybe this is the right place.
My general idea is to bridge tagged vlan packets from a physical interface
(intel) to a virtual interface (virtio in qemu) and not losing the tags, so
the qemu guest can use vconfig and friends to get some vlan interfaces.
Is this possible and are there any additional steps necessary besides the
usual bridge configuration?
What bothers me especially is the vlan filtering done by nics which can
prevent to even receive the packets from the LAN.
And on the other side of course can the bridge code forward packets including
tags so that virtio is able to handle them?

-- 
Regards,
Stephan

^ permalink raw reply

* [PATCH] net/phy: Remove duplicate micrel phy defines
From: dinguyen @ 2013-08-22 21:01 UTC (permalink / raw)
  To: dinh.linux; +Cc: Dinh Nguyen, Sean Cross, David S. Miller, netdev

From: Dinh Nguyen <dinguyen@altera.com>

Commit <f275487fa phy: micrel: Add definitions for common Micrel PHY
registers>, that is currently in Shawn Guo for-next tree at:
http://git.linaro.org/git-ro/people/shawnguo/linux-2.6.git, has moved
a few of the Micrel PHY defines to include/linux/micrel_phy.h.

This commit removes the duplicate defines from commit:
<954c3967 net/phy: micrel: Add OF configuration support for ksz9021>.

It also moves a few defines to the include file.

Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
Cc: Sean Cross <xobs@kosagi.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: netdev@vger.kernel.org
---
 drivers/net/phy/micrel.c   |   26 +++++++-------------------
 include/linux/micrel_phy.h |    4 ++++
 2 files changed, 11 insertions(+), 19 deletions(-)

diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index c31aad0..6ddaa87 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -54,18 +54,6 @@
 #define KS8737_CTRL_INT_ACTIVE_HIGH		(1 << 14)
 #define KSZ8051_RMII_50MHZ_CLK			(1 << 7)
 
-/* Write/read to/from extended registers */
-#define MII_KSZPHY_EXTREG                       0x0b
-#define KSZPHY_EXTREG_WRITE                     0x8000
-
-#define MII_KSZPHY_EXTREG_WRITE                 0x0c
-#define MII_KSZPHY_EXTREG_READ                  0x0d
-
-/* Extended registers */
-#define MII_KSZPHY_CLK_CONTROL_PAD_SKEW         0x104
-#define MII_KSZPHY_RX_DATA_PAD_SKEW             0x105
-#define MII_KSZPHY_TX_DATA_PAD_SKEW             0x106
-
 #define PS_TO_REG				200
 
 static int ksz_config_flags(struct phy_device *phydev)
@@ -83,15 +71,15 @@ static int ksz_config_flags(struct phy_device *phydev)
 static int kszphy_extended_write(struct phy_device *phydev,
                                  u32 regnum, u16 val)
 {
-	phy_write(phydev, MII_KSZPHY_EXTREG, KSZPHY_EXTREG_WRITE | regnum);
-	return phy_write(phydev, MII_KSZPHY_EXTREG_WRITE, val);
+	phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, KSZPHY_EXTREG_WRITE | regnum);
+	return phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, val);
 }
 
 static int kszphy_extended_read(struct phy_device *phydev,
                                  u32 regnum)
 {
-	phy_write(phydev, MII_KSZPHY_EXTREG, regnum);
-	return phy_read(phydev, MII_KSZPHY_EXTREG_READ);
+	phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, regnum);
+	return phy_read(phydev, MICREL_KSZ9021_EXTREG_DATA_READ);
 }
 
 static int kszphy_ack_interrupt(struct phy_device *phydev)
@@ -227,15 +215,15 @@ static int ksz9021_config_init(struct phy_device *phydev)
 
 	if (of_node) {
 		ksz9021_load_values_from_of(phydev, of_node,
-				    MII_KSZPHY_CLK_CONTROL_PAD_SKEW,
+				    MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW,
 				    "txen-skew-ps", "txc-skew-ps",
 				    "rxdv-skew-ps", "rxc-skew-ps");
 		ksz9021_load_values_from_of(phydev, of_node,
-				    MII_KSZPHY_RX_DATA_PAD_SKEW,
+				    MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW,
 				    "rxd0-skew-ps", "rxd1-skew-ps",
 				    "rxd2-skew-ps", "rxd3-skew-ps");
 		ksz9021_load_values_from_of(phydev, of_node,
-				    MII_KSZPHY_TX_DATA_PAD_SKEW,
+				    MICREL_KSZ9021_RGMII_TX_DATA_PAD_SKEW,
 				    "txd0-skew-ps", "txd1-skew-ps",
 				    "txd2-skew-ps", "txd3-skew-ps");
 	}
diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h
index ad05ce6..f9cf9bb 100644
--- a/include/linux/micrel_phy.h
+++ b/include/linux/micrel_phy.h
@@ -38,7 +38,11 @@
 
 #define MICREL_KSZ9021_EXTREG_CTRL	0xB
 #define MICREL_KSZ9021_EXTREG_DATA_WRITE	0xC
+#define MICREL_KSZ9021_EXTREG_DATA_READ		0xD
 #define MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW	0x104
 #define MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW	0x105
+#define MICREL_KSZ9021_RGMII_TX_DATA_PAD_SCEW   0x106
+
+#define KSZPHY_EXTREG_WRITE                     0x8000
 
 #endif /* _MICREL_PHY_H */
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH net-next 3/3] net: tcp_probe: add IPv6 support
From: Daniel Borkmann @ 2013-08-22 21:20 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20130822.134309.2073296501906078763.davem@davemloft.net>

On 08/22/2013 10:43 PM, David Miller wrote:
> From: Daniel Borkmann <dborkman@redhat.com>
> Date: Wed, 21 Aug 2013 19:48:00 +0200
>
>> +	union {
>> +		struct sockaddr		raw;
>> +		struct sockaddr_in	v4;
>> +		struct sockaddr_in6	v6;
>> +	}	src, dst;
>
> This bloats up the tcp_log structure unnecessarily.  You have
> absolutely no use for the port member, for example.
>
> I know you want to use this so that you can be lazy and only
> use the single printf format specifier.  Here, keeping the
> tcp_log compact is more important.

Well, the port is being filled out *and* used in both IPv4 and IPv6
cases. That is why %pISpc is being used, hence IP + port that is being
printed. The port was of course also printed to the log before in
IPv4 only case, so nothing would change there.

^ permalink raw reply

* [PATCH 1/2] genl: Fix genl dumpit() locking.
From: Pravin B Shelar @ 2013-08-22 21:25 UTC (permalink / raw)
  To: netdev; +Cc: Pravin B Shelar, Jesse Gross, Johannes Berg

In case of genl-family with parallel ops off, dumpif() callback
is expected to run under genl_lock, But commit def3117493eafd9df
(genl: Allow concurrent genl callbacks.) changed this behaviour
where only first dumpit() op was called under genl-lock.
For subsequent dump, only nlk->cb_lock was taken.
Following patch fixes it by defining locked dumpit() and done()
callback which takes care of genl-locking.

CC: Jesse Gross <jesse@nicira.com>
CC: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
v1-v2:
No change.
---
 net/netlink/genetlink.c |   46 +++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f85f8a2..3669039 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -544,6 +544,28 @@ void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
 }
 EXPORT_SYMBOL(genlmsg_put);
 
+static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct genl_ops *ops = cb->data;
+	int rc;
+
+	genl_lock();
+	rc = ops->dumpit(skb, cb);
+	genl_unlock();
+	return rc;
+}
+
+static int genl_lock_done(struct netlink_callback *cb)
+{
+	struct genl_ops *ops = cb->data;
+	int rc;
+
+	genl_lock();
+	rc = ops->done(cb);
+	genl_unlock();
+	return rc;
+}
+
 static int genl_family_rcv_msg(struct genl_family *family,
 			       struct sk_buff *skb,
 			       struct nlmsghdr *nlh)
@@ -572,15 +594,29 @@ static int genl_family_rcv_msg(struct genl_family *family,
 		return -EPERM;
 
 	if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
-		struct netlink_dump_control c = {
-			.dump = ops->dumpit,
-			.done = ops->done,
-		};
+		struct netlink_dump_control c;
+		int rc;
 
 		if (ops->dumpit == NULL)
 			return -EOPNOTSUPP;
 
-		return netlink_dump_start(net->genl_sock, skb, nlh, &c);
+		memset(&c, 0, sizeof(c));
+		if (!family->parallel_ops) {
+			genl_unlock();
+			c.data = ops;
+			c.dump = genl_lock_dumpit;
+			if (ops->done)
+				c.done = genl_lock_done;
+		} else {
+			c.dump = ops->dumpit;
+			c.done = ops->done;
+		}
+
+		rc = netlink_dump_start(net->genl_sock, skb, nlh, &c);
+		if (!family->parallel_ops)
+			genl_lock();
+		return rc;
+
 	}
 
 	if (ops->doit == NULL)
-- 
1.7.1

^ permalink raw reply related

* [PATCH 2/2] genl: Hold reference on correct module while netlink-dump.
From: Pravin B Shelar @ 2013-08-22 21:25 UTC (permalink / raw)
  To: netdev; +Cc: Pravin B Shelar, Jesse Gross, Johannes Berg

netlink dump operations take module as parameter to hold
reference for entire netlink dump duration.
Currently it holds ref only on genl module which is not correct
when we use ops registered to genl from another module.
Following patch adds module pointer to genl_ops so that netlink
can hold ref count on it.

CC: Jesse Gross <jesse@nicira.com>
CC: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
v1-v2:
No need to ref count genl module.
---
 include/net/genetlink.h |   20 +++++++++++++++++---
 net/netlink/genetlink.c |   20 +++++++++++---------
 2 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 93024a4..ab8a7c5 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -61,6 +61,7 @@ struct genl_family {
 	struct list_head	ops_list;	/* private */
 	struct list_head	family_list;	/* private */
 	struct list_head	mcast_groups;	/* private */
+	struct module		*module;
 };
 
 /**
@@ -121,9 +122,22 @@ struct genl_ops {
 	struct list_head	ops_list;
 };
 
-extern int genl_register_family(struct genl_family *family);
-extern int genl_register_family_with_ops(struct genl_family *family,
-	struct genl_ops *ops, size_t n_ops);
+extern int __genl_register_family(struct genl_family *family, struct module *module);
+
+static inline int genl_register_family(struct genl_family *family)
+{
+	return __genl_register_family(family, THIS_MODULE);
+}
+
+extern int __genl_register_family_with_ops(struct genl_family *family,
+	struct genl_ops *ops, size_t n_ops, struct module *module);
+
+static inline int genl_register_family_with_ops(struct genl_family *family,
+	struct genl_ops *ops, size_t n_ops)
+{
+	return __genl_register_family_with_ops(family, ops, n_ops, THIS_MODULE);
+}
+
 extern int genl_unregister_family(struct genl_family *family);
 extern int genl_register_ops(struct genl_family *, struct genl_ops *ops);
 extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 3669039..d491604 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -364,7 +364,7 @@ int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops)
 EXPORT_SYMBOL(genl_unregister_ops);
 
 /**
- * genl_register_family - register a generic netlink family
+ * __genl_register_family - register a generic netlink family
  * @family: generic netlink family
  *
  * Registers the specified family after validating it first. Only one
@@ -374,7 +374,7 @@ EXPORT_SYMBOL(genl_unregister_ops);
  *
  * Return 0 on success or a negative error code.
  */
-int genl_register_family(struct genl_family *family)
+int __genl_register_family(struct genl_family *family, struct module *module)
 {
 	int err = -EINVAL;
 
@@ -418,6 +418,7 @@ int genl_register_family(struct genl_family *family)
 	} else
 		family->attrbuf = NULL;
 
+	family->module = module;
 	list_add_tail(&family->family_list, genl_family_chain(family->id));
 	genl_unlock_all();
 
@@ -430,10 +431,10 @@ errout_locked:
 errout:
 	return err;
 }
-EXPORT_SYMBOL(genl_register_family);
+EXPORT_SYMBOL(__genl_register_family);
 
 /**
- * genl_register_family_with_ops - register a generic netlink family
+ * __genl_register_family_with_ops - register a generic netlink family
  * @family: generic netlink family
  * @ops: operations to be registered
  * @n_ops: number of elements to register
@@ -457,12 +458,12 @@ EXPORT_SYMBOL(genl_register_family);
  *
  * Return 0 on success or a negative error code.
  */
-int genl_register_family_with_ops(struct genl_family *family,
-	struct genl_ops *ops, size_t n_ops)
+int __genl_register_family_with_ops(struct genl_family *family,
+	struct genl_ops *ops, size_t n_ops, struct module *module)
 {
 	int err, i;
 
-	err = genl_register_family(family);
+	err = __genl_register_family(family, module);
 	if (err)
 		return err;
 
@@ -476,7 +477,7 @@ err_out:
 	genl_unregister_family(family);
 	return err;
 }
-EXPORT_SYMBOL(genl_register_family_with_ops);
+EXPORT_SYMBOL(__genl_register_family_with_ops);
 
 /**
  * genl_unregister_family - unregister generic netlink family
@@ -612,7 +613,8 @@ static int genl_family_rcv_msg(struct genl_family *family,
 			c.done = ops->done;
 		}
 
-		rc = netlink_dump_start(net->genl_sock, skb, nlh, &c);
+		c.module = family->module;
+		rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
 		if (!family->parallel_ops)
 			genl_lock();
 		return rc;
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH net-next v4] r8169: fix invalid register dump
From: David Miller @ 2013-08-22 21:26 UTC (permalink / raw)
  To: lekensteyn; +Cc: netdev, nic_swsd, bhutchings, romieu
In-Reply-To: <1377119831-29691-1-git-send-email-lekensteyn@gmail.com>

From: Peter Wu <lekensteyn@gmail.com>
Date: Wed, 21 Aug 2013 23:17:11 +0200

> For some reason, my PCIe RTL8111E onboard NIC on a GA-Z68X-UD3H-B3
> motherboard reads as FFs when reading from MMIO with a block size
> larger than 7. Therefore change to reading blocks of four bytes.
> 
> Ben Hutchings noted that the buffer is large enough to hold all
> registers, so now all registers are read.
> 
> Signed-off-by: Peter Wu <lekensteyn@gmail.com>
> Acked-by: Francois Romieu <romieu@fr.zoreil.com>

Applied, thanks.

^ permalink raw reply

* Re: [PATCH 1/2] Revert "genetlink: fix family dump race"
From: Pravin Shelar @ 2013-08-22 21:27 UTC (permalink / raw)
  To: Johannes Berg; +Cc: David Miller, netdev, Thomas Graf
In-Reply-To: <1377203769.32535.5.camel@jlt4.sipsolutions.net>

On Thu, Aug 22, 2013 at 1:36 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Thu, 2013-08-22 at 13:26 -0700, David Miller wrote:
>
>> How to deal with the problem we were attempting to solve is still
>> under discussion.  It seems that even if we go to RCU we must also
>> address to module reference count issue.
>
> Yes, that's a separate issue. However, I think we should also check in
> more detail the dumpit locking issue Pravin pointed out - before his
> changes there was indeed the genl lock used as the cb_mutex. As I've
> said over in the other thread, I'm not sure that change was actually
> useful - it sounded like he confused kernel sockets and userland sockets
> here? (Or maybe I am?!)
>
> OTOH, we've already fixed the race conditions that resulted from his
> patch, at least in nl80211. You might remember the issue Linus ran into
> with the attrbuf, it's looking like that issue was because he changed
> generic netlink to no longer use the genl_lock as the cb_mutex.
>
>> I think the existing locking is very messy, and RCU looks a lot
>> cleaner and has potential for future improvements to the scalability
>> of dumps.
>
> I agree, though we're not all that interested in generic netlink family
> scalability I think, we have less than a dozen families, so this
> shouldn't really be an issue.
>
>> So I'd like to propose that we combine Johannes's RCU conversion
>> with some variant of the module reference count fix.
>>
>> Can you guys work together and come up with something I can apply?
>
> Sure, that in itself isn't really a problem, but if we don't take
> Pravin's patch to "revert" the cb_mutex change in his parallel_ops
> changes, then we definitely need to audit all generic netlink dumpit
> implementations in all users to see if they have similar races to
> nl80211. I originally thought that it was an nl80211 problem, but I'm
> now convinced that it wasn't. Still the new code in nl80211 is probably
> nicer, and we can probably make it parallel_ops now due to these changes
> but I'm not convinced we can audit all genl families.
>

I have sent fixes for genl-locking.

> If it wasn't that so much time has already passed since the parallel_ops
> changes I'd almost suggest reverting those altogether and addressing the
> locking properly ...
>
I think genl-parallel ops patch decouple genl-locking from netlink
lock which simplifies it. This also allows existing genl-family
gradually converted to parallel-ops. Once all are moved to parallel
ops, we can get rid of genl_mutex completely.

Passing mutex after one module to another is messy and confusing.
After genl-parallel op changes this is done only by rtnl module.
I will try to get rid of this cb_mutex parameter so that each layer
can have independent locks. I need to check rtnl module for that.

^ permalink raw reply

* Re: [PATCH 0/2] SH: fix typos in Ether platform data
From: David Miller @ 2013-08-22 21:32 UTC (permalink / raw)
  To: sergei.shtylyov; +Cc: netdev, lethal, linux-sh
In-Reply-To: <201308220215.16463.sergei.shtylyov@cogentembedded.com>

From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Date: Thu, 22 Aug 2013 02:15:16 +0400

>    Shamefully, I have fat fingered in both patches fixing Ether support on SH
> platforms and I didn't bother to compile test them at least with the ARM
> compiler I have at hand (although one of the files turned out to not really be
> compilable by it). Here's 2 patches fixing the typos, they are against David
> Miller's 'net-next.git'.

Applied, thanks Sergei.

^ permalink raw reply

* Re: [PATCH net-next] tcp: increase throughput when reordering is high
From: David Miller @ 2013-08-22 21:40 UTC (permalink / raw)
  To: ycheng; +Cc: ncardwell, edumazet, netdev
In-Reply-To: <1377131363-31341-1-git-send-email-ycheng@google.com>

From: Yuchung Cheng <ycheng@google.com>
Date: Wed, 21 Aug 2013 17:29:23 -0700

> The stack currently detects reordering and avoid spurious
> retransmission very well. However the throughput is sub-optimal under
> high reordering because cwnd is increased only if the data is deliverd
> in order. I.e., FLAG_DATA_ACKED check in tcp_ack().  The more packet
> are reordered the worse the throughput is.
> 
> Therefore when reordering is proven high, cwnd should advance whenever
> the data is delivered regardless of its ordering. If reordering is low,
> conservatively advance cwnd only on ordered deliveries in Open state,
> and retain cwnd in Disordered state (RFC5681).
> 
> Using netperf on a qdisc setup of 20Mbps BW and random RTT from 45ms
> to 55ms (for reordering effect). This change increases TCP throughput
> by 20 - 25% to near bottleneck BW.
> 
> A special case is the stretched ACK with new SACK and/or ECE mark.
> For example, a receiver may receive an out of order or ECN packet with
> unacked data buffered because of LRO or delayed ACK. The principle on
> such an ACK is to advance cwnd on the cummulative acked part first,
> then reduce cwnd in tcp_fastretrans_alert().
> 
> Signed-off-by: Yuchung Cheng <ycheng@google.com>

Applied, your team is doing great work on the TCP stack!

^ permalink raw reply

* Re: Can linux kernel bridge forward 802.1q tagged vlan packets?
From: Marek Kierdelewicz @ 2013-08-22 21:49 UTC (permalink / raw)
  To: Stephan von Krawczynski; +Cc: netdev, bridge
In-Reply-To: <20130822224453.ca93782f.skraw@ithnet.com>

Hi,

>My general idea is to bridge tagged vlan packets from a physical
>interface (intel) to a virtual interface (virtio in qemu) and not
>losing the tags, so the qemu guest can use vconfig and friends to get
>some vlan interfaces. Is this possible and are there any additional
>steps necessary besides the usual bridge configuration?

I'm using this setup with KVM virtualization (Qemu's successor). It
didn't work with default nic type for guest (realtek I think) as 802.1q
tags were not preserved properly in one of the directions. I don't
remember specifics. Anyway using e1000 driver instead of default fixed
it. Works like a charm.

Best regards,
Marek Kierdelewicz

^ permalink raw reply

* Re: [PATCH net-next 3/3] net: tcp_probe: add IPv6 support
From: David Miller @ 2013-08-22 21:50 UTC (permalink / raw)
  To: dborkman; +Cc: netdev
In-Reply-To: <52168097.7050200@redhat.com>

From: Daniel Borkmann <dborkman@redhat.com>
Date: Thu, 22 Aug 2013 23:20:23 +0200

> On 08/22/2013 10:43 PM, David Miller wrote:
>> From: Daniel Borkmann <dborkman@redhat.com>
>> Date: Wed, 21 Aug 2013 19:48:00 +0200
>>
>>> +	union {
>>> +		struct sockaddr		raw;
>>> +		struct sockaddr_in	v4;
>>> +		struct sockaddr_in6	v6;
>>> +	}	src, dst;
>>
>> This bloats up the tcp_log structure unnecessarily.  You have
>> absolutely no use for the port member, for example.
>>
>> I know you want to use this so that you can be lazy and only
>> use the single printf format specifier.  Here, keeping the
>> tcp_log compact is more important.
> 
> Well, the port is being filled out *and* used in both IPv4 and IPv6
> cases. That is why %pISpc is being used, hence IP + port that is being
> printed. The port was of course also printed to the log before in
> IPv4 only case, so nothing would change there.

Good point, ok I'll reconsider this series.

^ permalink raw reply

* [PATCH next 1/2] net: can: mscan: add a comment on reg to idx mapping
From: Anatolij Gustschin @ 2013-08-22 22:01 UTC (permalink / raw)
  To: Wolfgang Grandegger, Marc Kleine-Budde; +Cc: Gerhard Sittig, linux-can, netdev

From: Gerhard Sittig <gsi@denx.de>

add a comment about the magic of deriving an MSCAN component index
from the peripheral's physical address / register offset

Cc: linux-can@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: Gerhard Sittig <gsi@denx.de>
---
 drivers/net/can/mscan/mpc5xxx_can.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 5b0ee8e..bc422ba 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -148,7 +148,10 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		goto exit_put;
 	}
 
-	/* Determine the MSCAN device index from the physical address */
+	/* Determine the MSCAN device index from the peripheral's
+	 * physical address. Register address offsets against the
+	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
+	 */
 	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
 	BUG_ON(!pval || plen < sizeof(*pval));
 	clockidx = (*pval & 0x80) ? 1 : 0;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH next 2/2] net: can: mscan: improve clock API use
From: Anatolij Gustschin @ 2013-08-22 22:01 UTC (permalink / raw)
  To: Wolfgang Grandegger, Marc Kleine-Budde; +Cc: Gerhard Sittig, linux-can, netdev
In-Reply-To: <1377208917-16698-1-git-send-email-agust@denx.de>

From: Gerhard Sittig <gsi@denx.de>

the .get_clock() callback is run from probe() and might allocate
resources, introduce a .put_clock() callback that is run from remove()
to undo any allocation activities

prepare and enable the clocks in open(), disable and unprepare the
clocks in close() if clocks were acquired during probe(), to not assume
knowledge about which activities are done in probe() and remove()

use devm_get_clk() to lookup the SYS and REF clocks, to have the clocks
put upon device shutdown

store pointers to data structures upon successful allocation already
instead of deferral until complete setup, such that subroutines in the
setup sequence may access those data structures as well to track their
resource acquisition

since clock allocation remains optional, the release callback as well as
the enable/disable calls in open/close are optional as well

Cc: linux-can@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: Gerhard Sittig <gsi@denx.de>
---
 drivers/net/can/mscan/mpc5xxx_can.c |   18 ++++++++++++------
 drivers/net/can/mscan/mscan.c       |   25 ++++++++++++++++++++++++-
 drivers/net/can/mscan/mscan.h       |    3 +++
 3 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index bc422ba..e59b3a3 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -40,6 +40,7 @@ struct mpc5xxx_can_data {
 	unsigned int type;
 	u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,
 			 int *mscan_clksrc);
+	void (*put_clock)(struct platform_device *ofdev);
 };
 
 #ifdef CONFIG_PPC_MPC52xx
@@ -180,7 +181,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 			clockdiv = 1;
 
 		if (!clock_name || !strcmp(clock_name, "sys")) {
-			sys_clk = clk_get(&ofdev->dev, "sys_clk");
+			sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
 			if (IS_ERR(sys_clk)) {
 				dev_err(&ofdev->dev, "couldn't get sys_clk\n");
 				goto exit_unmap;
@@ -203,7 +204,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 		}
 
 		if (clocksrc < 0) {
-			ref_clk = clk_get(&ofdev->dev, "ref_clk");
+			ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
 			if (IS_ERR(ref_clk)) {
 				dev_err(&ofdev->dev, "couldn't get ref_clk\n");
 				goto exit_unmap;
@@ -280,6 +281,8 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 	dev = alloc_mscandev();
 	if (!dev)
 		goto exit_dispose_irq;
+	platform_set_drvdata(ofdev, dev);
+	SET_NETDEV_DEV(dev, &ofdev->dev);
 
 	priv = netdev_priv(dev);
 	priv->reg_base = base;
@@ -296,8 +299,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 		goto exit_free_mscan;
 	}
 
-	SET_NETDEV_DEV(dev, &ofdev->dev);
-
 	err = register_mscandev(dev, mscan_clksrc);
 	if (err) {
 		dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
@@ -305,8 +306,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
 		goto exit_free_mscan;
 	}
 
-	platform_set_drvdata(ofdev, dev);
-
 	dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
 		 priv->reg_base, dev->irq, priv->can.clock.freq);
 
@@ -324,10 +323,17 @@ exit_unmap_mem:
 
 static int mpc5xxx_can_remove(struct platform_device *ofdev)
 {
+	const struct of_device_id *match;
+	const struct mpc5xxx_can_data *data;
 	struct net_device *dev = platform_get_drvdata(ofdev);
 	struct mscan_priv *priv = netdev_priv(dev);
 
+	match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
+	data = match ? match->data : NULL;
+
 	unregister_mscandev(dev);
+	if (data && data->put_clock)
+		data->put_clock(ofdev);
 	iounmap(priv->reg_base);
 	irq_dispose_mapping(dev->irq);
 	free_candev(dev);
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index e6b4095..a955ec8 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -573,10 +573,21 @@ static int mscan_open(struct net_device *dev)
 	struct mscan_priv *priv = netdev_priv(dev);
 	struct mscan_regs __iomem *regs = priv->reg_base;
 
+	if (priv->clk_ipg) {
+		ret = clk_prepare_enable(priv->clk_ipg);
+		if (ret)
+			goto exit_retcode;
+	}
+	if (priv->clk_can) {
+		ret = clk_prepare_enable(priv->clk_can);
+		if (ret)
+			goto exit_dis_ipg_clock;
+	}
+
 	/* common open */
 	ret = open_candev(dev);
 	if (ret)
-		return ret;
+		goto exit_dis_can_clock;
 
 	napi_enable(&priv->napi);
 
@@ -604,6 +615,13 @@ exit_free_irq:
 exit_napi_disable:
 	napi_disable(&priv->napi);
 	close_candev(dev);
+exit_dis_can_clock:
+	if (priv->clk_can)
+		clk_disable_unprepare(priv->clk_can);
+exit_dis_ipg_clock:
+	if (priv->clk_ipg)
+		clk_disable_unprepare(priv->clk_ipg);
+exit_retcode:
 	return ret;
 }
 
@@ -621,6 +639,11 @@ static int mscan_close(struct net_device *dev)
 	close_candev(dev);
 	free_irq(dev->irq, dev);
 
+	if (priv->clk_can)
+		clk_disable_unprepare(priv->clk_can);
+	if (priv->clk_ipg)
+		clk_disable_unprepare(priv->clk_ipg);
+
 	return 0;
 }
 
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
index af2ed8b..9c24d60 100644
--- a/drivers/net/can/mscan/mscan.h
+++ b/drivers/net/can/mscan/mscan.h
@@ -21,6 +21,7 @@
 #ifndef __MSCAN_H__
 #define __MSCAN_H__
 
+#include <linux/clk.h>
 #include <linux/types.h>
 
 /* MSCAN control register 0 (CANCTL0) bits */
@@ -283,6 +284,8 @@ struct mscan_priv {
 	unsigned int type; 	/* MSCAN type variants */
 	unsigned long flags;
 	void __iomem *reg_base;	/* ioremap'ed address to registers */
+	struct clk *clk_ipg;	/* clock for registers */
+	struct clk *clk_can;	/* clock for bitrates */
 	u8 shadow_statflg;
 	u8 shadow_canrier;
 	u8 cur_pri;
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH 1/2] ethernet: moxa: remove unnecessary platform_set_drvdata()
From: David Miller @ 2013-08-22 22:12 UTC (permalink / raw)
  To: jg1.han; +Cc: netdev, jonas.jensen
In-Reply-To: <001901ce9eda$a9351310$fb9f3930$%han@samsung.com>

From: Jingoo Han <jg1.han@samsung.com>
Date: Thu, 22 Aug 2013 10:55:21 +0900

> The driver core clears the driver data to NULL after device_release
> or on probe failure. Thus, it is not needed to manually clear the
> device driver data to NULL.
> 
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>

Applied.

^ permalink raw reply

* Re: [PATCH 2/2] ethernet: broadcom: remove unnecessary platform_set_drvdata()
From: David Miller @ 2013-08-22 22:12 UTC (permalink / raw)
  To: jg1.han; +Cc: netdev, mbizon, florian
In-Reply-To: <001a01ce9eda$efcfdf80$cf6f9e80$%han@samsung.com>

From: Jingoo Han <jg1.han@samsung.com>
Date: Thu, 22 Aug 2013 10:57:20 +0900

> The driver core clears the driver data to NULL after device_release
> or on probe failure. Thus, it is not needed to manually clear the
> device driver data to NULL.
> 
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>

Applied.

^ permalink raw reply

* Re: Can linux kernel bridge forward 802.1q tagged vlan packets?
From: Stephen Hemminger @ 2013-08-22 22:19 UTC (permalink / raw)
  To: Marek Kierdelewicz; +Cc: bridge, Stephan von Krawczynski, netdev
In-Reply-To: <20130822234941.4affc863@catus>

On Thu, 22 Aug 2013 23:49:41 +0200
Marek Kierdelewicz <marek@piasta.pl> wrote:

> Hi,
> 
> >My general idea is to bridge tagged vlan packets from a physical
> >interface (intel) to a virtual interface (virtio in qemu) and not
> >losing the tags, so the qemu guest can use vconfig and friends to get
> >some vlan interfaces. Is this possible and are there any additional
> >steps necessary besides the usual bridge configuration?
> 
> I'm using this setup with KVM virtualization (Qemu's successor). It
> didn't work with default nic type for guest (realtek I think) as 802.1q
> tags were not preserved properly in one of the directions. I don't
> remember specifics. Anyway using e1000 driver instead of default fixed
> it. Works like a charm.

KVM e1000 Vnic doesn't do VLAN offloading at least in my experience.
Virtio works fine.

^ permalink raw reply

* [PATCH] net/cxgb3: fix revert error
From: Doug Ledford @ 2013-08-22 22:27 UTC (permalink / raw)
  To: netdev
  Cc: Doug Ledford, Santosh Rastapur, Jay Fenlason, David S. Miller,
	Divy Le ray, Alexey Kardashevskiy

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

728e2cc Revert "cxgb3: Check and handle the dma mapping errors"

reverted f83331b cxgb3: Check and handle the dma mapping errors,
however, in between those two there was also
be8b678 cxgb3: Correct comparisons and calculations using skb->tail and
skb-transport_header and
15dd16c cxgb3: Correct comparisons and calculations using skb->tail and
skb-transport_header

The author of the revert did not fix up the conflicts in such as way as
to preserve the other two commits, so they were reverted too.  As they
correct math issues under certain conditions, they should be retained.
This puts them back in place.

Signed-off-by: Doug Ledford <dledford@redhat.com>
---
 drivers/net/ethernet/chelsio/cxgb3/sge.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c
b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index 9c89dc8..632b318 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -1599,7 +1599,8 @@ static void write_ofld_wr(struct adapter *adap,
struct sk_buff *skb,
 	flits = skb_transport_offset(skb) / 8;
 	sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
 	sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb),
-			     skb->tail - skb->transport_header,
+			     skb_tail_pointer(skb) -
+			     skb_transport_header(skb),
 			     adap->pdev);
 	if (need_skb_unmap()) {
 		setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits);
-- 
1.8.1.4


[-- Attachment #2: Attached Message Part --]
[-- Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related

* Re: pull request (net-next): ipsec-next 2013-08-22
From: David Miller @ 2013-08-22 23:05 UTC (permalink / raw)
  To: steffen.klassert; +Cc: herbert, netdev
In-Reply-To: <1377169931-7302-1-git-send-email-steffen.klassert@secunet.com>

From: Steffen Klassert <steffen.klassert@secunet.com>
Date: Thu, 22 Aug 2013 13:12:04 +0200

> 1) Some constifications, from Mathias Krause.
> 
> 2) Catch bugs if a hold timer is still active when xfrm_policy_destroy()
>    is called, from Fan Du.
> 
> 3) Remove a redundant address family checking, from Fan Du.
> 
> 4) Make xfrm_state timer monotonic to be independent of system clock changes,
>    from Fan Du.
> 
> 5) Remove an outdated comment on returning -EREMOTE in the xfrm_lookup(),
>    from Rami Rosen.
> 
> Please pull or let me know if there are problems.

Pulled, thanks Steffen.

^ permalink raw reply

* Re: ipvsadm: One-packet scheduling with UDP service is unstable
From: Drunkard Zhang @ 2013-08-22 23:24 UTC (permalink / raw)
  To: Julian Anastasov
  Cc: Wensong Zhang, Simon Horman, Pablo Neira Ayuso, Patrick McHardy,
	Jozsef Kadlecsik, David S. Miller, netdev, lvs-devel,
	netfilter-devel, netfilter, coreteam, linux-kernel
In-Reply-To: <alpine.LFD.2.00.1308221558160.2993@ja.ssi.bg>

2013/8/22 Julian Anastasov <ja@ssi.bg>:
>
>         Hello,
>
> On Thu, 22 Aug 2013, Drunkard Zhang wrote:
>
>> 2013/8/22 Julian Anastasov <ja@ssi.bg>:
>> >
>> >         No kernel options should be related to OPS. I assume
>> > you are not using the SH scheduler. Make sure the OPS mode
>> > is properly applied to the virtual service, check for "ops"
>> > in the configuration:
>> >
>> > cat /proc/net/ip_vs
>>
>> Still no lucky here, ops is set in running config, but it's not like
>> that in real world.
>>
>> vs3 ~ # cat /proc/net/ip_vs
>> IP Virtual Server version 1.2.1 (size=1024)
>> Prot LocalAddress:Port Scheduler Flags
>>   -> RemoteAddress:Port Forward Weight ActiveConn InActConn
>> UDP  96A46478:0202 wrr ops
>
>>   -> 96A46450:0202      Route   25     0          1
>
>         The OPS connections are accounted in InActConn
> for a very short period, they live up to 1 jiffie, eg. 10ms.
> Also, WRR should be reliable for OPS while other
> schedulers (eg. *LC) are not suitable.

I noticed this too. While ops working, the InActConn is always
changing too, if it's fixed, the ops is not working.

>> And the traffic routed to each realserver didn't following weight I
>> set, it's routed pretty much one to one. I got 17 udp sources sending
>> to 16 different realservers, the others are bonding to another VIP.
>>
>> Prot LocalAddress:Port                 CPS    InPPS   OutPPS    InBPS   OutBPS
>>   -> RemoteAddress:Port
>> UDP  x.x.x.120:514                 0    67622        0 12339373        0
>>   -> x.x.x.65:514                  0       29        0     2895        0
>>   -> x.x.x.66:514                  0      225        0    21850        0
>
>         Do you see the same problem with ipvsadm -Ln --stats ?
> ipvsadm -Z may be needed to zero the stats after restoring all
> rules. "Conns" counter in stats should be according to WRR
> weights, it shows the scheduler decisions.

After every restore, the stats also zeroed, right? While, ops still not working.

vs3 ~/pkgs # ./ipvsadm -Z
vs3 ~/pkgs # ./ipvsadm -ln --stats -u [snipped]
Prot LocalAddress:Port               Conns   InPkts  OutPkts  InBytes OutBytes
  -> RemoteAddress:Port
UDP  x.x.x.120:514                 0 12497040        0    2572M        0
  -> x.x.x.65:514                  0     3975        0   394171        0
  -> x.x.x.66:514                  0    48466        0  4835716        0
  -> x.x.x.67:514                  0   407051        0 58479621        0
  -> x.x.x.68:514                  0   561120        0 85289892        0
  -> x.x.x.69:514                  0    30958        0  3120506        0
  -> x.x.x.70:514                  0   645475        0  100552K        0
  -> x.x.x.71:514                  0   147228        0 14560649        0
  -> x.x.x.72:514                  0   535693        0 84069390        0
  -> x.x.x.73:514                  0   564787        0 88165140        0
  -> x.x.x.74:514                  0   346734        0 53256088        0
  -> x.x.x.75:514                  0    47232        0  4801578        0
  -> x.x.x.76:514                  0  1175288        0  192699K        0
  -> x.x.x.77:514                  0   254915        0 25939720        0
  -> x.x.x.78:514                  0  2701531        0  652417K        0
  -> x.x.x.79:514                  0  2426686        0  573897K        0
  -> x.x.x.80:514                  0  2599901        0  629793K        0
  -> x.x.x.81:514                  0        0        0        0        0
  -> x.x.x.82:514                  0        0        0        0        0
  -> x.x.x.83:514                  0        0        0        0        0
  -> x.x.x.84:514                  0        0        0        0        0
  -> x.x.x.85:514                  0        0        0        0        0
  -> x.x.x.86:514                  0        0        0        0        0
  -> x.x.x.87:514                  0        0        0        0        0
  -> x.x.x.88:514                  0        0        0        0        0
  -> x.x.x.89:514                  0        0        0        0        0

>         In your rates listing CPS 0 is confusing, even for OPS.
> Is it from the new ipvsadm?

Yes, latest git version. When CPS is changing, the ops works, or it's not.

^ permalink raw reply

* Re: [PATCH ipsec 2/2] ipv6: set skb->protocol on tcp, raw and ip6_append_data genereated skbs
From: Eric Dumazet @ 2013-08-22 23:59 UTC (permalink / raw)
  To: Hannes Frederic Sowa; +Cc: Steffen Klassert, David Miller, netdev
In-Reply-To: <20130822195406.GA4745@order.stressinduktion.org>

On Thu, 2013-08-22 at 21:54 +0200, Hannes Frederic Sowa wrote:
> Currently we don't initialize skb->protocol when transmitting data via
> tcp, raw(with and without inclhdr) or udp+ufo or appending data directly
> to the socket transmit queue (via ip6_append_data). This needs to be
> done so that we can get the correct mtu in the xfrm layer.
> 
> Setting of skb->protocol happens only in functions where we also have
> a transmitting socket and a new skb, so we don't overwrite old values.
> 
> Cc: Steffen Klassert <steffen.klassert@secunet.com>
> Cc: Eric Dumazet <eric.dumazet@gmail.com>
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> ---

Seems good to me.

Acked-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply

* [net-next v2 3/8] i40e: driver ethtool core
From: Jeff Kirsher @ 2013-08-23  2:15 UTC (permalink / raw)
  To: davem; +Cc: e1000-devel, netdev, Jesse Brandeburg, gospo, sassmann
In-Reply-To: <1377224142-25160-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Jesse Brandeburg <jesse.brandeburg@intel.com>

This patch contains the ethtool interface and implementation.

The goal in this patch series is minimal functionality while not
including much in the way of "set support."

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Shannon Nelson <shannon.nelson@intel.com>
CC: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
CC: e1000-devel@lists.sourceforge.net
Tested-by: Kavindya Deegala <kavindya.s.deegala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
v1: this is the initial submittal
v2: changes due to first round of netdev feedback, including:
    remove unimplemented ethtool skeleton functions
    as per bwh, use better stats naming like tx-N
    don't report stats we won't change
    remove buggy static variable
    don't force n_len
    don't double buffer in get_drvinfo
    use strlcpy
    don't use hacks for old kernels
    use some simplifying macros
    use rtnl_link_stats64
    report correct speeds
---
 drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 1413 ++++++++++++++++++++++++
 1 file changed, 1413 insertions(+)
 create mode 100644 drivers/net/ethernet/intel/i40e/i40e_ethtool.c

diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
new file mode 100644
index 0000000..91589a9
--- /dev/null
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -0,0 +1,1413 @@
+/*******************************************************************************
+
+  Intel Ethernet Controller XL710 Family Linux Driver
+  Copyright(c) 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for i40e */
+
+#include "i40e.h"
+#include "i40e_diag.h"
+
+struct i40e_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+};
+
+#define I40E_STAT(_type, _name, _stat) { \
+	.stat_string = _name, \
+	.sizeof_stat = FIELD_SIZEOF(_type, _stat), \
+	.stat_offset = offsetof(_type, _stat) \
+}
+#define I40E_NETDEV_STAT(_net_stat) \
+		I40E_STAT(struct net_device_stats, #_net_stat, _net_stat)
+#define I40E_PF_STAT(_name, _stat) \
+		I40E_STAT(struct i40e_pf, _name, _stat)
+#define I40E_VSI_STAT(_name, _stat) \
+		I40E_STAT(struct i40e_vsi, _name, _stat)
+
+static const struct i40e_stats i40e_gstrings_net_stats[] = {
+	I40E_NETDEV_STAT(rx_packets),
+	I40E_NETDEV_STAT(tx_packets),
+	I40E_NETDEV_STAT(rx_bytes),
+	I40E_NETDEV_STAT(tx_bytes),
+	I40E_NETDEV_STAT(rx_errors),
+	I40E_NETDEV_STAT(tx_errors),
+	I40E_NETDEV_STAT(rx_dropped),
+	I40E_NETDEV_STAT(tx_dropped),
+	I40E_NETDEV_STAT(multicast),
+	I40E_NETDEV_STAT(collisions),
+	I40E_NETDEV_STAT(rx_length_errors),
+	I40E_NETDEV_STAT(rx_crc_errors),
+};
+
+/* These PF_STATs might look like duplicates of some NETDEV_STATs,
+ * but they are separate.  This device supports Virtualization, and
+ * as such might have several netdevs supporting VMDq and FCoE going
+ * through a single port.  The NETDEV_STATs are for individual netdevs
+ * seen at the top of the stack, and the PF_STATs are for the physical
+ * function at the bottom of the stack hosting those netdevs.
+ *
+ * The PF_STATs are appended to the netdev stats only when ethtool -S
+ * is queried on the base PF netdev, not on the VMDq or FCoE netdev.
+ */
+static struct i40e_stats i40e_gstrings_stats[] = {
+	I40E_PF_STAT("rx_bytes", stats.eth.rx_bytes),
+	I40E_PF_STAT("tx_bytes", stats.eth.tx_bytes),
+	I40E_PF_STAT("rx_errors", stats.eth.rx_errors),
+	I40E_PF_STAT("tx_errors", stats.eth.tx_errors),
+	I40E_PF_STAT("rx_dropped", stats.eth.rx_discards),
+	I40E_PF_STAT("tx_dropped", stats.eth.tx_discards),
+	I40E_PF_STAT("tx_dropped_link_down", stats.tx_dropped_link_down),
+	I40E_PF_STAT("crc_errors", stats.crc_errors),
+	I40E_PF_STAT("illegal_bytes", stats.illegal_bytes),
+	I40E_PF_STAT("mac_local_faults", stats.mac_local_faults),
+	I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults),
+	I40E_PF_STAT("rx_length_errors", stats.rx_length_errors),
+	I40E_PF_STAT("link_xon_rx", stats.link_xon_rx),
+	I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx),
+	I40E_PF_STAT("link_xon_tx", stats.link_xon_tx),
+	I40E_PF_STAT("link_xoff_tx", stats.link_xoff_tx),
+	I40E_PF_STAT("rx_size_64", stats.rx_size_64),
+	I40E_PF_STAT("rx_size_127", stats.rx_size_127),
+	I40E_PF_STAT("rx_size_255", stats.rx_size_255),
+	I40E_PF_STAT("rx_size_511", stats.rx_size_511),
+	I40E_PF_STAT("rx_size_1023", stats.rx_size_1023),
+	I40E_PF_STAT("rx_size_1522", stats.rx_size_1522),
+	I40E_PF_STAT("rx_size_big", stats.rx_size_big),
+	I40E_PF_STAT("tx_size_64", stats.tx_size_64),
+	I40E_PF_STAT("tx_size_127", stats.tx_size_127),
+	I40E_PF_STAT("tx_size_255", stats.tx_size_255),
+	I40E_PF_STAT("tx_size_511", stats.tx_size_511),
+	I40E_PF_STAT("tx_size_1023", stats.tx_size_1023),
+	I40E_PF_STAT("tx_size_1522", stats.tx_size_1522),
+	I40E_PF_STAT("tx_size_big", stats.tx_size_big),
+	I40E_PF_STAT("rx_undersize", stats.rx_undersize),
+	I40E_PF_STAT("rx_fragments", stats.rx_fragments),
+	I40E_PF_STAT("rx_oversize", stats.rx_oversize),
+	I40E_PF_STAT("rx_jabber", stats.rx_jabber),
+	I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
+};
+
+#define I40E_QUEUE_STATS_LEN(n) \
+  ((((struct i40e_netdev_priv *)netdev_priv((n)))->vsi->num_queue_pairs + \
+    ((struct i40e_netdev_priv *)netdev_priv((n)))->vsi->num_queue_pairs) * 2)
+#define I40E_GLOBAL_STATS_LEN	ARRAY_SIZE(i40e_gstrings_stats)
+#define I40E_NETDEV_STATS_LEN   ARRAY_SIZE(i40e_gstrings_net_stats)
+#define I40E_VSI_STATS_LEN(n)   (I40E_NETDEV_STATS_LEN + \
+				 I40E_QUEUE_STATS_LEN((n)))
+#define I40E_PFC_STATS_LEN ( \
+		(FIELD_SIZEOF(struct i40e_pf, stats.priority_xoff_rx) + \
+		 FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_rx) + \
+		 FIELD_SIZEOF(struct i40e_pf, stats.priority_xoff_tx) + \
+		 FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_tx) + \
+		 FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_2_xoff)) \
+		 / sizeof(u64))
+#define I40E_PF_STATS_LEN(n)    (I40E_GLOBAL_STATS_LEN + \
+				 I40E_PFC_STATS_LEN + \
+				 I40E_VSI_STATS_LEN((n)))
+
+enum i40e_ethtool_test_id {
+	I40E_ETH_TEST_REG = 0,
+	I40E_ETH_TEST_EEPROM,
+	I40E_ETH_TEST_INTR,
+	I40E_ETH_TEST_LOOPBACK,
+	I40E_ETH_TEST_LINK,
+};
+
+static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = {
+	"Register test  (offline)",
+	"Eeprom test    (offline)",
+	"Interrupt test (offline)",
+	"Loopback test  (offline)",
+	"Link test   (on/offline)"
+};
+
+#define I40E_TEST_LEN (sizeof(i40e_gstrings_test) / ETH_GSTRING_LEN)
+
+/**
+ * i40e_get_settings - Get Link Speed and Duplex settings
+ * @netdev: network interface device structure
+ * @ecmd: ethtool command
+ *
+ * Reports speed/duplex settings based on media_type
+ **/
+static int i40e_get_settings(struct net_device *netdev,
+			     struct ethtool_cmd *ecmd)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_pf *pf = np->vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	struct i40e_link_status *hw_link_info = &hw->phy.link_info;
+	u32 link_speed = hw_link_info->link_speed;
+	bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP;
+
+	/* hardware is either in 40G mode or 10G mode
+	 * NOTE: this section initializes supported and advertising
+	 */
+	switch (hw_link_info->phy_type) {
+	case I40E_PHY_TYPE_40GBASE_CR4:
+	case I40E_PHY_TYPE_40GBASE_CR4_CU:
+		ecmd->supported = SUPPORTED_40000baseCR4_Full;
+		ecmd->advertising = ADVERTISED_40000baseCR4_Full;
+		break;
+	case I40E_PHY_TYPE_40GBASE_KR4:
+		ecmd->supported = SUPPORTED_40000baseKR4_Full;
+		ecmd->advertising = ADVERTISED_40000baseKR4_Full;
+		break;
+	case I40E_PHY_TYPE_40GBASE_SR4:
+		ecmd->supported = SUPPORTED_40000baseSR4_Full;
+		ecmd->advertising = ADVERTISED_40000baseSR4_Full;
+		break;
+	case I40E_PHY_TYPE_40GBASE_LR4:
+		ecmd->supported = SUPPORTED_40000baseLR4_Full;
+		ecmd->advertising = ADVERTISED_40000baseLR4_Full;
+		break;
+	case I40E_PHY_TYPE_10GBASE_KX4:
+		ecmd->supported = SUPPORTED_10000baseKX4_Full;
+		ecmd->advertising = ADVERTISED_10000baseKX4_Full;
+		break;
+	case I40E_PHY_TYPE_10GBASE_KR:
+		ecmd->supported = SUPPORTED_10000baseKR_Full;
+		ecmd->advertising = ADVERTISED_10000baseKR_Full;
+		break;
+	case I40E_PHY_TYPE_10GBASE_T:
+	default:
+		ecmd->supported = SUPPORTED_10000baseT_Full;
+		ecmd->advertising = ADVERTISED_10000baseT_Full;
+		break;
+	}
+
+	/* for now just say autoneg all the time */
+	ecmd->supported |= SUPPORTED_Autoneg;
+
+	if (hw->phy.media_type == I40E_MEDIA_TYPE_BACKPLANE) {
+		ecmd->supported |= SUPPORTED_Backplane;
+		ecmd->advertising |= ADVERTISED_Backplane;
+		ecmd->port = PORT_NONE;
+	} else if (hw->phy.media_type == I40E_MEDIA_TYPE_BASET) {
+		ecmd->supported |= SUPPORTED_TP;
+		ecmd->advertising |= ADVERTISED_TP;
+		ecmd->port = PORT_TP;
+	} else {
+		ecmd->supported |= SUPPORTED_FIBRE;
+		ecmd->advertising |= ADVERTISED_FIBRE;
+		ecmd->port = PORT_FIBRE;
+	}
+
+	ecmd->transceiver = XCVR_EXTERNAL;
+
+	if (link_up) {
+		switch (link_speed) {
+		case I40E_LINK_SPEED_40GB:
+			/* need a SPEED_40000 in ethtool.h */
+			ecmd->speed = 40000;
+			break;
+		case I40E_LINK_SPEED_10GB:
+			ecmd->speed = SPEED_10000;
+			break;
+		default:
+			break;
+		}
+		ecmd->duplex = DUPLEX_FULL;
+	} else {
+		ecmd->speed = SPEED_UNKNOWN;
+		ecmd->duplex = DUPLEX_UNKNOWN;
+	}
+
+	return 0;
+}
+
+
+/**
+ * i40e_get_pauseparam -  Get Flow Control status
+ * Return tx/rx-pause status
+ **/
+static void i40e_get_pauseparam(struct net_device *netdev,
+				struct ethtool_pauseparam *pause)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_pf *pf = np->vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	struct i40e_link_status *hw_link_info = &hw->phy.link_info;
+
+	pause->autoneg =
+		((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ?
+		  AUTONEG_ENABLE : AUTONEG_DISABLE);
+
+	pause->rx_pause = 0;
+	pause->tx_pause = 0;
+	if (hw_link_info->an_info & I40E_AQ_LINK_PAUSE_RX)
+		pause->rx_pause = 1;
+	if (hw_link_info->an_info & I40E_AQ_LINK_PAUSE_TX)
+		pause->tx_pause = 1;
+}
+
+static u32 i40e_get_msglevel(struct net_device *netdev)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_pf *pf = np->vsi->back;
+
+	return pf->msg_enable;
+}
+
+static void i40e_set_msglevel(struct net_device *netdev, u32 data)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_pf *pf = np->vsi->back;
+
+	if (I40E_DEBUG_USER & data)
+		pf->hw.debug_mask = data;
+	pf->msg_enable = data;
+}
+
+static int i40e_get_regs_len(struct net_device *netdev)
+{
+	int reg_count = 0;
+	int i;
+
+	for (i = 0; i40e_reg_list[i].offset != 0; i++)
+		reg_count += i40e_reg_list[i].elements;
+
+	return reg_count * sizeof(u32);
+}
+
+static void i40e_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
+			  void *p)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_pf *pf = np->vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	u32 *reg_buf = p;
+	int i, j, ri;
+	u32 reg;
+
+	/* Tell ethtool which driver-version-specific regs output we have.
+	 *
+	 * At some point, if we have ethtool doing special formatting of
+	 * this data, it will rely on this version number to know how to
+	 * interpret things.  Hence, this needs to be updated if/when the
+	 * diags register table is changed.
+	 */
+	regs->version = 1;
+
+	/* loop through the diags reg table for what to print */
+	ri = 0;
+	for (i = 0; i40e_reg_list[i].offset != 0; i++) {
+		for (j = 0; j < i40e_reg_list[i].elements; j++) {
+			reg = i40e_reg_list[i].offset
+				+ (j * i40e_reg_list[i].stride);
+			reg_buf[ri++] = rd32(hw, reg);
+		}
+	}
+
+	return;
+}
+
+static void i40e_get_drvinfo(struct net_device *netdev,
+			     struct ethtool_drvinfo *drvinfo)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+
+	strlcpy(drvinfo->driver, i40e_driver_name, sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, i40e_driver_version_str,
+		sizeof(drvinfo->version));
+	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+		 "FW %d.%d API %d.%d NVM %02d.%02d.%02d",
+		 pf->hw.aq.fw_maj_ver, pf->hw.aq.fw_min_ver,
+		 pf->hw.aq.api_maj_ver, pf->hw.aq.api_min_ver,
+		 ((pf->hw.nvm.version >> 12) & 0xf),
+		 ((pf->hw.nvm.version >> 4) & 0xff),
+		 (pf->hw.nvm.version & 0xf));
+	strlcpy(drvinfo->bus_info, pci_name(pf->pdev),
+		sizeof(drvinfo->bus_info));
+}
+
+static void i40e_get_ringparam(struct net_device *netdev,
+			       struct ethtool_ringparam *ring)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_pf *pf = np->vsi->back;
+	struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+
+	ring->rx_max_pending = I40E_MAX_NUM_DESCRIPTORS;
+	ring->tx_max_pending = I40E_MAX_NUM_DESCRIPTORS;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = vsi->rx_rings[0].count;
+	ring->tx_pending = vsi->tx_rings[0].count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static int i40e_set_ringparam(struct net_device *netdev,
+			      struct ethtool_ringparam *ring)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	struct i40e_ring *tx_rings = NULL, *rx_rings = NULL;
+	u32 new_rx_count, new_tx_count;
+	int i, err = 0;
+
+	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+		return -EINVAL;
+
+	new_tx_count = clamp_t(u32, ring->tx_pending,
+			       I40E_MIN_NUM_DESCRIPTORS,
+			       I40E_MAX_NUM_DESCRIPTORS);
+	new_tx_count = ALIGN(new_tx_count, I40E_REQ_DESCRIPTOR_MULTIPLE);
+
+	new_rx_count = clamp_t(u32, ring->rx_pending,
+			       I40E_MIN_NUM_DESCRIPTORS,
+			       I40E_MAX_NUM_DESCRIPTORS);
+	new_rx_count = ALIGN(new_rx_count, I40E_REQ_DESCRIPTOR_MULTIPLE);
+
+	/* if nothing to do return success */
+	if ((new_tx_count == vsi->tx_rings[0].count) &&
+	    (new_rx_count == vsi->rx_rings[0].count))
+		return 0;
+
+	while (test_and_set_bit(__I40E_CONFIG_BUSY, &pf->state))
+		usleep_range(1000, 2000);
+
+	if (!netif_running(vsi->netdev)) {
+		/* simple case - set for the next time the netdev is started */
+		for (i = 0; i < vsi->num_queue_pairs; i++) {
+			vsi->tx_rings[i].count = new_tx_count;
+			vsi->rx_rings[i].count = new_rx_count;
+		}
+		goto done;
+	}
+
+	/* We can't just free everything and then setup again,
+	 * because the ISRs in MSI-X mode get passed pointers
+	 * to the Tx and Rx ring structs.
+	 */
+
+	/* alloc updated Tx resources */
+	if (new_tx_count != vsi->tx_rings[0].count) {
+		netdev_info(netdev,
+			    "%s: Changing Tx descriptor count from %d to %d.\n",
+			    __func__, vsi->tx_rings[0].count, new_tx_count);
+		tx_rings = kcalloc(vsi->alloc_queue_pairs,
+				   sizeof(struct i40e_ring), GFP_KERNEL);
+		if (!tx_rings) {
+			err = -ENOMEM;
+			goto done;
+		}
+
+		for (i = 0; i < vsi->num_queue_pairs; i++) {
+			/* clone ring and setup updated count */
+			tx_rings[i] = vsi->tx_rings[i];
+			tx_rings[i].count = new_tx_count;
+			err = i40e_setup_tx_descriptors(&tx_rings[i]);
+			if (err) {
+				while (i) {
+					i--;
+					i40e_free_tx_resources(&tx_rings[i]);
+				}
+				kfree(tx_rings);
+				tx_rings = NULL;
+
+				goto done;
+			}
+		}
+	}
+
+	/* alloc updated Rx resources */
+	if (new_rx_count != vsi->rx_rings[0].count) {
+		netdev_info(netdev,
+			    "%s: Changing Rx descriptor count from %d to %d\n",
+			    __func__, vsi->rx_rings[0].count, new_rx_count);
+		rx_rings = kcalloc(vsi->alloc_queue_pairs,
+				   sizeof(struct i40e_ring), GFP_KERNEL);
+		if (!rx_rings) {
+			err = -ENOMEM;
+			goto free_tx;
+		}
+
+		for (i = 0; i < vsi->num_queue_pairs; i++) {
+			/* clone ring and setup updated count */
+			rx_rings[i] = vsi->rx_rings[i];
+			rx_rings[i].count = new_rx_count;
+			err = i40e_setup_rx_descriptors(&rx_rings[i]);
+			if (err) {
+				while (i) {
+					i--;
+					i40e_free_rx_resources(&rx_rings[i]);
+				}
+				kfree(rx_rings);
+				rx_rings = NULL;
+
+				goto free_tx;
+			}
+		}
+	}
+
+	/* Bring interface down, copy in the new ring info,
+	 * then restore the interface
+	 */
+	i40e_down(vsi);
+
+	if (tx_rings) {
+		for (i = 0; i < vsi->num_queue_pairs; i++) {
+			i40e_free_tx_resources(&vsi->tx_rings[i]);
+			vsi->tx_rings[i] = tx_rings[i];
+		}
+		kfree(tx_rings);
+		tx_rings = NULL;
+	}
+
+	if (rx_rings) {
+		for (i = 0; i < vsi->num_queue_pairs; i++) {
+			i40e_free_rx_resources(&vsi->rx_rings[i]);
+			vsi->rx_rings[i] = rx_rings[i];
+		}
+		kfree(rx_rings);
+		rx_rings = NULL;
+	}
+
+	i40e_up(vsi);
+
+free_tx:
+	/* error cleanup if the Rx allocations failed after getting Tx */
+	if (tx_rings) {
+		for (i = 0; i < vsi->num_queue_pairs; i++)
+			i40e_free_tx_resources(&tx_rings[i]);
+		kfree(tx_rings);
+		tx_rings = NULL;
+	}
+
+done:
+	clear_bit(__I40E_CONFIG_BUSY, &pf->state);
+
+	return err;
+}
+
+static int i40e_get_sset_count(struct net_device *netdev, int sset)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+
+	switch (sset) {
+	case ETH_SS_TEST:
+		return I40E_TEST_LEN;
+	case ETH_SS_STATS:
+		if (vsi == pf->vsi[pf->lan_vsi])
+			return I40E_PF_STATS_LEN(netdev);
+		else
+			return I40E_VSI_STATS_LEN(netdev);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void i40e_get_ethtool_stats(struct net_device *netdev,
+				   struct ethtool_stats *stats, u64 *data)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	struct rtnl_link_stats64 *net_stats = i40e_get_vsi_stats_struct(vsi);
+	char *p;
+	int i, j;
+
+	i40e_update_stats(vsi);
+
+	i = 0;
+	for (j = 0; j < I40E_NETDEV_STATS_LEN; j++) {
+		p = (char *)net_stats + i40e_gstrings_net_stats[j].stat_offset;
+		data[i++] = (i40e_gstrings_net_stats[j].sizeof_stat ==
+			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+	}
+	for (j = 0; j < vsi->num_queue_pairs; j++) {
+		data[i++] = vsi->tx_rings[j].tx_stats.packets;
+		data[i++] = vsi->tx_rings[j].tx_stats.bytes;
+	}
+	for (j = 0; j < vsi->num_queue_pairs; j++) {
+		data[i++] = vsi->rx_rings[j].rx_stats.packets;
+		data[i++] = vsi->rx_rings[j].rx_stats.bytes;
+	}
+	if (vsi == pf->vsi[pf->lan_vsi]) {
+		for (j = 0; j < I40E_GLOBAL_STATS_LEN; j++) {
+			p = (char *)pf + i40e_gstrings_stats[j].stat_offset;
+			data[i++] = (i40e_gstrings_stats[j].sizeof_stat ==
+				   sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+		}
+		for (j = 0; j < I40E_MAX_USER_PRIORITY; j++) {
+			data[i++] = pf->stats.priority_xon_tx[j];
+			data[i++] = pf->stats.priority_xoff_tx[j];
+		}
+		for (j = 0; j < I40E_MAX_USER_PRIORITY; j++) {
+			data[i++] = pf->stats.priority_xon_rx[j];
+			data[i++] = pf->stats.priority_xoff_rx[j];
+		}
+		for (j = 0; j < I40E_MAX_USER_PRIORITY; j++)
+			data[i++] = pf->stats.priority_xon_2_xoff[j];
+	}
+
+	return;
+}
+
+static void i40e_get_strings(struct net_device *netdev, u32 stringset,
+			     u8 *data)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	char *p = (char *)data;
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_TEST:
+		for (i = 0; i < I40E_TEST_LEN; i++) {
+			memcpy(data, i40e_gstrings_test[i], ETH_GSTRING_LEN);
+			data += ETH_GSTRING_LEN;
+		}
+		break;
+	case ETH_SS_STATS:
+		for (i = 0; i < I40E_NETDEV_STATS_LEN; i++) {
+			snprintf(p, ETH_GSTRING_LEN, "%s",
+				 i40e_gstrings_net_stats[i].stat_string);
+			p += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < vsi->num_queue_pairs; i++) {
+			snprintf(p, ETH_GSTRING_LEN, "tx-%u.tx_packets", i);
+			p += ETH_GSTRING_LEN;
+			snprintf(p, ETH_GSTRING_LEN, "tx-%u.tx_bytes", i);
+			p += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < vsi->num_queue_pairs; i++) {
+			snprintf(p, ETH_GSTRING_LEN, "rx-%u.rx_packets", i);
+			p += ETH_GSTRING_LEN;
+			snprintf(p, ETH_GSTRING_LEN, "rx-%u.rx_bytes", i);
+			p += ETH_GSTRING_LEN;
+		}
+		if (vsi == pf->vsi[pf->lan_vsi]) {
+			for (i = 0; i < I40E_GLOBAL_STATS_LEN; i++) {
+				snprintf(p, ETH_GSTRING_LEN, "port.%s",
+					i40e_gstrings_stats[i].stat_string);
+				p += ETH_GSTRING_LEN;
+			}
+			for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+				snprintf(p, ETH_GSTRING_LEN,
+					 "port.tx_priority_%u_xon", i);
+				p += ETH_GSTRING_LEN;
+				snprintf(p, ETH_GSTRING_LEN,
+					 "port.tx_priority_%u_xoff", i);
+				p += ETH_GSTRING_LEN;
+			}
+			for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+				snprintf(p, ETH_GSTRING_LEN,
+					 "port.rx_priority_%u_xon", i);
+				p += ETH_GSTRING_LEN;
+				snprintf(p, ETH_GSTRING_LEN,
+					 "port.rx_priority_%u_xoff", i);
+				p += ETH_GSTRING_LEN;
+			}
+			for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+				snprintf(p, ETH_GSTRING_LEN,
+					 "port.rx_priority_%u_xon_2_xoff", i);
+				p += ETH_GSTRING_LEN;
+			}
+		}
+		/* BUG_ON(p - data != I40E_STATS_LEN * ETH_GSTRING_LEN); */
+		break;
+	}
+}
+
+static int i40e_get_ts_info(struct net_device *dev,
+			    struct ethtool_ts_info *info)
+{
+	return ethtool_op_get_ts_info(dev, info);
+}
+
+static int i40e_link_test(struct i40e_pf *pf, u64 *data)
+{
+	bool link_up;
+
+	link_up = i40e_get_link_status(&pf->hw);
+	if (link_up)
+		*data = 0;
+	else
+		*data = 1;
+
+	return *data;
+}
+
+static int i40e_reg_test(struct i40e_pf *pf, u64 *data)
+{
+	enum i40e_status_code ret;
+
+	ret = i40e_diag_reg_test(&pf->hw);
+	*data = ret;
+
+	return ret;
+}
+
+static int i40e_eeprom_test(struct i40e_pf *pf, u64 *data)
+{
+	enum i40e_status_code ret;
+
+	ret = i40e_diag_eeprom_test(&pf->hw);
+	*data = ret;
+
+	return ret;
+}
+
+static int i40e_intr_test(struct i40e_pf *pf, u64 *data)
+{
+	*data = I40E_ERR_NOT_IMPLEMENTED;
+
+	return *data;
+}
+
+static int i40e_loopback_test(struct i40e_pf *pf, u64 *data)
+{
+	*data = I40E_ERR_NOT_IMPLEMENTED;
+
+	return *data;
+}
+
+static void i40e_diag_test(struct net_device *netdev,
+			   struct ethtool_test *eth_test, u64 *data)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_pf *pf = np->vsi->back;
+
+	set_bit(__I40E_TESTING, &pf->state);
+	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+		/* Offline tests */
+
+		netdev_info(netdev, "%s: offline testing starting\n", __func__);
+
+		/* Link test performed before hardware reset
+		 * so autoneg doesn't interfere with test result
+		 */
+		netdev_info(netdev, "%s: link test starting\n", __func__);
+		if (i40e_link_test(pf, &data[I40E_ETH_TEST_LINK]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		netdev_info(netdev, "%s: register test starting\n", __func__);
+		if (i40e_reg_test(pf, &data[I40E_ETH_TEST_REG]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+		netdev_info(netdev, "%s: eeprom test starting\n", __func__);
+		if (i40e_eeprom_test(pf, &data[I40E_ETH_TEST_EEPROM]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+		netdev_info(netdev, "%s: interrupt test starting\n", __func__);
+		if (i40e_intr_test(pf, &data[I40E_ETH_TEST_INTR]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+		netdev_info(netdev, "%s: loopback test starting\n", __func__);
+		if (i40e_loopback_test(pf, &data[I40E_ETH_TEST_LOOPBACK]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+	} else {
+		netdev_info(netdev, "%s: online test starting\n", __func__);
+		/* Online tests */
+		if (i40e_link_test(pf, &data[I40E_ETH_TEST_LINK]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		/* Offline only tests, not run in online; pass by default */
+		data[I40E_ETH_TEST_REG] = 0;
+		data[I40E_ETH_TEST_EEPROM] = 0;
+		data[I40E_ETH_TEST_INTR] = 0;
+		data[I40E_ETH_TEST_LOOPBACK] = 0;
+
+		clear_bit(__I40E_TESTING, &pf->state);
+	}
+}
+
+static void i40e_get_wol(struct net_device *netdev,
+			 struct ethtool_wolinfo *wol)
+{
+	wol->supported = 0;
+	wol->wolopts = 0;
+}
+
+static int i40e_nway_reset(struct net_device *netdev)
+{
+	/* restart autonegotiation */
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_pf *pf = np->vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	enum i40e_status_code ret = 0;
+
+	ret = i40e_aq_set_link_restart_an(hw, NULL);
+	if (ret != I40E_SUCCESS)
+		netdev_info(netdev, "%s: link restart failed, aq_err=%d\n",
+			    __func__, pf->hw.aq.asq_last_status);
+
+	return ret;
+}
+
+static int i40e_set_phys_id(struct net_device *netdev,
+			    enum ethtool_phys_id_state state)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_pf *pf = np->vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	int blink_freq = 2;
+
+	switch (state) {
+	case ETHTOOL_ID_ACTIVE:
+		pf->led_status = i40e_led_get(hw);
+		return blink_freq;
+	case ETHTOOL_ID_ON:
+		i40e_led_set(hw, 0xF);
+		break;
+	case ETHTOOL_ID_OFF:
+		i40e_led_set(hw, 0x0);
+		break;
+	case ETHTOOL_ID_INACTIVE:
+		i40e_led_set(hw, pf->led_status);
+		break;
+	}
+
+	return 0;
+}
+
+/* NOTE: i40e hardware uses a conversion factor of 2 for Interrupt
+ * Throttle Rate (ITR) ie. ITR(1) = 2us ITR(10) = 20 us, and also
+ * 125us (8000 interrupts per second) == ITR(62)
+ */
+
+static int i40e_get_coalesce(struct net_device *netdev,
+			     struct ethtool_coalesce *ec)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+
+	ec->tx_max_coalesced_frames_irq = vsi->work_limit;
+	ec->rx_max_coalesced_frames_irq = vsi->work_limit;
+
+	if (ITR_IS_DYNAMIC(vsi->rx_itr_setting))
+		ec->rx_coalesce_usecs = 1;
+	else
+		ec->rx_coalesce_usecs = vsi->rx_itr_setting;
+
+	if (ITR_IS_DYNAMIC(vsi->tx_itr_setting))
+		ec->tx_coalesce_usecs = 1;
+	else
+		ec->tx_coalesce_usecs = vsi->tx_itr_setting;
+
+	return 0;
+}
+
+static int i40e_set_coalesce(struct net_device *netdev,
+			     struct ethtool_coalesce *ec)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	u16 vector;
+	struct i40e_q_vector *q_vector;
+	int i;
+
+	if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
+		vsi->work_limit = ec->tx_max_coalesced_frames_irq;
+
+	switch (ec->rx_coalesce_usecs) {
+	case 0:
+		vsi->rx_itr_setting = 0;
+		break;
+	case 1:
+		vsi->rx_itr_setting = (I40E_ITR_DYNAMIC |
+				       ITR_REG_TO_USEC(I40E_ITR_RX_DEF));
+		break;
+	default:
+		if ((ec->rx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
+		    (ec->rx_coalesce_usecs > (I40E_MAX_ITR << 1)))
+			return -EINVAL;
+		vsi->rx_itr_setting = ec->rx_coalesce_usecs;
+		break;
+	}
+
+	switch (ec->tx_coalesce_usecs) {
+	case 0:
+		vsi->tx_itr_setting = 0;
+		break;
+	case 1:
+		vsi->tx_itr_setting = (I40E_ITR_DYNAMIC |
+				       ITR_REG_TO_USEC(I40E_ITR_TX_DEF));
+		break;
+	default:
+		if ((ec->tx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
+		    (ec->tx_coalesce_usecs > (I40E_MAX_ITR << 1)))
+			return -EINVAL;
+		vsi->tx_itr_setting = ec->tx_coalesce_usecs;
+		break;
+	}
+
+	vector = vsi->base_vector;
+	q_vector = vsi->q_vectors;
+	for (i = 0; i < vsi->num_q_vectors; i++, vector++, q_vector++) {
+		q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
+		wr32(hw, I40E_PFINT_ITRN(0, vector - 1), q_vector->rx.itr);
+		q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
+		wr32(hw, I40E_PFINT_ITRN(1, vector - 1), q_vector->tx.itr);
+		flush(hw);
+	}
+
+	return 0;
+}
+
+/**
+ * i40e_get_rss_hash_opts - Get RSS hash Input Set for each flow type
+ * @pf: pointer to the physical function struct
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the flow is supported, else Invalid Input.
+ **/
+static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
+{
+	cmd->data = 0;
+
+	/* Report default options for RSS on i40e */
+	switch (cmd->flow_type) {
+	case TCP_V4_FLOW:
+	case UDP_V4_FLOW:
+		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+	/* fall through to add IP fields */
+	case SCTP_V4_FLOW:
+	case AH_ESP_V4_FLOW:
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case IPV4_FLOW:
+		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+		break;
+	case TCP_V6_FLOW:
+	case UDP_V6_FLOW:
+		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+	/* fall through to add IP fields */
+	case SCTP_V6_FLOW:
+	case AH_ESP_V6_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+	case IPV6_FLOW:
+		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * i40e_get_rxnfc - command to get RX flow classification rules
+ * @netdev: network interface device structure
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the command is supported.
+ **/
+static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
+			  u32 *rule_locs)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	int ret = -EOPNOTSUPP;
+
+	switch (cmd->cmd) {
+	case ETHTOOL_GRXRINGS:
+		cmd->data = vsi->alloc_queue_pairs;
+		ret = 0;
+		break;
+	case ETHTOOL_GRXFH:
+		ret = i40e_get_rss_hash_opts(pf, cmd);
+		break;
+	case ETHTOOL_GRXCLSRLCNT:
+		ret = 0;
+		break;
+	case ETHTOOL_GRXCLSRULE:
+		ret = 0;
+		break;
+	case ETHTOOL_GRXCLSRLALL:
+		cmd->data = 500;
+		ret = 0;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * i40e_set_rss_hash_opt - Enable/Disable flow types for RSS hash
+ * @pf: pointer to the physical function struct
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the flow input set is supported.
+ **/
+static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
+{
+	struct i40e_hw *hw = &pf->hw;
+	u64 hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
+		   ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
+
+	/* RSS does not support anything other than hashing
+	 * to queues on src and dst IPs and ports
+	 */
+	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
+			  RXH_L4_B_0_1 | RXH_L4_B_2_3))
+		return -EINVAL;
+
+	/* We need at least the IP SRC and DEST fields for hashing */
+	if (!(nfc->data & RXH_IP_SRC) ||
+	    !(nfc->data & RXH_IP_DST))
+		return -EINVAL;
+
+	switch (nfc->flow_type) {
+	case TCP_V4_FLOW:
+		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+		case 0:
+			hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
+			break;
+		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case TCP_V6_FLOW:
+		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+		case 0:
+			hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
+			break;
+		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case UDP_V4_FLOW:
+		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+		case 0:
+			hena &=
+			~(((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
+			((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) |
+			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4));
+			break;
+		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			hena |=
+			(((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP)  |
+			((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) |
+			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4));
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case UDP_V6_FLOW:
+		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+		case 0:
+			hena &=
+			~(((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
+			((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP) |
+			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6));
+			break;
+		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			hena |=
+			(((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP)  |
+			((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP) |
+			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6));
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case AH_ESP_V4_FLOW:
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case SCTP_V4_FLOW:
+		if ((nfc->data & RXH_L4_B_0_1) ||
+		    (nfc->data & RXH_L4_B_2_3))
+			return -EINVAL;
+		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
+		break;
+	case AH_ESP_V6_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+	case SCTP_V6_FLOW:
+		if ((nfc->data & RXH_L4_B_0_1) ||
+		    (nfc->data & RXH_L4_B_2_3))
+			return -EINVAL;
+		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
+		break;
+	case IPV4_FLOW:
+		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
+			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4);
+		break;
+	case IPV6_FLOW:
+		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
+			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
+	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
+	flush(hw);
+
+	return 0;
+}
+
+#define IP_HEADER_OFFSET 14
+/**
+ * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required from the FDir descriptor
+ * @ethtool_rx_flow_spec: the flow spec
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static enum i40e_status_code i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
+				struct i40e_fdir_data *fd_data,
+				struct ethtool_rx_flow_spec *fsp, bool add)
+{
+	struct i40e_pf *pf = vsi->back;
+	enum i40e_status_code ret;
+	bool err = false;
+	int i;
+	struct iphdr *ip;
+	struct udphdr *udp;
+
+	ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
+	udp = (struct udphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
+	      + sizeof(struct iphdr));
+
+	ip->saddr = fsp->h_u.udp_ip4_spec.ip4src;
+	ip->daddr = fsp->h_u.udp_ip4_spec.ip4dst;
+	udp->source = fsp->h_u.udp_ip4_spec.psrc;
+	udp->dest = fsp->h_u.udp_ip4_spec.pdst;
+
+	for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
+	     i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) {
+		fd_data->pctype = i;
+		ret = i40e_program_fdir_filter(fd_data, pf, add);
+
+		if (ret != I40E_SUCCESS) {
+			dev_info(&pf->pdev->dev,
+				"%s: Filter command send failed for PCTYPE %d (ret = %d)\n",
+				__func__, fd_data->pctype, ret);
+			err = true;
+		} else {
+			dev_info(&pf->pdev->dev,
+				"%s: Filter OK for PCTYPE %d (ret = %d)\n",
+				 __func__,
+				fd_data->pctype, ret);
+		}
+	}
+
+	return err ? -EOPNOTSUPP : I40E_SUCCESS;
+}
+
+/**
+ * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required from the FDir descriptor
+ * @ethtool_rx_flow_spec: the flow spec
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static enum i40e_status_code i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
+				struct i40e_fdir_data *fd_data,
+				struct ethtool_rx_flow_spec *fsp, bool add)
+{
+	struct i40e_pf *pf = vsi->back;
+	enum i40e_status_code ret;
+	bool err = false;
+	struct iphdr *ip;
+	struct tcphdr *tcp;
+
+	ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
+	tcp = (struct tcphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
+	      + sizeof(struct iphdr));
+
+	ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
+	tcp->dest = fsp->h_u.tcp_ip4_spec.pdst;
+
+	fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
+	ret = i40e_program_fdir_filter(fd_data, pf, add);
+
+	if (ret != I40E_SUCCESS) {
+		dev_info(&pf->pdev->dev,
+			"%s: Filter command send failed for PCTYPE %d (ret = %d)\n",
+			 __func__, fd_data->pctype, ret);
+			err = true;
+	} else {
+		dev_info(&pf->pdev->dev, "%s: Filter OK for PCTYPE %d (ret = %d)\n",
+			 __func__, fd_data->pctype, ret);
+	}
+
+	ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
+	tcp->source = fsp->h_u.tcp_ip4_spec.psrc;
+
+	fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+
+	if (ret != I40E_SUCCESS) {
+		dev_info(&pf->pdev->dev,
+			"%s: Filter command send failed for PCTYPE %d (ret = %d)\n",
+			__func__, fd_data->pctype, ret);
+			err = true;
+	} else {
+		dev_info(&pf->pdev->dev,
+			"%s: Filter OK for PCTYPE %d (ret = %d)\n",
+			 __func__, fd_data->pctype, ret);
+	}
+
+	return err ? -EOPNOTSUPP : I40E_SUCCESS;
+}
+
+
+/**
+ * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required from the FDir descriptor
+ * @ethtool_rx_flow_spec: the flow spec
+ * @add: true adds a filter, false removes it
+ *
+ * Returns I40E_SUCCESS if the filters were successfully added or removed
+ **/
+static enum i40e_status_code i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
+				struct i40e_fdir_data *fd_data,
+				struct ethtool_rx_flow_spec *fsp, bool add)
+{
+	return -EOPNOTSUPP;
+}
+
+/**
+ * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @fsp: the ethtool flow spec
+ * @add: true adds a filter, false removes it
+ *
+ * Returns I40E_SUCCESS if the filters were successfully added or removed
+ **/
+static enum i40e_status_code i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
+				struct i40e_fdir_data *fd_data,
+				struct ethtool_rx_flow_spec *fsp, bool add)
+{
+	struct i40e_pf *pf = vsi->back;
+	enum i40e_status_code ret;
+	bool err = false;
+	int i;
+	struct iphdr *ip;
+
+	ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
+
+	ip->saddr = fsp->h_u.usr_ip4_spec.ip4src;
+	ip->daddr = fsp->h_u.usr_ip4_spec.ip4dst;
+	ip->protocol = fsp->h_u.usr_ip4_spec.proto;
+
+	for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
+	     i <= I40E_FILTER_PCTYPE_FRAG_IPV4;	i++) {
+		fd_data->pctype = i;
+		ret = i40e_program_fdir_filter(fd_data, pf, add);
+
+		if (ret != I40E_SUCCESS) {
+			dev_info(&pf->pdev->dev,
+				"%s: Filter command send failed for PCTYPE %d (ret = %d)\n",
+				__func__, fd_data->pctype, ret);
+				err = true;
+		} else {
+			dev_info(&pf->pdev->dev,
+				"%s: Filter OK for PCTYPE %d (ret = %d)\n",
+				 __func__, fd_data->pctype, ret);
+		}
+	}
+
+	return err ? -EOPNOTSUPP : I40E_SUCCESS;
+}
+
+/**
+ * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters for
+ * a specific flow spec based on their protocol
+ * @vsi: pointer to the targeted VSI
+ * @cmd: command to get or set RX flow classification rules
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
+			struct ethtool_rxnfc *cmd, bool add)
+{
+	struct i40e_fdir_data fd_data;
+	enum i40e_status_code ret = -EINVAL;
+	struct i40e_pf *pf;
+	struct ethtool_rx_flow_spec *fsp =
+		(struct ethtool_rx_flow_spec *)&cmd->fs;
+
+	if (!vsi)
+		return -EINVAL;
+
+	pf = vsi->back;
+
+	if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) &&
+	    (fsp->ring_cookie >= vsi->num_queue_pairs))
+		return -EINVAL;
+
+	/* Populate the Flow Director that we have at the moment
+	 * and allocate the raw packet buffer for the calling functions
+	 */
+	fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
+				     GFP_KERNEL);
+
+	if (!fd_data.raw_packet) {
+		dev_info(&pf->pdev->dev,
+			"%s: Could not allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	fd_data.q_index = fsp->ring_cookie;
+	fd_data.flex_off = 0;
+	fd_data.pctype = 0;
+	fd_data.dest_vsi = vsi->id;
+	fd_data.dest_ctl = 0;
+	fd_data.fd_status = 0;
+	fd_data.cnt_index = 0;
+	fd_data.fd_id = 0;
+
+	switch (fsp->flow_type & ~FLOW_EXT) {
+	case TCP_V4_FLOW:
+		ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
+		break;
+	case UDP_V4_FLOW:
+		ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
+		break;
+	case SCTP_V4_FLOW:
+		ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
+		break;
+	case IPV4_FLOW:
+		ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
+		break;
+	case IP_USER_FLOW:
+		switch (fsp->h_u.usr_ip4_spec.proto) {
+		case IPPROTO_TCP:
+			ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
+			break;
+		case IPPROTO_UDP:
+			ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
+			break;
+		case IPPROTO_SCTP:
+			ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
+			break;
+		default:
+			ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
+			break;
+		}
+		break;
+	default:
+		dev_info(&pf->pdev->dev, "%s: Could not specify spec type\n",
+			 __func__);
+		ret = -EINVAL;
+	}
+
+	kfree(fd_data.raw_packet);
+	fd_data.raw_packet = NULL;
+
+	return ret;
+}
+/**
+ * i40e_set_rxnfc - command to set RX flow classification rules
+ * @netdev: network interface device structure
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the command is supported.
+ **/
+static int i40e_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
+{
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	int ret = -EOPNOTSUPP;
+
+	switch (cmd->cmd) {
+	case ETHTOOL_SRXFH:
+		ret = i40e_set_rss_hash_opt(pf, cmd);
+		break;
+	case ETHTOOL_SRXCLSRLINS:
+		ret = i40e_add_del_fdir_ethtool(vsi, cmd, true);
+		break;
+	case ETHTOOL_SRXCLSRLDEL:
+		ret = i40e_add_del_fdir_ethtool(vsi, cmd, false);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct ethtool_ops i40e_ethtool_ops = {
+	.get_settings           = i40e_get_settings,
+	.get_drvinfo            = i40e_get_drvinfo,
+	.get_regs_len           = i40e_get_regs_len,
+	.get_regs               = i40e_get_regs,
+	.nway_reset             = i40e_nway_reset,
+	.get_link               = ethtool_op_get_link,
+	.get_wol                = i40e_get_wol,
+	.get_ringparam          = i40e_get_ringparam,
+	.set_ringparam          = i40e_set_ringparam,
+	.get_pauseparam         = i40e_get_pauseparam,
+	.get_msglevel           = i40e_get_msglevel,
+	.set_msglevel           = i40e_set_msglevel,
+	.get_rxnfc              = i40e_get_rxnfc,
+	.set_rxnfc              = i40e_set_rxnfc,
+	.self_test              = i40e_diag_test,
+	.get_strings            = i40e_get_strings,
+	.set_phys_id            = i40e_set_phys_id,
+	.get_sset_count         = i40e_get_sset_count,
+	.get_ethtool_stats      = i40e_get_ethtool_stats,
+	.get_coalesce           = i40e_get_coalesce,
+	.set_coalesce           = i40e_set_coalesce,
+	.get_ts_info            = i40e_get_ts_info,
+};
+
+void i40e_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &i40e_ethtool_ops);
+}
-- 
1.8.3.1


------------------------------------------------------------------------------
Introducing Performance Central, a new site from SourceForge and 
AppDynamics. Performance Central is your source for news, insights, 
analysis and resources for efficient Application Performance Management. 
Visit us today!
http://pubads.g.doubleclick.net/gampad/clk?id=48897511&iu=/4140/ostg.clktrk
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit http://communities.intel.com/community/wired

^ 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