[Arm-dev] [PATCH 07/11] Integrate upstream patches for X-Gene Enet driver

Fri Nov 11 02:47:49 UTC 2016
Duc Dang <dhdang at apm.com>

Signed-off-by: Duc Dang <dhdang at apm.com>
---
 ...net-xgene-fix-error-handling-during-reset.patch |  72 +++++
 ...-net-xgene-fix-backward-compatibility-fix.patch |  47 ++++
 ...t-apm-xgene-use-phydev-from-struct-net_de.patch | 150 +++++++++++
 ...014-drivers-net-xgene-Fix-MSS-programming.patch | 297 +++++++++++++++++++++
 ...net-xgene-fix-Use-GPIO-to-get-link-status.patch |  91 +++++++
 ...-xgene-fix-Disable-coalescing-on-v1-hardw.patch |  61 +++++
 ...-xgene-fix-Coalescing-values-for-v2-hardw.patch |  67 +++++
 SPECS/kernel-aarch64.spec                          |  15 ++
 8 files changed, 800 insertions(+)
 create mode 100644 SOURCES/1011-net-xgene-fix-error-handling-during-reset.patch
 create mode 100644 SOURCES/1012-net-xgene-fix-backward-compatibility-fix.patch
 create mode 100644 SOURCES/1013-net-ethernet-apm-xgene-use-phydev-from-struct-net_de.patch
 create mode 100644 SOURCES/1014-drivers-net-xgene-Fix-MSS-programming.patch
 create mode 100644 SOURCES/1015-drivers-net-xgene-fix-Use-GPIO-to-get-link-status.patch
 create mode 100644 SOURCES/1016-drivers-net-xgene-fix-Disable-coalescing-on-v1-hardw.patch
 create mode 100644 SOURCES/1017-drivers-net-xgene-fix-Coalescing-values-for-v2-hardw.patch

diff --git a/SOURCES/1011-net-xgene-fix-error-handling-during-reset.patch b/SOURCES/1011-net-xgene-fix-error-handling-during-reset.patch
new file mode 100644
index 0000000..e10b74f
--- /dev/null
+++ b/SOURCES/1011-net-xgene-fix-error-handling-during-reset.patch
@@ -0,0 +1,72 @@
+From 98ccf422fa923fe6d9288980faef4c1257387282 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd at arndb.de>
+Date: Fri, 26 Aug 2016 17:25:46 +0200
+Subject: [PATCH 1011/1018] net/xgene: fix error handling during reset
+
+The newly added reset logic uses helper functions for the MMIO that
+may fail. However, when the read operation fails, we end up writing
+back uninitialized data to the register, as gcc warns:
+
+drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c: In function 'xgene_enet_link_state':
+drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c:213:2: error: 'data' may be used uninitialized in this function [-Werror=maybe-uninitialized]
+drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c:209:6: note: 'data' was declared here
+  u32 data;
+
+We already print a warning to the console log if that happens,
+the best alternative that I can see is skip the rest of the reset
+sequence if the register value cannot be read: Most likely the
+write would fail as well, and if it succeeded, worse things could
+happen.
+
+Signed-off-by: Arnd Bergmann <arnd at arndb.de>
+Fixes: 3eb7cb9dc946 ("drivers: net: xgene: XFI PCS reset when link is down")
+Cc: Fushen Chen <fchen at apm.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
+index d672e71..279ee27 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
+@@ -155,19 +155,23 @@ static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata,
+ 			   rd_addr);
+ }
+ 
+-static void xgene_enet_rd_pcs(struct xgene_enet_pdata *pdata,
++static bool xgene_enet_rd_pcs(struct xgene_enet_pdata *pdata,
+ 			      u32 rd_addr, u32 *rd_data)
+ {
+ 	void __iomem *addr, *rd, *cmd, *cmd_done;
++	bool success;
+ 
+ 	addr = pdata->pcs_addr + PCS_ADDR_REG_OFFSET;
+ 	rd = pdata->pcs_addr + PCS_READ_REG_OFFSET;
+ 	cmd = pdata->pcs_addr + PCS_COMMAND_REG_OFFSET;
+ 	cmd_done = pdata->pcs_addr + PCS_COMMAND_DONE_REG_OFFSET;
+ 
+-	if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data))
++	success = xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data);
++	if (!success)
+ 		netdev_err(pdata->ndev, "PCS read failed, addr: %04x\n",
+ 			   rd_addr);
++
++	return success;
+ }
+ 
+ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
+@@ -208,7 +212,9 @@ static void xgene_pcs_reset(struct xgene_enet_pdata *pdata)
+ {
+ 	u32 data;
+ 
+-	xgene_enet_rd_pcs(pdata, PCS_CONTROL_1, &data);
++	if (!xgene_enet_rd_pcs(pdata, PCS_CONTROL_1, &data))
++		return;
++
+ 	xgene_enet_wr_pcs(pdata, PCS_CONTROL_1, data | PCS_CTRL_PCS_RST);
+ 	xgene_enet_wr_pcs(pdata, PCS_CONTROL_1, data & ~PCS_CTRL_PCS_RST);
+ }
+-- 
+1.8.3.1
+
diff --git a/SOURCES/1012-net-xgene-fix-backward-compatibility-fix.patch b/SOURCES/1012-net-xgene-fix-backward-compatibility-fix.patch
new file mode 100644
index 0000000..c2a3712
--- /dev/null
+++ b/SOURCES/1012-net-xgene-fix-backward-compatibility-fix.patch
@@ -0,0 +1,47 @@
+From 76ba1e7db4a58d90d8ec9a81df4506913535da5a Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd at arndb.de>
+Date: Mon, 29 Aug 2016 14:37:14 +0200
+Subject: [PATCH 1012/1018] net: xgene: fix backward compatibility fix
+
+A bugfix for backward compatibility handling introduced undefined
+behavior for the case that of_parse_phandle() does not return
+a valid entry, as "gcc -Wmaybe-unused" reports:
+
+drivers/net/ethernet/apm/xgene/xgene_enet_hw.c: In function 'xgene_enet_phy_connect':
+drivers/net/ethernet/apm/xgene/xgene_enet_hw.c:776:6: error: 'phy_dev' may be used uninitialized in this function [-Werror=maybe-uninitialized]
+drivers/net/ethernet/apm/xgene/xgene_enet_hw.c: In function 'xgene_enet_mdio_config':
+drivers/net/ethernet/apm/xgene/xgene_enet_hw.c:776:6: error: 'phy_dev' may be used uninitialized in this function [-Werror=maybe-uninitialized]
+
+We can work around this by removing the check for zero "np", as
+of_phy_connect() will correctly handle a NULL argument so we fall
+back into the normal error handling case.
+
+Note that I had previously fixed another bug that resulted in the
+exact same warning, but this is a different problem that was
+introduced after my original fix.
+
+Signed-off-by: Arnd Bergmann <arnd at arndb.de>
+Fixes: 03377e381bf4 ("drivers: net: xgene: Fix backward compatibility")
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+index 126f631..8352334 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+@@ -762,10 +762,6 @@ int xgene_enet_phy_connect(struct net_device *ndev)
+ 	if (dev->of_node) {
+ 		for (i = 0 ; i < 2; i++) {
+ 			np = of_parse_phandle(dev->of_node, "phy-handle", i);
+-
+-			if (!np)
+-				continue;
+-
+ 			phy_dev = of_phy_connect(ndev, np,
+ 						 &xgene_enet_adjust_link,
+ 						 0, pdata->phy_mode);
+-- 
+1.8.3.1
+
diff --git a/SOURCES/1013-net-ethernet-apm-xgene-use-phydev-from-struct-net_de.patch b/SOURCES/1013-net-ethernet-apm-xgene-use-phydev-from-struct-net_de.patch
new file mode 100644
index 0000000..b057d0f
--- /dev/null
+++ b/SOURCES/1013-net-ethernet-apm-xgene-use-phydev-from-struct-net_de.patch
@@ -0,0 +1,150 @@
+From a5088e0b96469357d3ccc4ae729f174b7dc9f671 Mon Sep 17 00:00:00 2001
+From: Philippe Reynes <tremyfr at gmail.com>
+Date: Wed, 9 Nov 2016 18:19:05 -0600
+Subject: [PATCH 1013/1018] net: ethernet: apm: xgene: use phydev from struct
+ net_device
+
+The private structure contain a pointer to phydev, but the structure
+net_device already contain such pointer. So we can remove the pointer
+phy_dev in the private structure, and update the driver to use the
+one contained in struct net_device.
+
+Signed-off-by: Philippe Reynes <tremyfr at gmail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+
+[Apply from upstream commit 4.8 to CentOS 7.3 AltArch]
+Signed-off-by: Duc Dang <dhdang at apm.com>
+---
+ .../net/ethernet/apm/xgene/xgene_enet_ethtool.c    |  4 ++--
+ drivers/net/ethernet/apm/xgene/xgene_enet_hw.c     | 24 +++++++++++-----------
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.c   |  8 ++++----
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.h   |  1 -
+ 4 files changed, 18 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
+index 22a7b26..e1f44ae 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
+@@ -57,7 +57,7 @@ static void xgene_get_drvinfo(struct net_device *ndev,
+ static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+ {
+ 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+-	struct phy_device *phydev = pdata->phy_dev;
++	struct phy_device *phydev = ndev->phydev;
+ 
+ 	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
+ 		if (phydev == NULL)
+@@ -96,7 +96,7 @@ static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+ static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+ {
+ 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+-	struct phy_device *phydev = pdata->phy_dev;
++	struct phy_device *phydev = ndev->phydev;
+ 
+ 	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
+ 		if (!phydev)
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+index 8352334..36b478f 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+@@ -713,7 +713,7 @@ static void xgene_enet_adjust_link(struct net_device *ndev)
+ {
+ 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+ 	const struct xgene_mac_ops *mac_ops = pdata->mac_ops;
+-	struct phy_device *phydev = pdata->phy_dev;
++	struct phy_device *phydev = ndev->phydev;
+ 
+ 	if (phydev->link) {
+ 		if (pdata->phy_speed != phydev->speed) {
+@@ -774,15 +774,13 @@ int xgene_enet_phy_connect(struct net_device *ndev)
+ 			netdev_err(ndev, "Could not connect to PHY\n");
+ 			return -ENODEV;
+ 		}
+-
+-		pdata->phy_dev = phy_dev;
+ 	} else {
+ #ifdef CONFIG_ACPI
+ 		adev = acpi_phy_find_device(dev);
+ 		if (adev)
+-			pdata->phy_dev =  adev->driver_data;
+-
+-		phy_dev = pdata->phy_dev;
++			phy_dev =  adev->driver_data;
++		else
++			phy_dev = NULL;
+ 
+ 		if (!phy_dev ||
+ 		    phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link,
+@@ -848,8 +846,6 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata,
+ 	if (!phy)
+ 		return -EIO;
+ 
+-	pdata->phy_dev = phy;
+-
+ 	return ret;
+ }
+ 
+@@ -889,14 +885,18 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
+ 
+ void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata)
+ {
+-	if (pdata->phy_dev)
+-		phy_disconnect(pdata->phy_dev);
++	struct net_device *ndev = pdata->ndev;
++
++	if (ndev->phydev)
++		phy_disconnect(ndev->phydev);
+ }
+ 
+ void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata)
+ {
+-	if (pdata->phy_dev)
+-		phy_disconnect(pdata->phy_dev);
++	struct net_device *ndev = pdata->ndev;
++
++	if (ndev->phydev)
++		phy_disconnect(ndev->phydev);
+ 
+ 	mdiobus_unregister(pdata->mdio_bus);
+ 	mdiobus_free(pdata->mdio_bus);
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+index b8b9495..522ba92 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+@@ -748,8 +748,8 @@ static int xgene_enet_open(struct net_device *ndev)
+ 	if (ret)
+ 		return ret;
+ 
+-	if (pdata->phy_dev) {
+-		phy_start(pdata->phy_dev);
++	if (ndev->phydev) {
++		phy_start(ndev->phydev);
+ 	} else {
+ 		schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF);
+ 		netif_carrier_off(ndev);
+@@ -772,8 +772,8 @@ static int xgene_enet_close(struct net_device *ndev)
+ 	mac_ops->tx_disable(pdata);
+ 	mac_ops->rx_disable(pdata);
+ 
+-	if (pdata->phy_dev)
+-		phy_stop(pdata->phy_dev);
++	if (ndev->phydev)
++		phy_stop(ndev->phydev);
+ 	else
+ 		cancel_delayed_work_sync(&pdata->link_work);
+ 
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+index b339fc1..7735371 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+@@ -174,7 +174,6 @@ struct xgene_cle_ops {
+ struct xgene_enet_pdata {
+ 	struct net_device *ndev;
+ 	struct mii_bus *mdio_bus;
+-	struct phy_device *phy_dev;
+ 	int phy_speed;
+ 	struct clk *clk;
+ 	struct platform_device *pdev;
+-- 
+1.8.3.1
+
diff --git a/SOURCES/1014-drivers-net-xgene-Fix-MSS-programming.patch b/SOURCES/1014-drivers-net-xgene-Fix-MSS-programming.patch
new file mode 100644
index 0000000..2954784
--- /dev/null
+++ b/SOURCES/1014-drivers-net-xgene-Fix-MSS-programming.patch
@@ -0,0 +1,297 @@
+From 96703b9e54070f674bb14001c6928d19537c33d1 Mon Sep 17 00:00:00 2001
+From: Iyappan Subramanian <isubramanian at apm.com>
+Date: Thu, 22 Sep 2016 15:47:33 -0700
+Subject: [PATCH 1014/1018] drivers: net: xgene: Fix MSS programming
+
+Current driver programs static value of MSS in hardware register for TSO
+offload engine to segment the TCP payload regardless the MSS value
+provided by network stack.
+
+This patch fixes this by programming hardware registers with the
+stack provided MSS value.
+
+Since the hardware has the limitation of having only 4 MSS registers,
+this patch uses reference count of mss values being used.
+
+Signed-off-by: Iyappan Subramanian <isubramanian at apm.com>
+Signed-off-by: Toan Le <toanle at apm.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/ethernet/apm/xgene/xgene_enet_hw.h    |  7 ++
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.c  | 90 ++++++++++++++++++-----
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.h  |  8 +-
+ drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 18 ++++-
+ 4 files changed, 100 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
+index 8a8d055..8456337 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
+@@ -237,6 +237,8 @@ enum xgene_enet_rm {
+ #define TCPHDR_LEN			6
+ #define IPHDR_POS			6
+ #define IPHDR_LEN			6
++#define MSS_POS				20
++#define MSS_LEN				2
+ #define EC_POS				22	/* Enable checksum */
+ #define EC_LEN				1
+ #define ET_POS				23	/* Enable TSO */
+@@ -253,6 +255,11 @@ enum xgene_enet_rm {
+ 
+ #define LAST_BUFFER			(0x7800ULL << BUFDATALEN_POS)
+ 
++#define TSO_MSS0_POS			0
++#define TSO_MSS0_LEN			14
++#define TSO_MSS1_POS			16
++#define TSO_MSS1_LEN			14
++
+ struct xgene_enet_raw_desc {
+ 	__le64 m0;
+ 	__le64 m1;
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+index 522ba92..429f18f 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+@@ -137,6 +137,7 @@ static irqreturn_t xgene_enet_rx_irq(const int irq, void *data)
+ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
+ 				    struct xgene_enet_raw_desc *raw_desc)
+ {
++	struct xgene_enet_pdata *pdata = netdev_priv(cp_ring->ndev);
+ 	struct sk_buff *skb;
+ 	struct device *dev;
+ 	skb_frag_t *frag;
+@@ -144,6 +145,7 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
+ 	u16 skb_index;
+ 	u8 status;
+ 	int i, ret = 0;
++	u8 mss_index;
+ 
+ 	skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
+ 	skb = cp_ring->cp_skb[skb_index];
+@@ -160,6 +162,13 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
+ 			       DMA_TO_DEVICE);
+ 	}
+ 
++	if (GET_BIT(ET, le64_to_cpu(raw_desc->m3))) {
++		mss_index = GET_VAL(MSS, le64_to_cpu(raw_desc->m3));
++		spin_lock(&pdata->mss_lock);
++		pdata->mss_refcnt[mss_index]--;
++		spin_unlock(&pdata->mss_lock);
++	}
++
+ 	/* Checking for error */
+ 	status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
+ 	if (unlikely(status > 2)) {
+@@ -178,15 +187,53 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
+ 	return ret;
+ }
+ 
+-static u64 xgene_enet_work_msg(struct sk_buff *skb)
++static int xgene_enet_setup_mss(struct net_device *ndev, u32 mss)
++{
++	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
++	bool mss_index_found = false;
++	int mss_index;
++	int i;
++
++	spin_lock(&pdata->mss_lock);
++
++	/* Reuse the slot if MSS matches */
++	for (i = 0; !mss_index_found && i < NUM_MSS_REG; i++) {
++		if (pdata->mss[i] == mss) {
++			pdata->mss_refcnt[i]++;
++			mss_index = i;
++			mss_index_found = true;
++		}
++	}
++
++	/* Overwrite the slot with ref_count = 0 */
++	for (i = 0; !mss_index_found && i < NUM_MSS_REG; i++) {
++		if (!pdata->mss_refcnt[i]) {
++			pdata->mss_refcnt[i]++;
++			pdata->mac_ops->set_mss(pdata, mss, i);
++			pdata->mss[i] = mss;
++			mss_index = i;
++			mss_index_found = true;
++		}
++	}
++
++	spin_unlock(&pdata->mss_lock);
++
++	/* No slots with ref_count = 0 available, return busy */
++	if (!mss_index_found)
++		return -EBUSY;
++
++	return mss_index;
++}
++
++static int xgene_enet_work_msg(struct sk_buff *skb, u64 *hopinfo)
+ {
+ 	struct net_device *ndev = skb->dev;
+ 	struct iphdr *iph;
+ 	u8 l3hlen = 0, l4hlen = 0;
+ 	u8 ethhdr, proto = 0, csum_enable = 0;
+-	u64 hopinfo = 0;
+ 	u32 hdr_len, mss = 0;
+ 	u32 i, len, nr_frags;
++	int mss_index;
+ 
+ 	ethhdr = xgene_enet_hdr_len(skb->data);
+ 
+@@ -226,7 +273,11 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb)
+ 			if (!mss || ((skb->len - hdr_len) <= mss))
+ 				goto out;
+ 
+-			hopinfo |= SET_BIT(ET);
++			mss_index = xgene_enet_setup_mss(ndev, mss);
++			if (unlikely(mss_index < 0))
++				return -EBUSY;
++
++			*hopinfo |= SET_BIT(ET) | SET_VAL(MSS, mss_index);
+ 		}
+ 	} else if (iph->protocol == IPPROTO_UDP) {
+ 		l4hlen = UDP_HDR_SIZE;
+@@ -234,15 +285,15 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb)
+ 	}
+ out:
+ 	l3hlen = ip_hdrlen(skb) >> 2;
+-	hopinfo |= SET_VAL(TCPHDR, l4hlen) |
+-		  SET_VAL(IPHDR, l3hlen) |
+-		  SET_VAL(ETHHDR, ethhdr) |
+-		  SET_VAL(EC, csum_enable) |
+-		  SET_VAL(IS, proto) |
+-		  SET_BIT(IC) |
+-		  SET_BIT(TYPE_ETH_WORK_MESSAGE);
+-
+-	return hopinfo;
++	*hopinfo |= SET_VAL(TCPHDR, l4hlen) |
++		    SET_VAL(IPHDR, l3hlen) |
++		    SET_VAL(ETHHDR, ethhdr) |
++		    SET_VAL(EC, csum_enable) |
++		    SET_VAL(IS, proto) |
++		    SET_BIT(IC) |
++		    SET_BIT(TYPE_ETH_WORK_MESSAGE);
++
++	return 0;
+ }
+ 
+ static u16 xgene_enet_encode_len(u16 len)
+@@ -282,20 +333,22 @@ static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring,
+ 	dma_addr_t dma_addr, pbuf_addr, *frag_dma_addr;
+ 	skb_frag_t *frag;
+ 	u16 tail = tx_ring->tail;
+-	u64 hopinfo;
++	u64 hopinfo = 0;
+ 	u32 len, hw_len;
+ 	u8 ll = 0, nv = 0, idx = 0;
+ 	bool split = false;
+ 	u32 size, offset, ell_bytes = 0;
+ 	u32 i, fidx, nr_frags, count = 1;
++	int ret;
+ 
+ 	raw_desc = &tx_ring->raw_desc[tail];
+ 	tail = (tail + 1) & (tx_ring->slots - 1);
+ 	memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc));
+ 
+-	hopinfo = xgene_enet_work_msg(skb);
+-	if (!hopinfo)
+-		return -EINVAL;
++	ret = xgene_enet_work_msg(skb, &hopinfo);
++	if (ret)
++		return ret;
++
+ 	raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) |
+ 				   hopinfo);
+ 
+@@ -435,6 +488,9 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
+ 		return NETDEV_TX_OK;
+ 
+ 	count = xgene_enet_setup_tx_desc(tx_ring, skb);
++	if (count == -EBUSY)
++		return NETDEV_TX_BUSY;
++
+ 	if (count <= 0) {
+ 		dev_kfree_skb_any(skb);
+ 		return NETDEV_TX_OK;
+@@ -1669,7 +1725,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
+ 
+ 	if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+ 		ndev->features |= NETIF_F_TSO;
+-		pdata->mss = XGENE_ENET_MSS;
++		spin_lock_init(&pdata->mss_lock);
+ 	}
+ 	ndev->hw_features = ndev->features;
+ 
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+index 7735371..0cda58f 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+@@ -47,7 +47,7 @@
+ #define NUM_PKT_BUF	64
+ #define NUM_BUFPOOL	32
+ #define MAX_EXP_BUFFS	256
+-#define XGENE_ENET_MSS	1448
++#define NUM_MSS_REG	4
+ #define XGENE_MIN_ENET_FRAME_SIZE	60
+ 
+ #define XGENE_MAX_ENET_IRQ	16
+@@ -143,7 +143,7 @@ struct xgene_mac_ops {
+ 	void (*rx_disable)(struct xgene_enet_pdata *pdata);
+ 	void (*set_speed)(struct xgene_enet_pdata *pdata);
+ 	void (*set_mac_addr)(struct xgene_enet_pdata *pdata);
+-	void (*set_mss)(struct xgene_enet_pdata *pdata);
++	void (*set_mss)(struct xgene_enet_pdata *pdata, u16 mss, u8 index);
+ 	void (*link_state)(struct work_struct *work);
+ };
+ 
+@@ -212,7 +212,9 @@ struct xgene_enet_pdata {
+ 	u8 eth_bufnum;
+ 	u8 bp_bufnum;
+ 	u16 ring_num;
+-	u32 mss;
++	u32 mss[NUM_MSS_REG];
++	u32 mss_refcnt[NUM_MSS_REG];
++	spinlock_t mss_lock;  /* mss lock */
+ 	u8 tx_delay;
+ 	u8 rx_delay;
+ 	bool mdio_driver;
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
+index 279ee27..6475f38 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
+@@ -232,9 +232,22 @@ static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata)
+ 	xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1);
+ }
+ 
+-static void xgene_xgmac_set_mss(struct xgene_enet_pdata *pdata)
++static void xgene_xgmac_set_mss(struct xgene_enet_pdata *pdata,
++				u16 mss, u8 index)
+ {
+-	xgene_enet_wr_csr(pdata, XG_TSIF_MSS_REG0_ADDR, pdata->mss);
++	u8 offset;
++	u32 data;
++
++	offset = (index < 2) ? 0 : 4;
++	xgene_enet_rd_csr(pdata, XG_TSIF_MSS_REG0_ADDR + offset, &data);
++
++	if (!(index & 0x1))
++		data = SET_VAL(TSO_MSS1, data >> TSO_MSS1_POS) |
++			SET_VAL(TSO_MSS0, mss);
++	else
++		data = SET_VAL(TSO_MSS1, mss) | SET_VAL(TSO_MSS0, data);
++
++	xgene_enet_wr_csr(pdata, XG_TSIF_MSS_REG0_ADDR + offset, data);
+ }
+ 
+ static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata)
+@@ -258,7 +271,6 @@ static void xgene_xgmac_init(struct xgene_enet_pdata *pdata)
+ 	xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);
+ 
+ 	xgene_xgmac_set_mac_addr(pdata);
+-	xgene_xgmac_set_mss(pdata);
+ 
+ 	xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data);
+ 	data |= CFG_RSIF_FPBUFF_TIMEOUT_EN;
+-- 
+1.8.3.1
+
diff --git a/SOURCES/1015-drivers-net-xgene-fix-Use-GPIO-to-get-link-status.patch b/SOURCES/1015-drivers-net-xgene-fix-Use-GPIO-to-get-link-status.patch
new file mode 100644
index 0000000..5588ac5
--- /dev/null
+++ b/SOURCES/1015-drivers-net-xgene-fix-Use-GPIO-to-get-link-status.patch
@@ -0,0 +1,91 @@
+From 410b195f44efaaa3a42f6ff0fc5ffaa02ce934d5 Mon Sep 17 00:00:00 2001
+From: Iyappan Subramanian <isubramanian at apm.com>
+Date: Thu, 6 Oct 2016 14:35:57 -0700
+Subject: [PATCH 1015/1018] drivers: net: xgene: fix: Use GPIO to get link
+ status
+
+The link value reported by the link status register is not
+reliable when no SPF module inserted. This patchset fixes this
+issue by using GPIO to determine the link status.
+
+Signed-off-by: Iyappan Subramanian <isubramanian at apm.com>
+Signed-off-by: Quan Nguyen <qnguyen at apm.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.c  |  6 +++++-
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.h  |  1 +
+ drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 19 +++++++++++++++++--
+ 3 files changed, 23 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+index 429f18f..f75d955 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+@@ -1381,9 +1381,13 @@ static void xgene_enet_gpiod_get(struct xgene_enet_pdata *pdata)
+ {
+ 	struct device *dev = &pdata->pdev->dev;
+ 
+-	if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII)
++	pdata->sfp_gpio_en = false;
++	if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII ||
++	    (!device_property_present(dev, "sfp-gpios") &&
++	     !device_property_present(dev, "rxlos-gpios")))
+ 		return;
+ 
++	pdata->sfp_gpio_en = true;
+ 	pdata->sfp_rdy = gpiod_get(dev, "rxlos", GPIOD_IN);
+ 	if (IS_ERR(pdata->sfp_rdy))
+ 		pdata->sfp_rdy = gpiod_get(dev, "sfp", GPIOD_IN);
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+index 0cda58f..011965b 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+@@ -219,6 +219,7 @@ struct xgene_enet_pdata {
+ 	u8 rx_delay;
+ 	bool mdio_driver;
+ 	struct gpio_desc *sfp_rdy;
++	bool sfp_gpio_en;
+ };
+ 
+ struct xgene_indirect_ctl {
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
+index 6475f38..d1758b0 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
+@@ -415,16 +415,31 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
+ 	xgene_enet_wr_ring_if(pdata, addr, data);
+ }
+ 
++static int xgene_enet_gpio_lookup(struct xgene_enet_pdata *pdata)
++{
++	struct device *dev = &pdata->pdev->dev;
++
++	pdata->sfp_rdy = gpiod_get(dev, "rxlos", GPIOD_IN);
++	if (IS_ERR(pdata->sfp_rdy))
++		pdata->sfp_rdy = gpiod_get(dev, "sfp", GPIOD_IN);
++
++	if (IS_ERR(pdata->sfp_rdy))
++		return -ENODEV;
++
++	return 0;
++}
++
+ static void xgene_enet_link_state(struct work_struct *work)
+ {
+ 	struct xgene_enet_pdata *pdata = container_of(to_delayed_work(work),
+ 					 struct xgene_enet_pdata, link_work);
+-	struct gpio_desc *sfp_rdy = pdata->sfp_rdy;
+ 	struct net_device *ndev = pdata->ndev;
+ 	u32 link_status, poll_interval;
+ 
+ 	link_status = xgene_enet_link_status(pdata);
+-	if (link_status && !IS_ERR(sfp_rdy) && !gpiod_get_value(sfp_rdy))
++	if (pdata->sfp_gpio_en && link_status &&
++	    (!IS_ERR(pdata->sfp_rdy) || !xgene_enet_gpio_lookup(pdata)) &&
++	    !gpiod_get_value(pdata->sfp_rdy))
+ 		link_status = 0;
+ 
+ 	if (link_status) {
+-- 
+1.8.3.1
+
diff --git a/SOURCES/1016-drivers-net-xgene-fix-Disable-coalescing-on-v1-hardw.patch b/SOURCES/1016-drivers-net-xgene-fix-Disable-coalescing-on-v1-hardw.patch
new file mode 100644
index 0000000..5da6d49
--- /dev/null
+++ b/SOURCES/1016-drivers-net-xgene-fix-Disable-coalescing-on-v1-hardw.patch
@@ -0,0 +1,61 @@
+From b125c9d6439cce38fa6938c7b31ab2ed0e17dee6 Mon Sep 17 00:00:00 2001
+From: Iyappan Subramanian <isubramanian at apm.com>
+Date: Mon, 31 Oct 2016 16:00:26 -0700
+Subject: [PATCH 1016/1018] drivers: net: xgene: fix: Disable coalescing on v1
+ hardware
+
+Since ethernet v1 hardware has a bug related to coalescing, disabling
+this feature.
+
+Signed-off-by: Iyappan Subramanian <isubramanian at apm.com>
+Signed-off-by: Toan Le <toanle at apm.com>
+---
+ drivers/net/ethernet/apm/xgene/xgene_enet_hw.c   | 12 ------------
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.c |  3 ++-
+ 2 files changed, 2 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+index 36b478f..85ed9a1 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+@@ -204,17 +204,6 @@ static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
+ 	return num_msgs;
+ }
+ 
+-static void xgene_enet_setup_coalescing(struct xgene_enet_desc_ring *ring)
+-{
+-	u32 data = 0x7777;
+-
+-	xgene_enet_ring_wr32(ring, CSR_PBM_COAL, 0x8e);
+-	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK1, data);
+-	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data << 16);
+-	xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x40);
+-	xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x80);
+-}
+-
+ void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
+ 			    struct xgene_enet_pdata *pdata,
+ 			    enum xgene_enet_err_code status)
+@@ -928,5 +917,4 @@ struct xgene_ring_ops xgene_ring1_ops = {
+ 	.clear = xgene_enet_clear_ring,
+ 	.wr_cmd = xgene_enet_wr_cmd,
+ 	.len = xgene_enet_ring_len,
+-	.coalesce = xgene_enet_setup_coalescing,
+ };
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+index f75d955..fe34403 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+@@ -1188,7 +1188,8 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
+ 		tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
+ 	}
+ 
+-	pdata->ring_ops->coalesce(pdata->tx_ring[0]);
++	if (pdata->ring_ops->coalesce)
++		pdata->ring_ops->coalesce(pdata->tx_ring[0]);
+ 	pdata->tx_qcnt_hi = pdata->tx_ring[0]->slots - 128;
+ 
+ 	return 0;
+-- 
+1.8.3.1
+
diff --git a/SOURCES/1017-drivers-net-xgene-fix-Coalescing-values-for-v2-hardw.patch b/SOURCES/1017-drivers-net-xgene-fix-Coalescing-values-for-v2-hardw.patch
new file mode 100644
index 0000000..79203da
--- /dev/null
+++ b/SOURCES/1017-drivers-net-xgene-fix-Coalescing-values-for-v2-hardw.patch
@@ -0,0 +1,67 @@
+From da20928c43a4f6b9390a0fb027dda7d947011686 Mon Sep 17 00:00:00 2001
+From: Iyappan Subramanian <isubramanian at apm.com>
+Date: Mon, 31 Oct 2016 16:00:27 -0700
+Subject: [PATCH 1017/1018] drivers: net: xgene: fix: Coalescing values for v2
+ hardware
+
+Changing the interrupt trigger region id to 2 and the
+corresponding threshold set0/set1 values to 8/16.
+
+Signed-off-by: Iyappan Subramanian <isubramanian at apm.com>
+Signed-off-by: Toan Le <toanle at apm.com>
+---
+ drivers/net/ethernet/apm/xgene/xgene_enet_hw.h    |  2 ++
+ drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c | 12 +++++++-----
+ 2 files changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
+index 8456337..06e598c 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
+@@ -55,8 +55,10 @@ enum xgene_enet_rm {
+ #define PREFETCH_BUF_EN		BIT(21)
+ #define CSR_RING_ID_BUF		0x000c
+ #define CSR_PBM_COAL		0x0014
++#define CSR_PBM_CTICK0		0x0018
+ #define CSR_PBM_CTICK1		0x001c
+ #define CSR_PBM_CTICK2		0x0020
++#define CSR_PBM_CTICK3		0x0024
+ #define CSR_THRESHOLD0_SET1	0x0030
+ #define CSR_THRESHOLD1_SET1	0x0034
+ #define CSR_RING_NE_INT_MODE	0x017c
+diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c
+index 2b76732..af51dd5 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c
+@@ -30,7 +30,7 @@ static void xgene_enet_ring_init(struct xgene_enet_desc_ring *ring)
+ 		ring_cfg[0] |= SET_VAL(X2_INTLINE, ring->id & RING_BUFNUM_MASK);
+ 		ring_cfg[3] |= SET_BIT(X2_DEQINTEN);
+ 	}
+-	ring_cfg[0] |= SET_VAL(X2_CFGCRID, 1);
++	ring_cfg[0] |= SET_VAL(X2_CFGCRID, 2);
+ 
+ 	addr >>= 8;
+ 	ring_cfg[2] |= QCOHERENT | SET_VAL(RINGADDRL, addr);
+@@ -192,13 +192,15 @@ static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
+ 
+ static void xgene_enet_setup_coalescing(struct xgene_enet_desc_ring *ring)
+ {
+-	u32 data = 0x7777;
++	u32 data = 0x77777777;
+ 
+ 	xgene_enet_ring_wr32(ring, CSR_PBM_COAL, 0x8e);
++	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK0, data);
+ 	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK1, data);
+-	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data << 16);
+-	xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x40);
+-	xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x80);
++	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data);
++	xgene_enet_ring_wr32(ring, CSR_PBM_CTICK3, data);
++	xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x08);
++	xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x10);
+ }
+ 
+ struct xgene_ring_ops xgene_ring2_ops = {
+-- 
+1.8.3.1
+
diff --git a/SPECS/kernel-aarch64.spec b/SPECS/kernel-aarch64.spec
index 84374b8..c44bdc7 100644
--- a/SPECS/kernel-aarch64.spec
+++ b/SPECS/kernel-aarch64.spec
@@ -335,6 +335,13 @@ Patch1007: 1007-perf-xgene-Add-APM-X-Gene-SoC-Performance-Monitoring.patch
 Patch1008: 1008-perf-xgene-Remove-bogus-IS_ERR-check.patch
 Patch1009: 1009-MAINTAINERS-Add-entry-for-APM-X-Gene-SoC-PMU-driver.patch
 Patch1010: 1010-i2c-xgene-Avoid-dma_buffer-overrun.patch
+Patch1011: 1011-net-xgene-fix-error-handling-during-reset.patch
+Patch1012: 1012-net-xgene-fix-backward-compatibility-fix.patch
+Patch1013: 1013-net-ethernet-apm-xgene-use-phydev-from-struct-net_de.patch
+Patch1014: 1014-drivers-net-xgene-Fix-MSS-programming.patch
+Patch1015: 1015-drivers-net-xgene-fix-Use-GPIO-to-get-link-status.patch
+Patch1016: 1016-drivers-net-xgene-fix-Disable-coalescing-on-v1-hardw.patch
+Patch1017: 1017-drivers-net-xgene-fix-Coalescing-values-for-v2-hardw.patch
 
 # QDF2400 Patches
 Patch4000: 4000-arm64-Define-Qualcomm-Technologies-ARMv8-CPU.patch
@@ -680,6 +687,13 @@ git am %{PATCH1007}
 git am %{PATCH1008}
 git am %{PATCH1009}
 git am %{PATCH1010}
+git am %{PATCH1011}
+git am %{PATCH1012}
+git am %{PATCH1013}
+git am %{PATCH1014}
+git am %{PATCH1015}
+git am %{PATCH1016}
+git am %{PATCH1017}
 
 # Apply QDF2400 patches
 git am %{PATCH4000}
@@ -1459,6 +1473,7 @@ fi
 
 %changelog
 * Thu Nov 10 2016 Duc Dang <dhdang at apm.com> [4.5.0-17.el7]
+- Integrate upstream updates for X-Gene Enet driver
 - Avoid dma_buffer overrun for SlimPRO I2C driver 
 - Add X-Gene SoC PMU support
 - Add X-Gene HWMon support
-- 
1.8.3.1