orgads / rpms / kernel

Forked from rpms/kernel 3 years ago
Clone
f2c60e
From 33d983b5bb2929ae242606925e708092b1dfdd8f Mon Sep 17 00:00:00 2001
f2c60e
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
Date: Sat, 2 Sep 2017 11:01:22 +0100
f2c60e
Subject: drivers/irqchip: gicv3: add workaround for Synquacer pre-ITS
f2c60e
f2c60e
In their infinite wisdom, the Socionext engineers have decided
f2c60e
that ITS device IDs should not be hardwired, but it should be
f2c60e
left up to the software to assign them, by allowing it to
f2c60e
redirect MSI doorbell writes via a separate hardware block
f2c60e
that issues the doorbell write with a device ID that is
f2c60e
derived from the memory address. This completely breaks any
f2c60e
kind of isolation, or virtualization in general, for that
f2c60e
matter, but add support for it nonetheless.
f2c60e
f2c60e
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
---
f2c60e
 arch/arm64/Kconfig               |  8 +++++++
f2c60e
 drivers/irqchip/irq-gic-v3-its.c | 48 +++++++++++++++++++++++++++++++++++-----
f2c60e
 2 files changed, 51 insertions(+), 5 deletions(-)
f2c60e
f2c60e
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
f2c60e
index 0df64a6..c4361df 100644
f2c60e
--- a/arch/arm64/Kconfig
f2c60e
+++ b/arch/arm64/Kconfig
f2c60e
@@ -539,6 +539,14 @@ config QCOM_QDF2400_ERRATUM_0065
f2c60e
 
f2c60e
 	  If unsure, say Y.
f2c60e
 
f2c60e
+config SOCIONEXT_SYNQUACER_PREITS
f2c60e
+	bool "Socionext Synquacer: Workaround for GICv3 pre-ITS"
f2c60e
+	default y
f2c60e
+	help
f2c60e
+	  Socionext Synquacer SoCs implement a separate h/w block to generate
f2c60e
+	  MSI doorbell writes with non-zero values for the device ID.
f2c60e
+
f2c60e
+	  If unsure, say Y.
f2c60e
 endmenu
f2c60e
 
f2c60e
 
f2c60e
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
f2c60e
index e8d8934..0d372f1 100644
f2c60e
--- a/drivers/irqchip/irq-gic-v3-its.c
f2c60e
+++ b/drivers/irqchip/irq-gic-v3-its.c
f2c60e
@@ -46,6 +46,7 @@
f2c60e
 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING		(1ULL << 0)
f2c60e
 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375	(1ULL << 1)
f2c60e
 #define ITS_FLAGS_WORKAROUND_CAVIUM_23144	(1ULL << 2)
f2c60e
+#define ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS	(1ULL << 3)
f2c60e
 
f2c60e
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING	(1 << 0)
f2c60e
 
f2c60e
@@ -99,6 +100,10 @@ struct its_node {
f2c60e
 	struct its_collection	*collections;
f2c60e
 	struct list_head	its_device_list;
f2c60e
 	u64			flags;
f2c60e
+#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS
f2c60e
+	u64			pre_its_base;
f2c60e
+	u64			pre_its_size;
f2c60e
+#endif
f2c60e
 	u32			ite_size;
f2c60e
 	u32			device_ids;
f2c60e
 	int			numa_node;
f2c60e
@@ -1102,13 +1107,29 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
f2c60e
 	u64 addr;
f2c60e
 
f2c60e
 	its = its_dev->its;
f2c60e
-	addr = its->phys_base + GITS_TRANSLATER;
f2c60e
+
f2c60e
+#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS
f2c60e
+	if (its->flags & ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS)
f2c60e
+
f2c60e
+		/*
f2c60e
+		 * The Socionext Synquacer SoC has a so-called 'pre-ITS',
f2c60e
+		 * which maps 32-bit writes into a separate window of size
f2c60e
+		 * '4 << device_id_bits' onto writes to GITS_TRANSLATER with
f2c60e
+		 * device ID taken from bits [device_id_bits + 1:2] of the
f2c60e
+		 * window offset.
f2c60e
+		 */
f2c60e
+		addr = its->pre_its_base + (its_dev->device_id << 2);
f2c60e
+	else
f2c60e
+#endif
f2c60e
+		addr = its->phys_base + GITS_TRANSLATER;
f2c60e
 
f2c60e
 	msg->address_lo		= lower_32_bits(addr);
f2c60e
 	msg->address_hi		= upper_32_bits(addr);
f2c60e
 	msg->data		= its_get_event_id(d);
f2c60e
 
f2c60e
-	iommu_dma_map_msi_msg(d->irq, msg);
f2c60e
+	if (!IS_ENABLED(CONFIG_SOCIONEXT_SYNQUACER_PREITS) ||
f2c60e
+	    !(its->flags & ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS))
f2c60e
+		iommu_dma_map_msi_msg(d->irq, msg);
f2c60e
 }
f2c60e
 
f2c60e
 static int its_irq_set_irqchip_state(struct irq_data *d,
f2c60e
@@ -1666,6 +1687,11 @@ static int its_alloc_tables(struct its_node *its)
f2c60e
 		ids     = 0x14;                 /* 20 bits, 8MB */
f2c60e
 	}
f2c60e
 
f2c60e
+#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS
f2c60e
+	if (its->flags & ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS)
f2c60e
+		ids = ilog2(its->pre_its_size) - 2;
f2c60e
+#endif
f2c60e
+
f2c60e
 	its->device_ids = ids;
f2c60e
 
f2c60e
 	for (i = 0; i < GITS_BASER_NR_REGS; i++) {
f2c60e
@@ -2788,11 +2814,21 @@ static const struct gic_quirk its_quirks[] = {
f2c60e
 	}
f2c60e
 };
f2c60e
 
f2c60e
-static void its_enable_quirks(struct its_node *its)
f2c60e
+static void its_enable_quirks(struct its_node *its,
f2c60e
+			      struct fwnode_handle *handle)
f2c60e
 {
f2c60e
 	u32 iidr = readl_relaxed(its->base + GITS_IIDR);
f2c60e
 
f2c60e
 	gic_enable_quirks(iidr, its_quirks, its);
f2c60e
+
f2c60e
+#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS
f2c60e
+	if (!fwnode_property_read_u64_array(handle,
f2c60e
+					"socionext,synquacer-pre-its",
f2c60e
+					&its->pre_its_base, 2)) {
f2c60e
+		its->flags |= ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS;
f2c60e
+		pr_info("ITS: enabling workaround for Socionext Synquacer pre-ITS\n");
f2c60e
+	}
f2c60e
+#endif
f2c60e
 }
f2c60e
 
f2c60e
 static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
f2c60e
@@ -2812,7 +2848,9 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
f2c60e
 
f2c60e
 	inner_domain->parent = its_parent;
f2c60e
 	irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_NEXUS);
f2c60e
-	inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP;
f2c60e
+
f2c60e
+	if (!(its->flags & ITS_FLAGS_WORKAROUND_SOCIONEXT_PREITS))
f2c60e
+		inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP;
f2c60e
 	info->ops = &its_msi_domain_ops;
f2c60e
 	info->data = its;
f2c60e
 	inner_domain->host_data = info;
f2c60e
@@ -2966,7 +3004,7 @@ static int __init its_probe_one(struct resource *res,
f2c60e
 	}
f2c60e
 	its->cmd_write = its->cmd_base;
f2c60e
 
f2c60e
-	its_enable_quirks(its);
f2c60e
+	its_enable_quirks(its, handle);
f2c60e
 
f2c60e
 	err = its_alloc_tables(its);
f2c60e
 	if (err)
f2c60e
-- 
f2c60e
cgit v1.1
f2c60e
f2c60e
From 26e7bb47b0fb03a01be1e391a08c7375b45335a2 Mon Sep 17 00:00:00 2001
f2c60e
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
Date: Mon, 21 Aug 2017 20:29:05 +0100
f2c60e
Subject: pci: designware: add driver for DWC controller in ECAM shift mode
f2c60e
f2c60e
Some implementations of the Synopsys Designware PCIe controller implement
f2c60e
a so-called ECAM shift mode, which allows a static memory window to be
f2c60e
configured that covers the configuration space of the entire bus range.
f2c60e
f2c60e
If the firmware performs all the low level configuration that is required
f2c60e
to expose this controller in a fully ECAM compatible manner, we can
f2c60e
simply describe it as "pci-host-ecam-generic" and be done with it.
f2c60e
However, it appears that in some cases (one of which is the Armada 80x0),
f2c60e
the IP is synthesized with an ATU window size that does not allow the
f2c60e
first bus to be mapped in a way that prevents the device on the
f2c60e
downstream port from appearing more than once.
f2c60e
f2c60e
So implement a driver that relies on the firmware to perform all low
f2c60e
level initialization, and drives the controller in ECAM mode, but
f2c60e
overrides the config space accessors to take the above quirk into
f2c60e
account.
f2c60e
f2c60e
Note that, unlike most drivers for this IP, this driver does not expose
f2c60e
a fake bridge device at B/D/F 00:00.0. There is no point in doing so,
f2c60e
given that this is not a true bridge, and does not require any windows
f2c60e
to be configured in order for the downstream device to operate correctly.
f2c60e
Omitting it also prevents the PCI resource allocation routines from
f2c60e
handing out BAR space to it unnecessarily.
f2c60e
f2c60e
Cc: Bjorn Helgaas <bhelgaas@google.com>
f2c60e
Cc: Jingoo Han <jingoohan1@gmail.com>
f2c60e
Cc: Joao Pinto <Joao.Pinto@synopsys.com>
f2c60e
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
---
f2c60e
 drivers/pci/dwc/Kconfig                | 11 +++++
f2c60e
 drivers/pci/dwc/Makefile               |  1 +
f2c60e
 drivers/pci/dwc/pcie-designware-ecam.c | 77 ++++++++++++++++++++++++++++++++++
f2c60e
 3 files changed, 89 insertions(+)
f2c60e
 create mode 100644 drivers/pci/dwc/pcie-designware-ecam.c
f2c60e
f2c60e
diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/dwc/Kconfig
f2c60e
index 22ec82f..19856b1 100644
f2c60e
--- a/drivers/pci/dwc/Kconfig
f2c60e
+++ b/drivers/pci/dwc/Kconfig
f2c60e
@@ -169,4 +169,15 @@ config PCIE_KIRIN
f2c60e
 	  Say Y here if you want PCIe controller support
f2c60e
 	  on HiSilicon Kirin series SoCs.
f2c60e
 
f2c60e
+config PCIE_DW_HOST_ECAM
f2c60e
+	bool "Synopsys DesignWare PCIe controller in ECAM mode"
f2c60e
+	depends on OF && PCI
f2c60e
+	select PCI_HOST_COMMON
f2c60e
+	select IRQ_DOMAIN
f2c60e
+	help
f2c60e
+	  Add support for Synopsys DesignWare PCIe controllers configured
f2c60e
+	  by the firmware into ECAM shift mode. In some cases, these are
f2c60e
+	  fully ECAM compliant, in which case the pci-host-generic driver
f2c60e
+	  may be used instead.
f2c60e
+
f2c60e
 endmenu
f2c60e
diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile
f2c60e
index c61be97..7d5a23e 100644
f2c60e
--- a/drivers/pci/dwc/Makefile
f2c60e
+++ b/drivers/pci/dwc/Makefile
f2c60e
@@ -1,5 +1,6 @@
f2c60e
 # SPDX-License-Identifier: GPL-2.0
f2c60e
 obj-$(CONFIG_PCIE_DW) += pcie-designware.o
f2c60e
 obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o
f2c60e
+obj-$(CONFIG_PCIE_DW_HOST_ECAM) += pcie-designware-ecam.o
f2c60e
 obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o
f2c60e
 obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
f2c60e
 ifneq ($(filter y,$(CONFIG_PCI_DRA7XX_HOST) $(CONFIG_PCI_DRA7XX_EP)),)
f2c60e
diff --git a/drivers/pci/dwc/pcie-designware-ecam.c b/drivers/pci/dwc/pcie-designware-ecam.c
f2c60e
new file mode 100644
f2c60e
index 0000000..ede627d
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/pci/dwc/pcie-designware-ecam.c
f2c60e
@@ -0,0 +1,77 @@
f2c60e
+/*
f2c60e
+ * Driver for mostly ECAM compatible Synopsys dw PCIe controllers
f2c60e
+ * configured by the firmware into RC mode
f2c60e
+ *
f2c60e
+ * This program is free software; you can redistribute it and/or modify
f2c60e
+ * it under the terms of the GNU General Public License version 2 as
f2c60e
+ * published by the Free Software Foundation.
f2c60e
+ *
f2c60e
+ * Copyright (C) 2014 ARM Limited
f2c60e
+ * Copyright (C) 2017 Linaro Limited
f2c60e
+ *
f2c60e
+ * Authors: Will Deacon <will.deacon@arm.com>
f2c60e
+ *          Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
+ */
f2c60e
+
f2c60e
+#include <linux/kernel.h>
f2c60e
+#include <linux/init.h>
f2c60e
+#include <linux/of_address.h>
f2c60e
+#include <linux/of_pci.h>
f2c60e
+#include <linux/pci-ecam.h>
f2c60e
+#include <linux/platform_device.h>
f2c60e
+
f2c60e
+static int pci_dw_ecam_config_read(struct pci_bus *bus, u32 devfn, int where,
f2c60e
+				   int size, u32 *val)
f2c60e
+{
f2c60e
+	struct pci_config_window *cfg = bus->sysdata;
f2c60e
+
f2c60e
+	/*
f2c60e
+	 * The Synopsys dw PCIe controller in RC mode will not filter type 0
f2c60e
+	 * config TLPs sent to devices 1 and up on its downstream port,
f2c60e
+	 * resulting in devices appearing multiple times on bus 0 unless we
f2c60e
+	 * filter them here.
f2c60e
+	 */
f2c60e
+	if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) {
f2c60e
+		*val = 0xffffffff;
f2c60e
+		return PCIBIOS_DEVICE_NOT_FOUND;
f2c60e
+	}
f2c60e
+	return pci_generic_config_read(bus, devfn, where, size, val);
f2c60e
+}
f2c60e
+
f2c60e
+static int pci_dw_ecam_config_write(struct pci_bus *bus, u32 devfn, int where,
f2c60e
+				    int size, u32 val)
f2c60e
+{
f2c60e
+	struct pci_config_window *cfg = bus->sysdata;
f2c60e
+
f2c60e
+	if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0)
f2c60e
+		return PCIBIOS_DEVICE_NOT_FOUND;
f2c60e
+
f2c60e
+	return pci_generic_config_write(bus, devfn, where, size, val);
f2c60e
+}
f2c60e
+
f2c60e
+static struct pci_ecam_ops pci_dw_ecam_bus_ops = {
f2c60e
+	.pci_ops.map_bus		= pci_ecam_map_bus,
f2c60e
+	.pci_ops.read			= pci_dw_ecam_config_read,
f2c60e
+	.pci_ops.write			= pci_dw_ecam_config_write,
f2c60e
+	.bus_shift			= 20,
f2c60e
+};
f2c60e
+
f2c60e
+static const struct of_device_id pci_dw_ecam_of_match[] = {
f2c60e
+	{ .compatible = "marvell,armada8k-pcie-ecam" },
f2c60e
+	{ .compatible = "socionext,synquacer-pcie-ecam" },
f2c60e
+	{ .compatible = "snps,dw-pcie-ecam" },
f2c60e
+	{ },
f2c60e
+};
f2c60e
+
f2c60e
+static int pci_dw_ecam_probe(struct platform_device *pdev)
f2c60e
+{
f2c60e
+	return pci_host_common_probe(pdev, &pci_dw_ecam_bus_ops);
f2c60e
+}
f2c60e
+
f2c60e
+static struct platform_driver pci_dw_ecam_driver = {
f2c60e
+	.driver.name			= "pcie-designware-ecam",
f2c60e
+	.driver.of_match_table		= pci_dw_ecam_of_match,
f2c60e
+	.driver.suppress_bind_attrs	= true,
f2c60e
+	.probe				= pci_dw_ecam_probe,
f2c60e
+};
f2c60e
+builtin_platform_driver(pci_dw_ecam_driver);
f2c60e
-- 
f2c60e
cgit v1.1
f2c60e
f2c60e
From e3dff048a10f16aa0fd32438442ce39558bbdbef Mon Sep 17 00:00:00 2001
f2c60e
From: Jassi Brar <jaswinder.singh@linaro.org>
f2c60e
Date: Tue, 29 Aug 2017 22:45:59 +0530
f2c60e
Subject: net: socionext: Add Synquacer NetSec driver
f2c60e
f2c60e
This driver adds support for Socionext "netsec" IP Gigabit
f2c60e
Ethernet + PHY IP used in the Synquacer SC2A11 SoC.
f2c60e
f2c60e
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
f2c60e
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
---
f2c60e
 drivers/net/ethernet/Kconfig                       |   1 +
f2c60e
 drivers/net/ethernet/Makefile                      |   1 +
f2c60e
 drivers/net/ethernet/socionext/Kconfig             |  29 +
f2c60e
 drivers/net/ethernet/socionext/Makefile            |   1 +
f2c60e
 drivers/net/ethernet/socionext/netsec/Makefile     |   6 +
f2c60e
 drivers/net/ethernet/socionext/netsec/netsec.h     | 408 ++++++++++++++
f2c60e
 .../socionext/netsec/netsec_desc_ring_access.c     | 623 +++++++++++++++++++++
f2c60e
 .../net/ethernet/socionext/netsec/netsec_ethtool.c |  78 +++
f2c60e
 .../ethernet/socionext/netsec/netsec_gmac_access.c | 330 +++++++++++
f2c60e
 .../net/ethernet/socionext/netsec/netsec_netdev.c  | 540 ++++++++++++++++++
f2c60e
 .../ethernet/socionext/netsec/netsec_platform.c    | 435 ++++++++++++++
f2c60e
 11 files changed, 2452 insertions(+)
f2c60e
 create mode 100644 drivers/net/ethernet/socionext/Kconfig
f2c60e
 create mode 100644 drivers/net/ethernet/socionext/Makefile
f2c60e
 create mode 100644 drivers/net/ethernet/socionext/netsec/Makefile
f2c60e
 create mode 100644 drivers/net/ethernet/socionext/netsec/netsec.h
f2c60e
 create mode 100644 drivers/net/ethernet/socionext/netsec/netsec_desc_ring_access.c
f2c60e
 create mode 100644 drivers/net/ethernet/socionext/netsec/netsec_ethtool.c
f2c60e
 create mode 100644 drivers/net/ethernet/socionext/netsec/netsec_gmac_access.c
f2c60e
 create mode 100644 drivers/net/ethernet/socionext/netsec/netsec_netdev.c
f2c60e
 create mode 100644 drivers/net/ethernet/socionext/netsec/netsec_platform.c
f2c60e
f2c60e
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
f2c60e
index c604213..d50519e 100644
f2c60e
--- a/drivers/net/ethernet/Kconfig
f2c60e
+++ b/drivers/net/ethernet/Kconfig
f2c60e
@@ -170,6 +170,7 @@ source "drivers/net/ethernet/sis/Kconfig"
f2c60e
 source "drivers/net/ethernet/sfc/Kconfig"
f2c60e
 source "drivers/net/ethernet/sgi/Kconfig"
f2c60e
 source "drivers/net/ethernet/smsc/Kconfig"
f2c60e
+source "drivers/net/ethernet/socionext/Kconfig"
f2c60e
 source "drivers/net/ethernet/stmicro/Kconfig"
f2c60e
 source "drivers/net/ethernet/sun/Kconfig"
f2c60e
 source "drivers/net/ethernet/tehuti/Kconfig"
f2c60e
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
f2c60e
index a0a03d4..6ae1bb9 100644
f2c60e
--- a/drivers/net/ethernet/Makefile
f2c60e
+++ b/drivers/net/ethernet/Makefile
f2c60e
@@ -81,6 +81,7 @@ obj-$(CONFIG_SFC) += sfc/
f2c60e
 obj-$(CONFIG_SFC_FALCON) += sfc/falcon/
f2c60e
 obj-$(CONFIG_NET_VENDOR_SGI) += sgi/
f2c60e
 obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
f2c60e
+obj-$(CONFIG_NET_VENDOR_SNI) += socionext/
f2c60e
 obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
f2c60e
 obj-$(CONFIG_NET_VENDOR_SUN) += sun/
f2c60e
 obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/
f2c60e
diff --git a/drivers/net/ethernet/socionext/Kconfig b/drivers/net/ethernet/socionext/Kconfig
f2c60e
new file mode 100644
f2c60e
index 0000000..a6dc195
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/net/ethernet/socionext/Kconfig
f2c60e
@@ -0,0 +1,29 @@
f2c60e
+#
f2c60e
+# Socionext Network device configuration
f2c60e
+#
f2c60e
+
f2c60e
+config NET_VENDOR_SNI
f2c60e
+	bool "Socionext devices"
f2c60e
+	default y
f2c60e
+	---help---
f2c60e
+	  If you have a network (Ethernet) card belonging to this class, say Y.
f2c60e
+
f2c60e
+	  Note that the answer to this question doesn't directly affect the
f2c60e
+	  the questions about Socionext cards. If you say Y, you will be asked
f2c60e
+	  for your specific card in the following questions.
f2c60e
+
f2c60e
+if NET_VENDOR_SNI
f2c60e
+
f2c60e
+config SNI_NETSEC
f2c60e
+	tristate "NETSEC Driver Support"
f2c60e
+	depends on OF
f2c60e
+	select PHYLIB
f2c60e
+	select MII
f2c60e
+help
f2c60e
+	  Enable to add support for the SocioNext NetSec Gigabit Ethernet
f2c60e
+	  controller + PHY, as found on the Synquacer SC2A11 SoC
f2c60e
+
f2c60e
+	  To compile this driver as a module, choose M here: the module will be
f2c60e
+	  called netsec.  If unsure, say N.
f2c60e
+
f2c60e
+endif # NET_VENDOR_SNI
f2c60e
diff --git a/drivers/net/ethernet/socionext/Makefile b/drivers/net/ethernet/socionext/Makefile
f2c60e
new file mode 100644
f2c60e
index 0000000..9555899
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/net/ethernet/socionext/Makefile
f2c60e
@@ -0,0 +1 @@
f2c60e
+obj-$(CONFIG_SNI_NETSEC) += netsec/
f2c60e
diff --git a/drivers/net/ethernet/socionext/netsec/Makefile b/drivers/net/ethernet/socionext/netsec/Makefile
f2c60e
new file mode 100644
f2c60e
index 0000000..18884ed
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/net/ethernet/socionext/netsec/Makefile
f2c60e
@@ -0,0 +1,6 @@
f2c60e
+obj-$(CONFIG_SNI_NETSEC) := netsec.o
f2c60e
+netsec-objs := netsec_desc_ring_access.o \
f2c60e
+		netsec_netdev.o \
f2c60e
+		netsec_ethtool.o \
f2c60e
+		netsec_platform.o \
f2c60e
+		netsec_gmac_access.o
f2c60e
diff --git a/drivers/net/ethernet/socionext/netsec/netsec.h b/drivers/net/ethernet/socionext/netsec/netsec.h
f2c60e
new file mode 100644
f2c60e
index 0000000..3b97661
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/net/ethernet/socionext/netsec/netsec.h
f2c60e
@@ -0,0 +1,408 @@
f2c60e
+/**
f2c60e
+ * netsec.h
f2c60e
+ *
f2c60e
+ *  Copyright (C) 2013-2014 Fujitsu Semiconductor Limited.
f2c60e
+ *  Copyright (C) 2014-2017 Linaro Ltd. All rights reserved.
f2c60e
+ *     Andy Green <andy.green@linaro.org>
f2c60e
+ *     Jassi Brar <jaswinder.singh@linaro.org>
f2c60e
+ *     Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
+ *
f2c60e
+ *  This program is free software; you can redistribute it and/or
f2c60e
+ *  modify it under the terms of the GNU General Public License
f2c60e
+ *  as published by the Free Software Foundation; either version 2
f2c60e
+ *  of the License, or (at your option) any later version.
f2c60e
+ */
f2c60e
+#ifndef NETSEC_INTERNAL_H
f2c60e
+#define NETSEC_INTERNAL_H
f2c60e
+
f2c60e
+#include <linux/netdevice.h>
f2c60e
+#include <linux/types.h>
f2c60e
+#include <linux/device.h>
f2c60e
+#include <linux/phy.h>
f2c60e
+#include <linux/ethtool.h>
f2c60e
+#include <linux/of_address.h>
f2c60e
+#include <linux/of_mdio.h>
f2c60e
+#include <linux/etherdevice.h>
f2c60e
+#include <net/sock.h>
f2c60e
+
f2c60e
+#define NETSEC_FLOW_CONTROL_START_THRESHOLD	36
f2c60e
+#define NETSEC_FLOW_CONTROL_STOP_THRESHOLD	48
f2c60e
+
f2c60e
+#define NETSEC_CLK_MHZ				1000000
f2c60e
+
f2c60e
+#define NETSEC_RX_PKT_BUF_LEN			1522
f2c60e
+#define NETSEC_RX_JUMBO_PKT_BUF_LEN		9022
f2c60e
+
f2c60e
+#define NETSEC_NETDEV_TX_PKT_SCAT_NUM_MAX	19
f2c60e
+
f2c60e
+#define DESC_NUM				128
f2c60e
+
f2c60e
+#define NETSEC_TX_SHIFT_OWN_FIELD		31
f2c60e
+#define NETSEC_TX_SHIFT_LD_FIELD		30
f2c60e
+#define NETSEC_TX_SHIFT_DRID_FIELD		24
f2c60e
+#define NETSEC_TX_SHIFT_PT_FIELD		21
f2c60e
+#define NETSEC_TX_SHIFT_TDRID_FIELD		16
f2c60e
+#define NETSEC_TX_SHIFT_CC_FIELD		15
f2c60e
+#define NETSEC_TX_SHIFT_FS_FIELD		9
f2c60e
+#define NETSEC_TX_LAST				8
f2c60e
+#define NETSEC_TX_SHIFT_CO			7
f2c60e
+#define NETSEC_TX_SHIFT_SO			6
f2c60e
+#define NETSEC_TX_SHIFT_TRS_FIELD		4
f2c60e
+
f2c60e
+#define NETSEC_RX_PKT_OWN_FIELD			31
f2c60e
+#define NETSEC_RX_PKT_LD_FIELD			30
f2c60e
+#define NETSEC_RX_PKT_SDRID_FIELD		24
f2c60e
+#define NETSEC_RX_PKT_FR_FIELD			23
f2c60e
+#define NETSEC_RX_PKT_ER_FIELD			21
f2c60e
+#define NETSEC_RX_PKT_ERR_FIELD			16
f2c60e
+#define NETSEC_RX_PKT_TDRID_FIELD		12
f2c60e
+#define NETSEC_RX_PKT_FS_FIELD			9
f2c60e
+#define NETSEC_RX_PKT_LS_FIELD			8
f2c60e
+#define NETSEC_RX_PKT_CO_FIELD			6
f2c60e
+
f2c60e
+#define NETSEC_RX_PKT_ERR_MASK			3
f2c60e
+
f2c60e
+#define NETSEC_MAX_TX_PKT_LEN			1518
f2c60e
+#define NETSEC_MAX_TX_JUMBO_PKT_LEN		9018
f2c60e
+
f2c60e
+enum netsec_rings {
f2c60e
+	NETSEC_RING_TX,
f2c60e
+	NETSEC_RING_RX
f2c60e
+};
f2c60e
+
f2c60e
+#define NETSEC_RING_GMAC			15
f2c60e
+#define NETSEC_RING_MAX				1
f2c60e
+
f2c60e
+#define NETSEC_TCP_SEG_LEN_MAX			1460
f2c60e
+#define NETSEC_TCP_JUMBO_SEG_LEN_MAX		8960
f2c60e
+
f2c60e
+#define NETSEC_RX_CKSUM_NOTAVAIL		0
f2c60e
+#define NETSEC_RX_CKSUM_OK			1
f2c60e
+#define NETSEC_RX_CKSUM_NG			2
f2c60e
+
f2c60e
+#define NETSEC_TOP_IRQ_REG_CODE_LOAD_END	BIT(20)
f2c60e
+#define NETSEC_IRQ_TRANSITION_COMPLETE		BIT(4)
f2c60e
+#define NETSEC_IRQ_RX				BIT(1)
f2c60e
+#define NETSEC_IRQ_TX				BIT(0)
f2c60e
+
f2c60e
+#define NETSEC_IRQ_EMPTY			BIT(17)
f2c60e
+#define NETSEC_IRQ_ERR				BIT(16)
f2c60e
+#define NETSEC_IRQ_PKT_CNT			BIT(15)
f2c60e
+#define NETSEC_IRQ_TIMEUP			BIT(14)
f2c60e
+#define NETSEC_IRQ_RCV				(NETSEC_IRQ_PKT_CNT | \
f2c60e
+						 NETSEC_IRQ_TIMEUP)
f2c60e
+
f2c60e
+#define NETSEC_IRQ_TX_DONE			BIT(15)
f2c60e
+#define NETSEC_IRQ_SND				(NETSEC_IRQ_TX_DONE | \
f2c60e
+						 NETSEC_IRQ_TIMEUP)
f2c60e
+
f2c60e
+#define NETSEC_MODE_TRANS_COMP_IRQ_N2T		BIT(20)
f2c60e
+#define NETSEC_MODE_TRANS_COMP_IRQ_T2N		BIT(19)
f2c60e
+
f2c60e
+#define NETSEC_DESC_MIN				2
f2c60e
+#define NETSEC_DESC_MAX				2047
f2c60e
+#define NETSEC_INT_PKTCNT_MAX			2047
f2c60e
+
f2c60e
+#define NETSEC_FLOW_START_TH_MAX		95
f2c60e
+#define NETSEC_FLOW_STOP_TH_MAX			95
f2c60e
+#define NETSEC_FLOW_PAUSE_TIME_MIN		5
f2c60e
+
f2c60e
+#define NETSEC_CLK_EN_REG_DOM_ALL		0x3f
f2c60e
+
f2c60e
+#define NETSEC_REG_TOP_STATUS			0x80
f2c60e
+#define NETSEC_REG_TOP_INTEN			0x81
f2c60e
+#define NETSEC_REG_INTEN_SET			0x8d
f2c60e
+#define NETSEC_REG_INTEN_CLR			0x8e
f2c60e
+#define NETSEC_REG_NRM_TX_STATUS		0x100
f2c60e
+#define NETSEC_REG_NRM_TX_INTEN			0x101
f2c60e
+#define NETSEC_REG_NRM_TX_INTEN_SET		0x10a
f2c60e
+#define NETSEC_REG_NRM_TX_INTEN_CLR		0x10b
f2c60e
+#define NETSEC_REG_NRM_RX_STATUS		0x110
f2c60e
+#define NETSEC_REG_NRM_RX_INTEN			0x111
f2c60e
+#define NETSEC_REG_NRM_RX_INTEN_SET		0x11a
f2c60e
+#define NETSEC_REG_NRM_RX_INTEN_CLR		0x11b
f2c60e
+#define NETSEC_REG_RESERVED_RX_DESC_START	0x122
f2c60e
+#define NETSEC_REG_RESERVED_TX_DESC_START	0x132
f2c60e
+#define NETSEC_REG_CLK_EN			0x40
f2c60e
+#define NETSEC_REG_SOFT_RST			0x41
f2c60e
+#define NETSEC_REG_PKT_CMD_BUF			0x34
f2c60e
+#define NETSEC_REG_PKT_CTRL			0x50
f2c60e
+#define NETSEC_REG_COM_INIT			0x48
f2c60e
+#define NETSEC_REG_DMA_TMR_CTRL			0x83
f2c60e
+#define NETSEC_REG_F_TAIKI_MC_VER		0x8b
f2c60e
+#define NETSEC_REG_F_TAIKI_VER			0x8c
f2c60e
+#define NETSEC_REG_DMA_HM_CTRL			0x85
f2c60e
+#define NETSEC_REG_DMA_MH_CTRL			0x88
f2c60e
+#define NETSEC_REG_ADDR_DIS_CORE		0x86
f2c60e
+#define NETSEC_REG_DMAC_HM_CMD_BUF		0x84
f2c60e
+#define NETSEC_REG_DMAC_MH_CMD_BUF		0x87
f2c60e
+#define NETSEC_REG_NRM_TX_PKTCNT		0x104
f2c60e
+#define NETSEC_REG_NRM_TX_DONE_TXINT_PKTCNT	0x106
f2c60e
+#define NETSEC_REG_NRM_RX_RXINT_PKTCNT		0x116
f2c60e
+#define NETSEC_REG_NRM_TX_TXINT_TMR		0x108
f2c60e
+#define NETSEC_REG_NRM_RX_RXINT_TMR		0x118
f2c60e
+#define NETSEC_REG_NRM_TX_DONE_PKTCNT		0x105
f2c60e
+#define NETSEC_REG_NRM_RX_PKTCNT		0x115
f2c60e
+#define NETSEC_REG_NRM_TX_TMR			0x107
f2c60e
+#define NETSEC_REG_NRM_RX_TMR			0x117
f2c60e
+#define NETSEC_REG_NRM_TX_DESC_START_UP		0x10d
f2c60e
+#define NETSEC_REG_NRM_TX_DESC_START_LW		0x102
f2c60e
+#define NETSEC_REG_NRM_RX_DESC_START_UP		0x11d
f2c60e
+#define NETSEC_REG_NRM_RX_DESC_START_LW		0x112
f2c60e
+#define NETSEC_REG_NRM_TX_CONFIG		0x10c
f2c60e
+#define NETSEC_REG_NRM_RX_CONFIG		0x11c
f2c60e
+#define MAC_REG_DATA				0x470
f2c60e
+#define MAC_REG_CMD				0x471
f2c60e
+#define MAC_REG_FLOW_TH				0x473
f2c60e
+#define MAC_REG_INTF_SEL			0x475
f2c60e
+#define MAC_REG_DESC_INIT			0x47f
f2c60e
+#define MAC_REG_DESC_SOFT_RST			0x481
f2c60e
+#define NETSEC_REG_MODE_TRANS_COMP_STATUS	0x140
f2c60e
+#define GMAC_REG_MCR				0x0000
f2c60e
+#define GMAC_REG_MFFR				0x0004
f2c60e
+#define GMAC_REG_GAR				0x0010
f2c60e
+#define GMAC_REG_GDR				0x0014
f2c60e
+#define GMAC_REG_FCR				0x0018
f2c60e
+#define GMAC_REG_BMR				0x1000
f2c60e
+#define GMAC_REG_RDLAR				0x100c
f2c60e
+#define GMAC_REG_TDLAR				0x1010
f2c60e
+#define GMAC_REG_OMR				0x1018
f2c60e
+
f2c60e
+#define NETSEC_PKT_CTRL_REG_MODE_NRM		BIT(28)
f2c60e
+#define NETSEC_PKT_CTRL_REG_EN_JUMBO		BIT(27)
f2c60e
+#define NETSEC_PKT_CTRL_REG_LOG_CHKSUM_ER	BIT(3)
f2c60e
+#define NETSEC_PKT_CTRL_REG_LOG_HD_INCOMPLETE	BIT(2)
f2c60e
+#define NETSEC_PKT_CTRL_REG_LOG_HD_ER		BIT(1)
f2c60e
+#define NETSEC_PKT_CTRL_REG_DRP_NO_MATCH	BIT(0)
f2c60e
+
f2c60e
+#define NETSEC_CLK_EN_REG_DOM_G			BIT(5)
f2c60e
+#define NETSEC_CLK_EN_REG_DOM_C			BIT(1)
f2c60e
+#define NETSEC_CLK_EN_REG_DOM_D			BIT(0)
f2c60e
+
f2c60e
+#define NETSEC_COM_INIT_REG_DB			BIT(2)
f2c60e
+#define NETSEC_COM_INIT_REG_CLS			BIT(1)
f2c60e
+#define NETSEC_COM_INIT_REG_ALL			(NETSEC_COM_INIT_REG_CLS | \
f2c60e
+						 NETSEC_COM_INIT_REG_DB)
f2c60e
+
f2c60e
+#define NETSEC_SOFT_RST_REG_RESET		0
f2c60e
+#define NETSEC_SOFT_RST_REG_RUN			BIT(31)
f2c60e
+
f2c60e
+#define NETSEC_DMA_CTRL_REG_STOP		1
f2c60e
+#define MH_CTRL__MODE_TRANS			BIT(20)
f2c60e
+
f2c60e
+#define NETSEC_GMAC_CMD_ST_READ			0
f2c60e
+#define NETSEC_GMAC_CMD_ST_WRITE		BIT(28)
f2c60e
+#define NETSEC_GMAC_CMD_ST_BUSY			BIT(31)
f2c60e
+
f2c60e
+#define NETSEC_GMAC_BMR_REG_COMMON		0x00412080
f2c60e
+#define NETSEC_GMAC_BMR_REG_RESET		0x00020181
f2c60e
+#define NETSEC_GMAC_BMR_REG_SWR			0x00000001
f2c60e
+
f2c60e
+#define NETSEC_GMAC_OMR_REG_ST			BIT(13)
f2c60e
+#define NETSEC_GMAC_OMR_REG_SR			BIT(1)
f2c60e
+
f2c60e
+#define NETSEC_GMAC_MCR_REG_IBN			BIT(30)
f2c60e
+#define NETSEC_GMAC_MCR_REG_CST			BIT(25)
f2c60e
+#define NETSEC_GMAC_MCR_REG_JE			BIT(20)
f2c60e
+#define NETSEC_MCR_PS				BIT(15)
f2c60e
+#define NETSEC_GMAC_MCR_REG_FES			BIT(14)
f2c60e
+#define NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON	0x0000280c
f2c60e
+#define NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON	0x0001a00c
f2c60e
+
f2c60e
+#define NETSEC_FCR_RFE				BIT(2)
f2c60e
+#define NETSEC_FCR_TFE				BIT(1)
f2c60e
+
f2c60e
+#define NETSEC_GMAC_GAR_REG_GW			BIT(1)
f2c60e
+#define NETSEC_GMAC_GAR_REG_GB			BIT(0)
f2c60e
+
f2c60e
+#define NETSEC_GMAC_GAR_REG_SHIFT_PA		11
f2c60e
+#define NETSEC_GMAC_GAR_REG_SHIFT_GR		6
f2c60e
+#define GMAC_REG_SHIFT_CR_GAR			2
f2c60e
+
f2c60e
+#define NETSEC_GMAC_GAR_REG_CR_25_35_MHZ	2
f2c60e
+#define NETSEC_GMAC_GAR_REG_CR_35_60_MHZ	3
f2c60e
+#define NETSEC_GMAC_GAR_REG_CR_60_100_MHZ	0
f2c60e
+#define NETSEC_GMAC_GAR_REG_CR_100_150_MHZ	1
f2c60e
+#define NETSEC_GMAC_GAR_REG_CR_150_250_MHZ	4
f2c60e
+#define NETSEC_GMAC_GAR_REG_CR_250_300_MHZ	5
f2c60e
+
f2c60e
+#define NETSEC_GMAC_RDLAR_REG_COMMON		0x18000
f2c60e
+#define NETSEC_GMAC_TDLAR_REG_COMMON		0x1c000
f2c60e
+
f2c60e
+#define NETSEC_REG_NETSEC_VER_F_TAIKI		0x50000
f2c60e
+
f2c60e
+#define NETSEC_REG_DESC_RING_CONFIG_CFG_UP	BIT(31)
f2c60e
+#define NETSEC_REG_DESC_RING_CONFIG_CH_RST	BIT(30)
f2c60e
+#define NETSEC_REG_DESC_TMR_MODE		4
f2c60e
+#define NETSEC_REG_DESC_ENDIAN			0
f2c60e
+
f2c60e
+#define NETSEC_MAC_DESC_SOFT_RST_SOFT_RST	1
f2c60e
+#define NETSEC_MAC_DESC_INIT_REG_INIT		1
f2c60e
+
f2c60e
+#define NETSEC_EEPROM_MAC_ADDRESS		0x00
f2c60e
+#define NETSEC_EEPROM_HM_ME_ADDRESS_H		0x08
f2c60e
+#define NETSEC_EEPROM_HM_ME_ADDRESS_L		0x0C
f2c60e
+#define NETSEC_EEPROM_HM_ME_SIZE		0x10
f2c60e
+#define NETSEC_EEPROM_MH_ME_ADDRESS_H		0x14
f2c60e
+#define NETSEC_EEPROM_MH_ME_ADDRESS_L		0x18
f2c60e
+#define NETSEC_EEPROM_MH_ME_SIZE		0x1C
f2c60e
+#define NETSEC_EEPROM_PKT_ME_ADDRESS		0x20
f2c60e
+#define NETSEC_EEPROM_PKT_ME_SIZE		0x24
f2c60e
+
f2c60e
+/* this is used to interpret a register layout */
f2c60e
+struct netsec_pkt_ctrlaram {
f2c60e
+	u8 log_chksum_er_flag:1;
f2c60e
+	u8 log_hd_imcomplete_flag:1;
f2c60e
+	u8 log_hd_er_flag:1;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_param {
f2c60e
+	struct netsec_pkt_ctrlaram pkt_ctrlaram;
f2c60e
+	bool use_jumbo_pkt_flag;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_mac_mode {
f2c60e
+	u16 flow_start_th;
f2c60e
+	u16 flow_stop_th;
f2c60e
+	u16 pause_time;
f2c60e
+	bool flow_ctrl_enable_flag;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_desc_ring {
f2c60e
+	spinlock_t spinlock_desc; /* protect descriptor access */
f2c60e
+	phys_addr_t desc_phys;
f2c60e
+	struct netsec_frag_info *frag;
f2c60e
+	struct sk_buff **priv;
f2c60e
+	void *ring_vaddr;
f2c60e
+	enum netsec_rings id;
f2c60e
+	int len;
f2c60e
+	u16 tx_done_num;
f2c60e
+	u16 rx_num;
f2c60e
+	u16 head;
f2c60e
+	u16 tail;
f2c60e
+	bool running;
f2c60e
+	bool full;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_frag_info {
f2c60e
+	dma_addr_t dma_addr;
f2c60e
+	void *addr;
f2c60e
+	u16 len;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_priv {
f2c60e
+	struct netsec_desc_ring desc_ring[NETSEC_RING_MAX + 1];
f2c60e
+	struct ethtool_coalesce et_coalesce;
f2c60e
+	struct netsec_mac_mode mac_mode;
f2c60e
+	struct netsec_param param;
f2c60e
+	struct napi_struct napi;
f2c60e
+	phy_interface_t phy_interface;
f2c60e
+	spinlock_t tx_queue_lock; /* protect transmit queue */
f2c60e
+	struct netsec_frag_info tx_info[MAX_SKB_FRAGS];
f2c60e
+	struct net_device *ndev;
f2c60e
+	struct device_node *phy_np;
f2c60e
+	struct phy_device *phydev;
f2c60e
+	struct mii_bus *mii_bus;
f2c60e
+	void __iomem *ioaddr;
f2c60e
+	const void *eeprom_base;
f2c60e
+	struct device *dev;
f2c60e
+	struct clk *clk[3];
f2c60e
+	u32 rx_pkt_buf_len;
f2c60e
+	u32 msg_enable;
f2c60e
+	u32 freq;
f2c60e
+	int actual_link_speed;
f2c60e
+	int clock_count;
f2c60e
+	bool rx_cksum_offload_flag;
f2c60e
+	bool actual_duplex;
f2c60e
+	bool irq_registered;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_tx_de {
f2c60e
+	u32 attr;
f2c60e
+	u32 data_buf_addr_up;
f2c60e
+	u32 data_buf_addr_lw;
f2c60e
+	u32 buf_len_info;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_rx_de {
f2c60e
+	u32 attr;
f2c60e
+	u32 data_buf_addr_up;
f2c60e
+	u32 data_buf_addr_lw;
f2c60e
+	u32 buf_len_info;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_tx_pkt_ctrl {
f2c60e
+	u16 tcp_seg_len;
f2c60e
+	bool tcp_seg_offload_flag;
f2c60e
+	bool cksum_offload_flag;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_rx_pkt_info {
f2c60e
+	int rx_cksum_result;
f2c60e
+	int err_code;
f2c60e
+	bool is_fragmented;
f2c60e
+	bool err_flag;
f2c60e
+};
f2c60e
+
f2c60e
+struct netsec_skb_cb {
f2c60e
+	bool is_rx;
f2c60e
+};
f2c60e
+
f2c60e
+static inline void netsec_writel(struct netsec_priv *priv,
f2c60e
+				 u32 reg_addr, u32 val)
f2c60e
+{
f2c60e
+	writel_relaxed(val, priv->ioaddr + (reg_addr << 2));
f2c60e
+}
f2c60e
+
f2c60e
+static inline u32 netsec_readl(struct netsec_priv *priv, u32 reg_addr)
f2c60e
+{
f2c60e
+	return readl_relaxed(priv->ioaddr + (reg_addr << 2));
f2c60e
+}
f2c60e
+
f2c60e
+static inline void netsec_mark_skb_type(struct sk_buff *skb, bool is_rx)
f2c60e
+{
f2c60e
+	struct netsec_skb_cb *cb = (struct netsec_skb_cb *)skb->cb;
f2c60e
+
f2c60e
+	cb->is_rx = is_rx;
f2c60e
+}
f2c60e
+
f2c60e
+static inline bool skb_is_rx(struct sk_buff *skb)
f2c60e
+{
f2c60e
+	struct netsec_skb_cb *cb = (struct netsec_skb_cb *)skb->cb;
f2c60e
+
f2c60e
+	return cb->is_rx;
f2c60e
+}
f2c60e
+
f2c60e
+extern const struct net_device_ops netsec_netdev_ops;
f2c60e
+extern const struct ethtool_ops netsec_ethtool_ops;
f2c60e
+
f2c60e
+int netsec_start_gmac(struct netsec_priv *priv);
f2c60e
+int netsec_stop_gmac(struct netsec_priv *priv);
f2c60e
+int netsec_mii_register(struct netsec_priv *priv);
f2c60e
+void netsec_mii_unregister(struct netsec_priv *priv);
f2c60e
+int netsec_start_desc_ring(struct netsec_priv *priv, enum netsec_rings id);
f2c60e
+void netsec_stop_desc_ring(struct netsec_priv *priv, enum netsec_rings id);
f2c60e
+u16 netsec_get_rx_num(struct netsec_priv *priv);
f2c60e
+u16 netsec_get_tx_avail_num(struct netsec_priv *priv);
f2c60e
+int netsec_clean_tx_desc_ring(struct netsec_priv *priv);
f2c60e
+int netsec_clean_rx_desc_ring(struct netsec_priv *priv);
f2c60e
+int netsec_set_tx_pkt_data(struct netsec_priv *priv,
f2c60e
+			   const struct netsec_tx_pkt_ctrl *tx_ctrl,
f2c60e
+			   u8 count_frags, const struct netsec_frag_info *info,
f2c60e
+			   struct sk_buff *skb);
f2c60e
+int netsec_get_rx_pkt_data(struct netsec_priv *priv,
f2c60e
+			   struct netsec_rx_pkt_info *rxpi,
f2c60e
+			   struct netsec_frag_info *frag, u16 *len,
f2c60e
+			   struct sk_buff **skb);
f2c60e
+void netsec_ring_irq_enable(struct netsec_priv *priv,
f2c60e
+			    enum netsec_rings id, u32 i);
f2c60e
+void netsec_ring_irq_disable(struct netsec_priv *priv,
f2c60e
+			     enum netsec_rings id, u32 i);
f2c60e
+int netsec_alloc_desc_ring(struct netsec_priv *priv, enum netsec_rings id);
f2c60e
+void netsec_free_desc_ring(struct netsec_priv *priv,
f2c60e
+			   struct netsec_desc_ring *desc);
f2c60e
+int netsec_setup_rx_desc(struct netsec_priv *priv,
f2c60e
+			 struct netsec_desc_ring *desc);
f2c60e
+int netsec_netdev_napi_poll(struct napi_struct *napi_p, int budget);
f2c60e
+
f2c60e
+#endif /* NETSEC_INTERNAL_H */
f2c60e
diff --git a/drivers/net/ethernet/socionext/netsec/netsec_desc_ring_access.c b/drivers/net/ethernet/socionext/netsec/netsec_desc_ring_access.c
f2c60e
new file mode 100644
f2c60e
index 0000000..a4e56cd
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/net/ethernet/socionext/netsec/netsec_desc_ring_access.c
f2c60e
@@ -0,0 +1,623 @@
f2c60e
+/**
f2c60e
+ * drivers/net/ethernet/socionext/netsec/netsec_desc_ring_access.c
f2c60e
+ *
f2c60e
+ *  Copyright (C) 2013-2014 Fujitsu Semiconductor Limited.
f2c60e
+ *  Copyright (C) 2014-2017 Linaro Ltd. All rights reserved.
f2c60e
+ *     Andy Green <andy.green@linaro.org>
f2c60e
+ *     Jassi Brar <jaswinder.singh@linaro.org>
f2c60e
+ *     Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
+ *
f2c60e
+ *  This program is free software; you can redistribute it and/or
f2c60e
+ *  modify it under the terms of the GNU General Public License
f2c60e
+ *  as published by the Free Software Foundation; either version 2
f2c60e
+ *  of the License, or (at your option) any later version.
f2c60e
+ */
f2c60e
+
f2c60e
+#include <linux/spinlock.h>
f2c60e
+#include <linux/dma-mapping.h>
f2c60e
+
f2c60e
+#include "netsec.h"
f2c60e
+
f2c60e
+static const u32 ads_irq_set[] = {
f2c60e
+	NETSEC_REG_NRM_TX_INTEN_SET,
f2c60e
+	NETSEC_REG_NRM_RX_INTEN_SET,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 desc_ring_irq_inten_clr_reg_addr[] = {
f2c60e
+	NETSEC_REG_NRM_TX_INTEN_CLR,
f2c60e
+	NETSEC_REG_NRM_RX_INTEN_CLR,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 int_tmr_reg_addr[] = {
f2c60e
+	NETSEC_REG_NRM_TX_TXINT_TMR,
f2c60e
+	NETSEC_REG_NRM_RX_RXINT_TMR,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 rx_pkt_cnt_reg_addr[] = {
f2c60e
+	0,
f2c60e
+	NETSEC_REG_NRM_RX_PKTCNT,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 tx_pkt_cnt_reg_addr[] = {
f2c60e
+	NETSEC_REG_NRM_TX_PKTCNT,
f2c60e
+	0,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 int_pkt_cnt_reg_addr[] = {
f2c60e
+	NETSEC_REG_NRM_TX_DONE_TXINT_PKTCNT,
f2c60e
+	NETSEC_REG_NRM_RX_RXINT_PKTCNT,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 tx_done_pkt_addr[] = {
f2c60e
+	NETSEC_REG_NRM_TX_DONE_PKTCNT,
f2c60e
+	0,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 netsec_desc_mask[] = {
f2c60e
+	[NETSEC_RING_TX] = NETSEC_GMAC_OMR_REG_ST,
f2c60e
+	[NETSEC_RING_RX] = NETSEC_GMAC_OMR_REG_SR
f2c60e
+};
f2c60e
+
f2c60e
+void netsec_ring_irq_enable(struct netsec_priv *priv,
f2c60e
+			    enum netsec_rings id, u32 irqf)
f2c60e
+{
f2c60e
+	netsec_writel(priv, ads_irq_set[id], irqf);
f2c60e
+}
f2c60e
+
f2c60e
+void netsec_ring_irq_disable(struct netsec_priv *priv,
f2c60e
+			     enum netsec_rings id, u32 irqf)
f2c60e
+{
f2c60e
+	netsec_writel(priv, desc_ring_irq_inten_clr_reg_addr[id], irqf);
f2c60e
+}
f2c60e
+
f2c60e
+static struct sk_buff *alloc_rx_pkt_buf(struct netsec_priv *priv,
f2c60e
+					struct netsec_frag_info *info)
f2c60e
+{
f2c60e
+	struct sk_buff *skb;
f2c60e
+
f2c60e
+	if (device_get_dma_attr(priv->dev) == DEV_DMA_COHERENT) {
f2c60e
+		skb = netdev_alloc_skb_ip_align(priv->ndev, info->len);
f2c60e
+	} else {
f2c60e
+		info->len = L1_CACHE_ALIGN(info->len);
f2c60e
+		skb = netdev_alloc_skb(priv->ndev, info->len);
f2c60e
+	}
f2c60e
+	if (!skb)
f2c60e
+		return NULL;
f2c60e
+
f2c60e
+	netsec_mark_skb_type(skb, NETSEC_RING_RX);
f2c60e
+	info->addr = skb->data;
f2c60e
+	info->dma_addr = dma_map_single(priv->dev, info->addr, info->len,
f2c60e
+					DMA_FROM_DEVICE);
f2c60e
+	if (dma_mapping_error(priv->dev, info->dma_addr)) {
f2c60e
+		dev_kfree_skb(skb);
f2c60e
+		return NULL;
f2c60e
+	}
f2c60e
+	return skb;
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_alloc_desc_ring(struct netsec_priv *priv, enum netsec_rings id)
f2c60e
+{
f2c60e
+	struct netsec_desc_ring *desc = &priv->desc_ring[id];
f2c60e
+	int ret = 0;
f2c60e
+
f2c60e
+	desc->id = id;
f2c60e
+	desc->len = sizeof(struct netsec_tx_de); /* rx and tx desc same size */
f2c60e
+
f2c60e
+	spin_lock_init(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	desc->ring_vaddr = dma_zalloc_coherent(priv->dev, desc->len * DESC_NUM,
f2c60e
+					       &desc->desc_phys, GFP_KERNEL);
f2c60e
+	if (!desc->ring_vaddr) {
f2c60e
+		ret = -ENOMEM;
f2c60e
+		goto err;
f2c60e
+	}
f2c60e
+
f2c60e
+	desc->frag = kcalloc(DESC_NUM, sizeof(*desc->frag), GFP_KERNEL);
f2c60e
+	if (!desc->frag) {
f2c60e
+		ret = -ENOMEM;
f2c60e
+		goto err;
f2c60e
+	}
f2c60e
+
f2c60e
+	desc->priv = kcalloc(DESC_NUM, sizeof(struct sk_buff *), GFP_KERNEL);
f2c60e
+	if (!desc->priv) {
f2c60e
+		ret = -ENOMEM;
f2c60e
+		goto err;
f2c60e
+	}
f2c60e
+
f2c60e
+	return 0;
f2c60e
+
f2c60e
+err:
f2c60e
+	netsec_free_desc_ring(priv, desc);
f2c60e
+
f2c60e
+	return ret;
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_uninit_pkt_desc_ring(struct netsec_priv *priv,
f2c60e
+					struct netsec_desc_ring *desc)
f2c60e
+{
f2c60e
+	struct netsec_frag_info *frag;
f2c60e
+	u32 status;
f2c60e
+	u16 idx;
f2c60e
+
f2c60e
+	for (idx = 0; idx < DESC_NUM; idx++) {
f2c60e
+		frag = &desc->frag[idx];
f2c60e
+		if (!frag->addr)
f2c60e
+			continue;
f2c60e
+
f2c60e
+		status = *(u32 *)(desc->ring_vaddr + desc->len * idx);
f2c60e
+
f2c60e
+		dma_unmap_single(priv->dev, frag->dma_addr, frag->len,
f2c60e
+				 skb_is_rx(desc->priv[idx]) ? DMA_FROM_DEVICE :
f2c60e
+							      DMA_TO_DEVICE);
f2c60e
+		if ((status >> NETSEC_TX_LAST) & 1)
f2c60e
+			dev_kfree_skb(desc->priv[idx]);
f2c60e
+	}
f2c60e
+
f2c60e
+	memset(desc->frag, 0, sizeof(struct netsec_frag_info) * DESC_NUM);
f2c60e
+	memset(desc->priv, 0, sizeof(struct sk_buff *) * DESC_NUM);
f2c60e
+	memset(desc->ring_vaddr, 0, desc->len * DESC_NUM);
f2c60e
+}
f2c60e
+
f2c60e
+void netsec_free_desc_ring(struct netsec_priv *priv,
f2c60e
+			   struct netsec_desc_ring *desc)
f2c60e
+{
f2c60e
+	if (desc->ring_vaddr && desc->frag && desc->priv)
f2c60e
+		netsec_uninit_pkt_desc_ring(priv, desc);
f2c60e
+
f2c60e
+	if (desc->ring_vaddr) {
f2c60e
+		dma_free_coherent(priv->dev, desc->len * DESC_NUM,
f2c60e
+				  desc->ring_vaddr, desc->desc_phys);
f2c60e
+		desc->ring_vaddr = NULL;
f2c60e
+	}
f2c60e
+	kfree(desc->frag);
f2c60e
+	desc->frag = NULL;
f2c60e
+	kfree(desc->priv);
f2c60e
+	desc->priv = NULL;
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_set_rx_de(struct netsec_priv *priv,
f2c60e
+			     struct netsec_desc_ring *desc, u16 idx,
f2c60e
+			     const struct netsec_frag_info *info,
f2c60e
+			     struct sk_buff *skb)
f2c60e
+{
f2c60e
+	struct netsec_rx_de *de = desc->ring_vaddr + desc->len * idx;
f2c60e
+	u32 attr = (1 << NETSEC_RX_PKT_OWN_FIELD) |
f2c60e
+		   (1 << NETSEC_RX_PKT_FS_FIELD) |
f2c60e
+		   (1 << NETSEC_RX_PKT_LS_FIELD);
f2c60e
+
f2c60e
+	if (idx == DESC_NUM - 1)
f2c60e
+		attr |= (1 << NETSEC_RX_PKT_LD_FIELD);
f2c60e
+
f2c60e
+	de->data_buf_addr_up = upper_32_bits(info->dma_addr);
f2c60e
+	de->data_buf_addr_lw = lower_32_bits(info->dma_addr);
f2c60e
+	de->buf_len_info = info->len;
f2c60e
+	/* desc->attr makes the descriptor live, so it must be physically
f2c60e
+	 * written last after the rest of the descriptor body is already there
f2c60e
+	 */
f2c60e
+	dma_wmb();
f2c60e
+	de->attr = attr;
f2c60e
+
f2c60e
+	desc->frag[idx].dma_addr = info->dma_addr;
f2c60e
+	desc->frag[idx].addr = info->addr;
f2c60e
+	desc->frag[idx].len = info->len;
f2c60e
+
f2c60e
+	desc->priv[idx] = skb;
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_setup_rx_desc(struct netsec_priv *priv,
f2c60e
+			 struct netsec_desc_ring *desc)
f2c60e
+{
f2c60e
+	struct netsec_frag_info info;
f2c60e
+	struct sk_buff *skb;
f2c60e
+	int n;
f2c60e
+
f2c60e
+	info.len = priv->rx_pkt_buf_len;
f2c60e
+
f2c60e
+	for (n = 0; n < DESC_NUM; n++) {
f2c60e
+		skb = alloc_rx_pkt_buf(priv, &info;;
f2c60e
+		if (!skb) {
f2c60e
+			netsec_uninit_pkt_desc_ring(priv, desc);
f2c60e
+			return -ENOMEM;
f2c60e
+		}
f2c60e
+		netsec_set_rx_de(priv, desc, n, &info, skb);
f2c60e
+	}
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_set_tx_desc_entry(struct netsec_priv *priv,
f2c60e
+				     struct netsec_desc_ring *desc,
f2c60e
+				     const struct netsec_tx_pkt_ctrl *tx_ctrl,
f2c60e
+				     bool first_flag, bool last_flag,
f2c60e
+				     const struct netsec_frag_info *frag,
f2c60e
+				     struct sk_buff *skb)
f2c60e
+{
f2c60e
+	struct netsec_tx_de *tx_desc_entry;
f2c60e
+	int idx = desc->head;
f2c60e
+	u32 attr;
f2c60e
+
f2c60e
+	tx_desc_entry = desc->ring_vaddr + (desc->len * idx);
f2c60e
+
f2c60e
+	attr = (1 << NETSEC_TX_SHIFT_OWN_FIELD) |
f2c60e
+	       (desc->id << NETSEC_TX_SHIFT_DRID_FIELD) |
f2c60e
+	       (1 << NETSEC_TX_SHIFT_PT_FIELD) |
f2c60e
+	       (NETSEC_RING_GMAC << NETSEC_TX_SHIFT_TDRID_FIELD) |
f2c60e
+	       (first_flag << NETSEC_TX_SHIFT_FS_FIELD) |
f2c60e
+	       (last_flag << NETSEC_TX_LAST) |
f2c60e
+	       (tx_ctrl->cksum_offload_flag << NETSEC_TX_SHIFT_CO) |
f2c60e
+	       (tx_ctrl->tcp_seg_offload_flag << NETSEC_TX_SHIFT_SO) |
f2c60e
+	       (1 << NETSEC_TX_SHIFT_TRS_FIELD);
f2c60e
+	if (idx == DESC_NUM - 1)
f2c60e
+		attr |= (1 << NETSEC_TX_SHIFT_LD_FIELD);
f2c60e
+
f2c60e
+	tx_desc_entry->data_buf_addr_up = upper_32_bits(frag->dma_addr);
f2c60e
+	tx_desc_entry->data_buf_addr_lw = lower_32_bits(frag->dma_addr);
f2c60e
+	tx_desc_entry->buf_len_info = (tx_ctrl->tcp_seg_len << 16) | frag->len;
f2c60e
+	/* desc->attr makes the descriptor live, so it must be physically
f2c60e
+	 * written last after the rest of the descriptor body is already there
f2c60e
+	 */
f2c60e
+	dma_wmb();
f2c60e
+	tx_desc_entry->attr = attr;
f2c60e
+
f2c60e
+	desc->frag[idx] = *frag;
f2c60e
+	desc->priv[idx] = skb;
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_get_rx_de(struct netsec_priv *priv,
f2c60e
+			     struct netsec_desc_ring *desc, u16 idx,
f2c60e
+			     struct netsec_rx_pkt_info *rxpi,
f2c60e
+			     struct netsec_frag_info *frag, u16 *len,
f2c60e
+			     struct sk_buff **skb)
f2c60e
+{
f2c60e
+	struct netsec_rx_de de = {};
f2c60e
+
f2c60e
+	*rxpi = (struct netsec_rx_pkt_info){};
f2c60e
+	memcpy(&de, desc->ring_vaddr + desc->len * idx, desc->len);
f2c60e
+
f2c60e
+	dev_dbg(priv->dev, "%08x\n", *(u32 *)&de);
f2c60e
+	*len = de.buf_len_info >> 16;
f2c60e
+
f2c60e
+	rxpi->is_fragmented = (de.attr >> NETSEC_RX_PKT_FR_FIELD) & 1;
f2c60e
+	rxpi->err_flag = (de.attr >> NETSEC_RX_PKT_ER_FIELD) & 1;
f2c60e
+	rxpi->rx_cksum_result = (de.attr >> NETSEC_RX_PKT_CO_FIELD) & 3;
f2c60e
+	rxpi->err_code = (de.attr >> NETSEC_RX_PKT_ERR_FIELD) &
f2c60e
+							NETSEC_RX_PKT_ERR_MASK;
f2c60e
+	*frag = desc->frag[idx];
f2c60e
+	*skb = desc->priv[idx];
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_inc_desc_head_idx(struct netsec_priv *priv,
f2c60e
+				     struct netsec_desc_ring *desc, u16 inc)
f2c60e
+{
f2c60e
+	u32 sum;
f2c60e
+
f2c60e
+	sum = desc->head + inc;
f2c60e
+
f2c60e
+	if (sum >= DESC_NUM)
f2c60e
+		sum -= DESC_NUM;
f2c60e
+
f2c60e
+	desc->head = sum;
f2c60e
+	desc->full = desc->head == desc->tail;
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_inc_desc_tail_idx(struct netsec_priv *priv,
f2c60e
+				     struct netsec_desc_ring *desc)
f2c60e
+{
f2c60e
+	u32 sum;
f2c60e
+
f2c60e
+	sum = desc->tail + 1;
f2c60e
+
f2c60e
+	if (sum >= DESC_NUM)
f2c60e
+		sum -= DESC_NUM;
f2c60e
+
f2c60e
+	desc->tail = sum;
f2c60e
+	desc->full = false;
f2c60e
+}
f2c60e
+
f2c60e
+static u16 netsec_get_tx_avail_num_sub(struct netsec_priv *priv,
f2c60e
+				       const struct netsec_desc_ring *desc)
f2c60e
+{
f2c60e
+	if (desc->full)
f2c60e
+		return 0;
f2c60e
+
f2c60e
+	if (desc->tail > desc->head)
f2c60e
+		return desc->tail - desc->head;
f2c60e
+
f2c60e
+	return DESC_NUM + desc->tail - desc->head;
f2c60e
+}
f2c60e
+
f2c60e
+static u16 netsec_get_tx_done_num_sub(struct netsec_priv *priv,
f2c60e
+				      struct netsec_desc_ring *desc)
f2c60e
+{
f2c60e
+	desc->tx_done_num += netsec_readl(priv, tx_done_pkt_addr[desc->id]);
f2c60e
+
f2c60e
+	return desc->tx_done_num;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_set_irq_coalesce_param(struct netsec_priv *priv,
f2c60e
+					 enum netsec_rings id)
f2c60e
+{
f2c60e
+	int max_frames, tmr;
f2c60e
+
f2c60e
+	switch (id) {
f2c60e
+	case NETSEC_RING_TX:
f2c60e
+		max_frames = priv->et_coalesce.tx_max_coalesced_frames;
f2c60e
+		tmr = priv->et_coalesce.tx_coalesce_usecs;
f2c60e
+		break;
f2c60e
+	case NETSEC_RING_RX:
f2c60e
+		max_frames = priv->et_coalesce.rx_max_coalesced_frames;
f2c60e
+		tmr = priv->et_coalesce.rx_coalesce_usecs;
f2c60e
+		break;
f2c60e
+	default:
f2c60e
+		return -EINVAL;
f2c60e
+	}
f2c60e
+
f2c60e
+	netsec_writel(priv, int_pkt_cnt_reg_addr[id], max_frames);
f2c60e
+	netsec_writel(priv, int_tmr_reg_addr[id], ((tmr != 0) << 31) | tmr);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_start_desc_ring(struct netsec_priv *priv, enum netsec_rings id)
f2c60e
+{
f2c60e
+	struct netsec_desc_ring *desc = &priv->desc_ring[id];
f2c60e
+	int ret = 0;
f2c60e
+
f2c60e
+	spin_lock_bh(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	if (desc->running) {
f2c60e
+		ret = -EBUSY;
f2c60e
+		goto err;
f2c60e
+	}
f2c60e
+
f2c60e
+	switch (desc->id) {
f2c60e
+	case NETSEC_RING_RX:
f2c60e
+		netsec_writel(priv, ads_irq_set[id], NETSEC_IRQ_RCV);
f2c60e
+		break;
f2c60e
+	case NETSEC_RING_TX:
f2c60e
+		netsec_writel(priv, ads_irq_set[id], NETSEC_IRQ_EMPTY);
f2c60e
+		break;
f2c60e
+	}
f2c60e
+
f2c60e
+	netsec_set_irq_coalesce_param(priv, desc->id);
f2c60e
+	desc->running = true;
f2c60e
+
f2c60e
+err:
f2c60e
+	spin_unlock_bh(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	return ret;
f2c60e
+}
f2c60e
+
f2c60e
+void netsec_stop_desc_ring(struct netsec_priv *priv, enum netsec_rings id)
f2c60e
+{
f2c60e
+	struct netsec_desc_ring *desc = &priv->desc_ring[id];
f2c60e
+
f2c60e
+	spin_lock_bh(&desc->spinlock_desc);
f2c60e
+	if (desc->running)
f2c60e
+		netsec_writel(priv, desc_ring_irq_inten_clr_reg_addr[id],
f2c60e
+			      NETSEC_IRQ_RCV | NETSEC_IRQ_EMPTY |
f2c60e
+			      NETSEC_IRQ_SND);
f2c60e
+
f2c60e
+	desc->running = false;
f2c60e
+	spin_unlock_bh(&desc->spinlock_desc);
f2c60e
+}
f2c60e
+
f2c60e
+u16 netsec_get_rx_num(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	struct netsec_desc_ring *desc = &priv->desc_ring[NETSEC_RING_RX];
f2c60e
+	u32 result;
f2c60e
+
f2c60e
+	spin_lock(&desc->spinlock_desc);
f2c60e
+	if (desc->running) {
f2c60e
+		result = netsec_readl(priv,
f2c60e
+				      rx_pkt_cnt_reg_addr[NETSEC_RING_RX]);
f2c60e
+		desc->rx_num += result;
f2c60e
+		if (result)
f2c60e
+			netsec_inc_desc_head_idx(priv, desc, result);
f2c60e
+	}
f2c60e
+	spin_unlock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	return desc->rx_num;
f2c60e
+}
f2c60e
+
f2c60e
+u16 netsec_get_tx_avail_num(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	struct netsec_desc_ring *desc = &priv->desc_ring[NETSEC_RING_TX];
f2c60e
+	u16 result;
f2c60e
+
f2c60e
+	spin_lock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	if (!desc->running) {
f2c60e
+		netif_err(priv, drv, priv->ndev,
f2c60e
+			  "%s: not running tx desc\n", __func__);
f2c60e
+		result = 0;
f2c60e
+		goto err;
f2c60e
+	}
f2c60e
+
f2c60e
+	result = netsec_get_tx_avail_num_sub(priv, desc);
f2c60e
+
f2c60e
+err:
f2c60e
+	spin_unlock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	return result;
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_clean_tx_desc_ring(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	struct netsec_desc_ring *desc = &priv->desc_ring[NETSEC_RING_TX];
f2c60e
+	unsigned int pkts = 0, bytes = 0;
f2c60e
+	struct netsec_frag_info *frag;
f2c60e
+	struct netsec_tx_de *entry;
f2c60e
+	bool is_last;
f2c60e
+
f2c60e
+	spin_lock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	netsec_get_tx_done_num_sub(priv, desc);
f2c60e
+
f2c60e
+	while ((desc->tail != desc->head || desc->full) && desc->tx_done_num) {
f2c60e
+		frag = &desc->frag[desc->tail];
f2c60e
+		entry = desc->ring_vaddr + desc->len * desc->tail;
f2c60e
+		is_last = (entry->attr >> NETSEC_TX_LAST) & 1;
f2c60e
+
f2c60e
+		dma_unmap_single(priv->dev, frag->dma_addr, frag->len,
f2c60e
+				 DMA_TO_DEVICE);
f2c60e
+		if (is_last) {
f2c60e
+			pkts++;
f2c60e
+			bytes += desc->priv[desc->tail]->len;
f2c60e
+			dev_kfree_skb(desc->priv[desc->tail]);
f2c60e
+		}
f2c60e
+		*frag = (struct netsec_frag_info){};
f2c60e
+		netsec_inc_desc_tail_idx(priv, desc);
f2c60e
+
f2c60e
+		if (is_last)
f2c60e
+			desc->tx_done_num--;
f2c60e
+	}
f2c60e
+
f2c60e
+	spin_unlock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	priv->ndev->stats.tx_packets += pkts;
f2c60e
+	priv->ndev->stats.tx_bytes += bytes;
f2c60e
+
f2c60e
+	netdev_completed_queue(priv->ndev, pkts, bytes);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_clean_rx_desc_ring(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	struct netsec_desc_ring *desc = &priv->desc_ring[NETSEC_RING_RX];
f2c60e
+
f2c60e
+	spin_lock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	while (desc->full || (desc->tail != desc->head)) {
f2c60e
+		netsec_set_rx_de(priv, desc, desc->tail,
f2c60e
+				 &desc->frag[desc->tail],
f2c60e
+				 desc->priv[desc->tail]);
f2c60e
+		desc->rx_num--;
f2c60e
+		netsec_inc_desc_tail_idx(priv, desc);
f2c60e
+	}
f2c60e
+
f2c60e
+	spin_unlock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_set_tx_pkt_data(struct netsec_priv *priv,
f2c60e
+			   const struct netsec_tx_pkt_ctrl *tx_ctrl,
f2c60e
+			   u8 count_frags, const struct netsec_frag_info *info,
f2c60e
+			   struct sk_buff *skb)
f2c60e
+{
f2c60e
+	struct netsec_desc_ring *desc;
f2c60e
+	u32 sum_len = 0;
f2c60e
+	unsigned int i;
f2c60e
+	int ret = 0;
f2c60e
+
f2c60e
+	if (tx_ctrl->tcp_seg_offload_flag && !tx_ctrl->cksum_offload_flag)
f2c60e
+		return -EINVAL;
f2c60e
+
f2c60e
+	if (tx_ctrl->tcp_seg_offload_flag) {
f2c60e
+		if (tx_ctrl->tcp_seg_len == 0)
f2c60e
+			return -EINVAL;
f2c60e
+
f2c60e
+		if (priv->param.use_jumbo_pkt_flag) {
f2c60e
+			if (tx_ctrl->tcp_seg_len > NETSEC_TCP_JUMBO_SEG_LEN_MAX)
f2c60e
+				return -EINVAL;
f2c60e
+		} else {
f2c60e
+			if (tx_ctrl->tcp_seg_len > NETSEC_TCP_SEG_LEN_MAX)
f2c60e
+				return -EINVAL;
f2c60e
+		}
f2c60e
+	} else {
f2c60e
+		if (tx_ctrl->tcp_seg_len)
f2c60e
+			return -EINVAL;
f2c60e
+	}
f2c60e
+
f2c60e
+	if (!count_frags)
f2c60e
+		return -ERANGE;
f2c60e
+
f2c60e
+	for (i = 0; i < count_frags; i++) {
f2c60e
+		if ((info[i].len == 0) || (info[i].len > 0xffff)) {
f2c60e
+			netif_err(priv, drv, priv->ndev,
f2c60e
+				  "%s: bad info len\n", __func__);
f2c60e
+			return -EINVAL;
f2c60e
+		}
f2c60e
+		sum_len += info[i].len;
f2c60e
+	}
f2c60e
+
f2c60e
+	if (!tx_ctrl->tcp_seg_offload_flag) {
f2c60e
+		if (priv->param.use_jumbo_pkt_flag) {
f2c60e
+			if (sum_len > NETSEC_MAX_TX_JUMBO_PKT_LEN)
f2c60e
+				return -EINVAL;
f2c60e
+		} else {
f2c60e
+			if (sum_len > NETSEC_MAX_TX_PKT_LEN)
f2c60e
+				return -EINVAL;
f2c60e
+		}
f2c60e
+	}
f2c60e
+
f2c60e
+	desc = &priv->desc_ring[NETSEC_RING_TX];
f2c60e
+	spin_lock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	if (!desc->running) {
f2c60e
+		ret = -ENODEV;
f2c60e
+		goto end;
f2c60e
+	}
f2c60e
+
f2c60e
+	dma_rmb(); /* we need to see a consistent view of pending tx count */
f2c60e
+	if (count_frags > netsec_get_tx_avail_num_sub(priv, desc)) {
f2c60e
+		ret = -EBUSY;
f2c60e
+		goto end;
f2c60e
+	}
f2c60e
+
f2c60e
+	for (i = 0; i < count_frags; i++) {
f2c60e
+		netsec_set_tx_desc_entry(priv, desc, tx_ctrl, i == 0,
f2c60e
+					 i == count_frags - 1, &info[i], skb);
f2c60e
+		netsec_inc_desc_head_idx(priv, desc, 1);
f2c60e
+	}
f2c60e
+
f2c60e
+	dma_wmb(); /* ensure the descriptor is flushed */
f2c60e
+	netsec_writel(priv, tx_pkt_cnt_reg_addr[NETSEC_RING_TX], 1);
f2c60e
+
f2c60e
+end:
f2c60e
+	spin_unlock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	return ret;
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_get_rx_pkt_data(struct netsec_priv *priv,
f2c60e
+			   struct netsec_rx_pkt_info *rxpi,
f2c60e
+			   struct netsec_frag_info *frag, u16 *len,
f2c60e
+			   struct sk_buff **skb)
f2c60e
+{
f2c60e
+	struct netsec_desc_ring *desc = &priv->desc_ring[NETSEC_RING_RX];
f2c60e
+	struct netsec_frag_info info;
f2c60e
+	struct sk_buff *tmp_skb;
f2c60e
+	int ret = 0;
f2c60e
+
f2c60e
+	spin_lock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	if (desc->rx_num == 0) {
f2c60e
+		dev_err(priv->dev, "%s 0 len rx\n", __func__);
f2c60e
+		ret = -EINVAL;
f2c60e
+		goto err;
f2c60e
+	}
f2c60e
+
f2c60e
+	info.len = priv->rx_pkt_buf_len;
f2c60e
+	dma_rmb(); /* we need to ensure we only see current data in descriptor */
f2c60e
+	tmp_skb = alloc_rx_pkt_buf(priv, &info;;
f2c60e
+	if (!tmp_skb) {
f2c60e
+		netsec_set_rx_de(priv, desc, desc->tail,
f2c60e
+				 &desc->frag[desc->tail],
f2c60e
+				 desc->priv[desc->tail]);
f2c60e
+		ret = -ENOMEM;
f2c60e
+	} else {
f2c60e
+		netsec_get_rx_de(priv, desc, desc->tail, rxpi, frag, len, skb);
f2c60e
+		netsec_set_rx_de(priv, desc, desc->tail, &info, tmp_skb);
f2c60e
+	}
f2c60e
+
f2c60e
+	netsec_inc_desc_tail_idx(priv, desc);
f2c60e
+	desc->rx_num--;
f2c60e
+
f2c60e
+err:
f2c60e
+	spin_unlock(&desc->spinlock_desc);
f2c60e
+
f2c60e
+	return ret;
f2c60e
+}
f2c60e
diff --git a/drivers/net/ethernet/socionext/netsec/netsec_ethtool.c b/drivers/net/ethernet/socionext/netsec/netsec_ethtool.c
f2c60e
new file mode 100644
f2c60e
index 0000000..45830fe
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/net/ethernet/socionext/netsec/netsec_ethtool.c
f2c60e
@@ -0,0 +1,78 @@
f2c60e
+/**
f2c60e
+ * drivers/net/ethernet/socionext/netsec/netsec_ethtool.c
f2c60e
+ *
f2c60e
+ *  Copyright (C) 2013-2014 Fujitsu Semiconductor Limited.
f2c60e
+ *  Copyright (C) 2014-2017 Linaro Ltd. All rights reserved.
f2c60e
+ *     Andy Green <andy.green@linaro.org>
f2c60e
+ *     Jassi Brar <jaswinder.singh@linaro.org>
f2c60e
+ *     Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
+ *
f2c60e
+ *  This program is free software; you can redistribute it and/or
f2c60e
+ *  modify it under the terms of the GNU General Public License
f2c60e
+ *  as published by the Free Software Foundation; either version 2
f2c60e
+ *  of the License, or (at your option) any later version.
f2c60e
+ */
f2c60e
+
f2c60e
+#include "netsec.h"
f2c60e
+
f2c60e
+static void netsec_et_get_drvinfo(struct net_device *net_device,
f2c60e
+				  struct ethtool_drvinfo *info)
f2c60e
+{
f2c60e
+	strlcpy(info->driver, "netsec", sizeof(info->driver));
f2c60e
+	strlcpy(info->bus_info, dev_name(net_device->dev.parent),
f2c60e
+		sizeof(info->bus_info));
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_et_get_coalesce(struct net_device *net_device,
f2c60e
+				  struct ethtool_coalesce *et_coalesce)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = netdev_priv(net_device);
f2c60e
+
f2c60e
+	*et_coalesce = priv->et_coalesce;
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_et_set_coalesce(struct net_device *net_device,
f2c60e
+				  struct ethtool_coalesce *et_coalesce)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = netdev_priv(net_device);
f2c60e
+
f2c60e
+	if (et_coalesce->rx_max_coalesced_frames > NETSEC_INT_PKTCNT_MAX)
f2c60e
+		return -EINVAL;
f2c60e
+	if (et_coalesce->tx_max_coalesced_frames > NETSEC_INT_PKTCNT_MAX)
f2c60e
+		return -EINVAL;
f2c60e
+	if (!et_coalesce->rx_max_coalesced_frames)
f2c60e
+		return -EINVAL;
f2c60e
+	if (!et_coalesce->tx_max_coalesced_frames)
f2c60e
+		return -EINVAL;
f2c60e
+
f2c60e
+	priv->et_coalesce = *et_coalesce;
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static u32 netsec_et_get_msglevel(struct net_device *dev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = netdev_priv(dev);
f2c60e
+
f2c60e
+	return priv->msg_enable;
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_et_set_msglevel(struct net_device *dev, u32 datum)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = netdev_priv(dev);
f2c60e
+
f2c60e
+	priv->msg_enable = datum;
f2c60e
+}
f2c60e
+
f2c60e
+const struct ethtool_ops netsec_ethtool_ops = {
f2c60e
+	.get_drvinfo		= netsec_et_get_drvinfo,
f2c60e
+	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
f2c60e
+	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
f2c60e
+	.get_link		= ethtool_op_get_link,
f2c60e
+	.get_coalesce		= netsec_et_get_coalesce,
f2c60e
+	.set_coalesce		= netsec_et_set_coalesce,
f2c60e
+	.get_msglevel		= netsec_et_get_msglevel,
f2c60e
+	.set_msglevel		= netsec_et_set_msglevel,
f2c60e
+};
f2c60e
diff --git a/drivers/net/ethernet/socionext/netsec/netsec_gmac_access.c b/drivers/net/ethernet/socionext/netsec/netsec_gmac_access.c
f2c60e
new file mode 100644
f2c60e
index 0000000..94e9b7f
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/net/ethernet/socionext/netsec/netsec_gmac_access.c
f2c60e
@@ -0,0 +1,330 @@
f2c60e
+/**
f2c60e
+ * drivers/net/ethernet/socionext/netsec/netsec_gmac_access.c
f2c60e
+ *
f2c60e
+ *  Copyright (C) 2013-2014 Fujitsu Semiconductor Limited.
f2c60e
+ *  Copyright (C) 2014-2017 Linaro Ltd. All rights reserved.
f2c60e
+ *     Andy Green <andy.green@linaro.org>
f2c60e
+ *     Jassi Brar <jaswinder.singh@linaro.org>
f2c60e
+ *     Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
+ *
f2c60e
+ *  This program is free software; you can redistribute it and/or
f2c60e
+ *  modify it under the terms of the GNU General Public License
f2c60e
+ *  as published by the Free Software Foundation; either version 2
f2c60e
+ *  of the License, or (at your option) any later version.
f2c60e
+ */
f2c60e
+#include "netsec.h"
f2c60e
+
f2c60e
+#define TIMEOUT_SPINS_MAC		1000
f2c60e
+#define TIMEOUT_SECONDARY_MS_MAC	100
f2c60e
+
f2c60e
+static u32 netsec_clk_type(u32 freq)
f2c60e
+{
f2c60e
+	if (freq < 35 * NETSEC_CLK_MHZ)
f2c60e
+		return NETSEC_GMAC_GAR_REG_CR_25_35_MHZ;
f2c60e
+	if (freq < 60 * NETSEC_CLK_MHZ)
f2c60e
+		return NETSEC_GMAC_GAR_REG_CR_35_60_MHZ;
f2c60e
+	if (freq < 100 * NETSEC_CLK_MHZ)
f2c60e
+		return NETSEC_GMAC_GAR_REG_CR_60_100_MHZ;
f2c60e
+	if (freq < 150 * NETSEC_CLK_MHZ)
f2c60e
+		return NETSEC_GMAC_GAR_REG_CR_100_150_MHZ;
f2c60e
+	if (freq < 250 * NETSEC_CLK_MHZ)
f2c60e
+		return NETSEC_GMAC_GAR_REG_CR_150_250_MHZ;
f2c60e
+
f2c60e
+	return NETSEC_GMAC_GAR_REG_CR_250_300_MHZ;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_wait_while_busy(struct netsec_priv *priv, u32 addr, u32 mask)
f2c60e
+{
f2c60e
+	u32 timeout = TIMEOUT_SPINS_MAC;
f2c60e
+
f2c60e
+	while (--timeout && netsec_readl(priv, addr) & mask)
f2c60e
+		cpu_relax();
f2c60e
+	if (timeout)
f2c60e
+		return 0;
f2c60e
+
f2c60e
+	timeout = TIMEOUT_SECONDARY_MS_MAC;
f2c60e
+	while (--timeout && netsec_readl(priv, addr) & mask)
f2c60e
+		usleep_range(1000, 2000);
f2c60e
+
f2c60e
+	if (timeout)
f2c60e
+		return 0;
f2c60e
+
f2c60e
+	netdev_WARN(priv->ndev, "%s: timeout\n", __func__);
f2c60e
+
f2c60e
+	return -ETIMEDOUT;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_mac_write(struct netsec_priv *priv, u32 addr, u32 value)
f2c60e
+{
f2c60e
+	netsec_writel(priv, MAC_REG_DATA, value);
f2c60e
+	netsec_writel(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_WRITE);
f2c60e
+	return netsec_wait_while_busy(priv,
f2c60e
+				      MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY);
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_mac_read(struct netsec_priv *priv, u32 addr, u32 *read)
f2c60e
+{
f2c60e
+	int ret;
f2c60e
+
f2c60e
+	netsec_writel(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_READ);
f2c60e
+	ret = netsec_wait_while_busy(priv,
f2c60e
+				     MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY);
f2c60e
+	if (ret)
f2c60e
+		return ret;
f2c60e
+
f2c60e
+	*read = netsec_readl(priv, MAC_REG_DATA);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_mac_wait_while_busy(struct netsec_priv *priv,
f2c60e
+				      u32 addr, u32 mask)
f2c60e
+{
f2c60e
+	u32 timeout = TIMEOUT_SPINS_MAC;
f2c60e
+	int ret, data;
f2c60e
+
f2c60e
+	do {
f2c60e
+		ret = netsec_mac_read(priv, addr, &data);
f2c60e
+		if (ret)
f2c60e
+			break;
f2c60e
+		cpu_relax();
f2c60e
+	} while (--timeout && (data & mask));
f2c60e
+
f2c60e
+	if (timeout)
f2c60e
+		return 0;
f2c60e
+
f2c60e
+	timeout = TIMEOUT_SECONDARY_MS_MAC;
f2c60e
+	do {
f2c60e
+		usleep_range(1000, 2000);
f2c60e
+
f2c60e
+		ret = netsec_mac_read(priv, addr, &data);
f2c60e
+		if (ret)
f2c60e
+			break;
f2c60e
+		cpu_relax();
f2c60e
+	} while (--timeout && (data & mask));
f2c60e
+
f2c60e
+	if (timeout && !ret)
f2c60e
+		return 0;
f2c60e
+
f2c60e
+	netdev_WARN(priv->ndev, "%s: timeout\n", __func__);
f2c60e
+
f2c60e
+	return -ETIMEDOUT;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_mac_update_to_phy_state(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	struct phy_device *phydev = priv->ndev->phydev;
f2c60e
+	u32 value = 0;
f2c60e
+
f2c60e
+	value = phydev->duplex ? NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON :
f2c60e
+				 NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON;
f2c60e
+
f2c60e
+	if (phydev->speed != SPEED_1000)
f2c60e
+		value |= NETSEC_MCR_PS;
f2c60e
+
f2c60e
+	if ((priv->phy_interface != PHY_INTERFACE_MODE_GMII) &&
f2c60e
+	    (phydev->speed == SPEED_100))
f2c60e
+		value |= NETSEC_GMAC_MCR_REG_FES;
f2c60e
+
f2c60e
+	value |= NETSEC_GMAC_MCR_REG_CST | NETSEC_GMAC_MCR_REG_JE;
f2c60e
+
f2c60e
+	if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII)
f2c60e
+		value |= NETSEC_GMAC_MCR_REG_IBN;
f2c60e
+
f2c60e
+	if (netsec_mac_write(priv, GMAC_REG_MCR, value))
f2c60e
+		return -ETIMEDOUT;
f2c60e
+
f2c60e
+	priv->actual_link_speed = phydev->speed;
f2c60e
+	priv->actual_duplex = phydev->duplex;
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+/* NB netsec_start_gmac() only called from adjust_link */
f2c60e
+
f2c60e
+int netsec_start_gmac(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	struct phy_device *phydev = priv->ndev->phydev;
f2c60e
+	u32 value = 0;
f2c60e
+	int ret;
f2c60e
+
f2c60e
+	if (priv->desc_ring[NETSEC_RING_TX].running &&
f2c60e
+	    priv->desc_ring[NETSEC_RING_RX].running)
f2c60e
+		return 0;
f2c60e
+
f2c60e
+	if (!priv->desc_ring[NETSEC_RING_RX].running &&
f2c60e
+	    !priv->desc_ring[NETSEC_RING_TX].running) {
f2c60e
+		if (phydev->speed != SPEED_1000)
f2c60e
+			value = (NETSEC_GMAC_MCR_REG_CST |
f2c60e
+				 NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON);
f2c60e
+
f2c60e
+		if (netsec_mac_write(priv, GMAC_REG_MCR, value))
f2c60e
+			return -ETIMEDOUT;
f2c60e
+		if (netsec_mac_write(priv, GMAC_REG_BMR,
f2c60e
+				     NETSEC_GMAC_BMR_REG_RESET))
f2c60e
+			return -ETIMEDOUT;
f2c60e
+
f2c60e
+		/* Wait soft reset */
f2c60e
+		usleep_range(1000, 5000);
f2c60e
+
f2c60e
+		ret = netsec_mac_read(priv, GMAC_REG_BMR, &value);
f2c60e
+		if (ret)
f2c60e
+			return ret;
f2c60e
+		if (value & NETSEC_GMAC_BMR_REG_SWR)
f2c60e
+			return -EAGAIN;
f2c60e
+
f2c60e
+		netsec_writel(priv, MAC_REG_DESC_SOFT_RST, 1);
f2c60e
+		if (netsec_wait_while_busy(priv, MAC_REG_DESC_SOFT_RST, 1))
f2c60e
+			return -ETIMEDOUT;
f2c60e
+
f2c60e
+		netsec_writel(priv, MAC_REG_DESC_INIT, 1);
f2c60e
+		if (netsec_wait_while_busy(priv, MAC_REG_DESC_INIT, 1))
f2c60e
+			return -ETIMEDOUT;
f2c60e
+
f2c60e
+		if (netsec_mac_write(priv, GMAC_REG_BMR,
f2c60e
+				     NETSEC_GMAC_BMR_REG_COMMON))
f2c60e
+			return -ETIMEDOUT;
f2c60e
+		if (netsec_mac_write(priv, GMAC_REG_RDLAR,
f2c60e
+				     NETSEC_GMAC_RDLAR_REG_COMMON))
f2c60e
+			return -ETIMEDOUT;
f2c60e
+		if (netsec_mac_write(priv, GMAC_REG_TDLAR,
f2c60e
+				     NETSEC_GMAC_TDLAR_REG_COMMON))
f2c60e
+			return -ETIMEDOUT;
f2c60e
+		if (netsec_mac_write(priv, GMAC_REG_MFFR, 0x80000001))
f2c60e
+			return -ETIMEDOUT;
f2c60e
+
f2c60e
+		ret = netsec_mac_update_to_phy_state(priv);
f2c60e
+		if (ret)
f2c60e
+			return ret;
f2c60e
+
f2c60e
+		if (priv->mac_mode.flow_ctrl_enable_flag) {
f2c60e
+			netsec_writel(priv, MAC_REG_FLOW_TH,
f2c60e
+				      (priv->mac_mode.flow_stop_th << 16) |
f2c60e
+				      priv->mac_mode.flow_start_th);
f2c60e
+			if (netsec_mac_write(priv, GMAC_REG_FCR,
f2c60e
+					     (priv->mac_mode.pause_time << 16) |
f2c60e
+					     NETSEC_FCR_RFE | NETSEC_FCR_TFE))
f2c60e
+				return -ETIMEDOUT;
f2c60e
+		}
f2c60e
+	}
f2c60e
+
f2c60e
+	ret = netsec_mac_read(priv, GMAC_REG_OMR, &value);
f2c60e
+	if (ret)
f2c60e
+		return ret;
f2c60e
+
f2c60e
+	if (!priv->desc_ring[NETSEC_RING_RX].running) {
f2c60e
+		value |= NETSEC_GMAC_OMR_REG_SR;
f2c60e
+		netsec_start_desc_ring(priv, NETSEC_RING_RX);
f2c60e
+	}
f2c60e
+	if (!priv->desc_ring[NETSEC_RING_TX].running) {
f2c60e
+		value |= NETSEC_GMAC_OMR_REG_ST;
f2c60e
+		netsec_start_desc_ring(priv, NETSEC_RING_TX);
f2c60e
+	}
f2c60e
+
f2c60e
+	if (netsec_mac_write(priv, GMAC_REG_OMR, value))
f2c60e
+		return -ETIMEDOUT;
f2c60e
+
f2c60e
+	netsec_writel(priv, NETSEC_REG_INTEN_SET,
f2c60e
+		      NETSEC_IRQ_TX | NETSEC_IRQ_RX);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_stop_gmac(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	u32 value;
f2c60e
+	int ret;
f2c60e
+
f2c60e
+	ret = netsec_mac_read(priv, GMAC_REG_OMR, &value);
f2c60e
+	if (ret)
f2c60e
+		return ret;
f2c60e
+
f2c60e
+	if (priv->desc_ring[NETSEC_RING_RX].running) {
f2c60e
+		value &= ~NETSEC_GMAC_OMR_REG_SR;
f2c60e
+		netsec_stop_desc_ring(priv, NETSEC_RING_RX);
f2c60e
+	}
f2c60e
+	if (priv->desc_ring[NETSEC_RING_TX].running) {
f2c60e
+		value &= ~NETSEC_GMAC_OMR_REG_ST;
f2c60e
+		netsec_stop_desc_ring(priv, NETSEC_RING_TX);
f2c60e
+	}
f2c60e
+
f2c60e
+	priv->actual_link_speed = 0;
f2c60e
+	priv->actual_duplex = false;
f2c60e
+
f2c60e
+	return netsec_mac_write(priv, GMAC_REG_OMR, value);
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_phy_write(struct mii_bus *bus,
f2c60e
+			    int phy_addr, int reg, u16 val)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = bus->priv;
f2c60e
+
f2c60e
+	if (netsec_mac_write(priv, GMAC_REG_GDR, val))
f2c60e
+		return -ETIMEDOUT;
f2c60e
+	if (netsec_mac_write(priv, GMAC_REG_GAR,
f2c60e
+			     phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA |
f2c60e
+			     reg << NETSEC_GMAC_GAR_REG_SHIFT_GR |
f2c60e
+			     NETSEC_GMAC_GAR_REG_GW | NETSEC_GMAC_GAR_REG_GB |
f2c60e
+			     (netsec_clk_type(priv->freq) <<
f2c60e
+			      GMAC_REG_SHIFT_CR_GAR)))
f2c60e
+		return -ETIMEDOUT;
f2c60e
+
f2c60e
+	return netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
f2c60e
+					  NETSEC_GMAC_GAR_REG_GB);
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = bus->priv;
f2c60e
+	u32 data;
f2c60e
+	int ret;
f2c60e
+
f2c60e
+	if (netsec_mac_write(priv, GMAC_REG_GAR, NETSEC_GMAC_GAR_REG_GB |
f2c60e
+			     phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA |
f2c60e
+			     reg_addr << NETSEC_GMAC_GAR_REG_SHIFT_GR |
f2c60e
+			     (netsec_clk_type(priv->freq) <<
f2c60e
+			      GMAC_REG_SHIFT_CR_GAR)))
f2c60e
+		return -ETIMEDOUT;
f2c60e
+
f2c60e
+	ret = netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
f2c60e
+					 NETSEC_GMAC_GAR_REG_GB);
f2c60e
+	if (ret)
f2c60e
+		return ret;
f2c60e
+
f2c60e
+	ret = netsec_mac_read(priv, GMAC_REG_GDR, &data);
f2c60e
+	if (ret)
f2c60e
+		return ret;
f2c60e
+
f2c60e
+	return data;
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_mii_register(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	struct mii_bus *bus = devm_mdiobus_alloc(priv->dev);
f2c60e
+	int ret;
f2c60e
+
f2c60e
+	if (!bus)
f2c60e
+		return -ENOMEM;
f2c60e
+
f2c60e
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(priv->dev));
f2c60e
+	bus->priv = priv;
f2c60e
+	bus->name = "SNI NETSEC MDIO";
f2c60e
+	bus->read = netsec_phy_read;
f2c60e
+	bus->write = netsec_phy_write;
f2c60e
+	bus->parent = priv->dev;
f2c60e
+	priv->mii_bus = bus;
f2c60e
+
f2c60e
+	if (dev_of_node(priv->dev)) {
f2c60e
+		ret = of_mdiobus_register(bus, dev_of_node(priv->dev));
f2c60e
+	} else {
f2c60e
+		/* Mask out all PHYs from auto probing. */
f2c60e
+		bus->phy_mask = ~0;
f2c60e
+		ret = mdiobus_register(bus);
f2c60e
+	}
f2c60e
+	return ret;
f2c60e
+}
f2c60e
+
f2c60e
+void netsec_mii_unregister(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	mdiobus_unregister(priv->mii_bus);
f2c60e
+}
f2c60e
diff --git a/drivers/net/ethernet/socionext/netsec/netsec_netdev.c b/drivers/net/ethernet/socionext/netsec/netsec_netdev.c
f2c60e
new file mode 100644
f2c60e
index 0000000..e99cf0e
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/net/ethernet/socionext/netsec/netsec_netdev.c
f2c60e
@@ -0,0 +1,540 @@
f2c60e
+/**
f2c60e
+ * drivers/net/ethernet/socionext/netsec/netsec_netdev.c
f2c60e
+ *
f2c60e
+ *  Copyright (C) 2013-2014 Fujitsu Semiconductor Limited.
f2c60e
+ *  Copyright (C) 2014-2017 Linaro Ltd. All rights reserved.
f2c60e
+ *     Andy Green <andy.green@linaro.org>
f2c60e
+ *     Jassi Brar <jaswinder.singh@linaro.org>
f2c60e
+ *     Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
+ *
f2c60e
+ *  This program is free software; you can redistribute it and/or
f2c60e
+ *  modify it under the terms of the GNU General Public License
f2c60e
+ *  as published by the Free Software Foundation; either version 2
f2c60e
+ *  of the License, or (at your option) any later version.
f2c60e
+ */
f2c60e
+
f2c60e
+#include <linux/ip.h>
f2c60e
+#include <linux/ipv6.h>
f2c60e
+#include <linux/tcp.h>
f2c60e
+#include <net/tcp.h>
f2c60e
+#include <net/ip6_checksum.h>
f2c60e
+#include <linux/pm_runtime.h>
f2c60e
+
f2c60e
+#include "netsec.h"
f2c60e
+
f2c60e
+#define WAIT_FW_RDY_TIMEOUT 50
f2c60e
+
f2c60e
+static const u32 desc_ring_irq_status_reg_addr[] = {
f2c60e
+	NETSEC_REG_NRM_TX_STATUS,
f2c60e
+	NETSEC_REG_NRM_RX_STATUS,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 desc_ads[] = {
f2c60e
+	NETSEC_REG_NRM_TX_CONFIG,
f2c60e
+	NETSEC_REG_NRM_RX_CONFIG,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 netsec_desc_start_reg_addr_up[] = {
f2c60e
+	NETSEC_REG_NRM_TX_DESC_START_UP,
f2c60e
+	NETSEC_REG_NRM_RX_DESC_START_UP,
f2c60e
+};
f2c60e
+
f2c60e
+static const u32 netsec_desc_start_reg_addr_lw[] = {
f2c60e
+	NETSEC_REG_NRM_TX_DESC_START_LW,
f2c60e
+	NETSEC_REG_NRM_RX_DESC_START_LW,
f2c60e
+};
f2c60e
+
f2c60e
+static u32 netsec_calc_pkt_ctrl_reg_param(const struct netsec_pkt_ctrlaram
f2c60e
+					*pkt_ctrlaram_p)
f2c60e
+{
f2c60e
+	u32 param = NETSEC_PKT_CTRL_REG_MODE_NRM;
f2c60e
+
f2c60e
+	if (pkt_ctrlaram_p->log_chksum_er_flag)
f2c60e
+		param |= NETSEC_PKT_CTRL_REG_LOG_CHKSUM_ER;
f2c60e
+
f2c60e
+	if (pkt_ctrlaram_p->log_hd_imcomplete_flag)
f2c60e
+		param |= NETSEC_PKT_CTRL_REG_LOG_HD_INCOMPLETE;
f2c60e
+
f2c60e
+	if (pkt_ctrlaram_p->log_hd_er_flag)
f2c60e
+		param |= NETSEC_PKT_CTRL_REG_LOG_HD_ER;
f2c60e
+
f2c60e
+	return param;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_netdev_load_ucode_region(struct netsec_priv *priv, u32 reg,
f2c60e
+					   u32 addr_h, u32 addr_l, u32 size)
f2c60e
+{
f2c60e
+	u64 base = (u64)addr_h << 32 | addr_l;
f2c60e
+	__le32 *ucode;
f2c60e
+	u32 i;
f2c60e
+
f2c60e
+	ucode = memremap(base, size * sizeof(u32), MEMREMAP_WT);
f2c60e
+	if (!ucode)
f2c60e
+		return -ENOMEM;
f2c60e
+
f2c60e
+	for (i = 0; i < size; i++)
f2c60e
+		netsec_writel(priv, reg, le32_to_cpu(ucode[i]));
f2c60e
+
f2c60e
+	memunmap(ucode);
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_netdev_load_microcode(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	int err;
f2c60e
+
f2c60e
+	err = netsec_netdev_load_ucode_region(
f2c60e
+		priv, NETSEC_REG_DMAC_HM_CMD_BUF,
f2c60e
+		le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_HM_ME_ADDRESS_H),
f2c60e
+		le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_HM_ME_ADDRESS_L),
f2c60e
+		le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_HM_ME_SIZE));
f2c60e
+	if (err)
f2c60e
+		return err;
f2c60e
+
f2c60e
+	err = netsec_netdev_load_ucode_region(
f2c60e
+		priv, NETSEC_REG_DMAC_MH_CMD_BUF,
f2c60e
+		le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_MH_ME_ADDRESS_H),
f2c60e
+		le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_MH_ME_ADDRESS_L),
f2c60e
+		le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_MH_ME_SIZE));
f2c60e
+	if (err)
f2c60e
+		return err;
f2c60e
+
f2c60e
+	err = netsec_netdev_load_ucode_region(
f2c60e
+		priv, NETSEC_REG_PKT_CMD_BUF,
f2c60e
+		0,
f2c60e
+		le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_PKT_ME_ADDRESS),
f2c60e
+		le32_to_cpup(priv->eeprom_base + NETSEC_EEPROM_PKT_ME_SIZE));
f2c60e
+	if (err)
f2c60e
+		return err;
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_init_hardware(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	u32 value;
f2c60e
+	int err;
f2c60e
+
f2c60e
+	/* set desc_start addr */
f2c60e
+	netsec_writel(priv, netsec_desc_start_reg_addr_up[NETSEC_RING_RX],
f2c60e
+		      upper_32_bits(priv->desc_ring[NETSEC_RING_RX].desc_phys));
f2c60e
+	netsec_writel(priv, netsec_desc_start_reg_addr_lw[NETSEC_RING_RX],
f2c60e
+		      lower_32_bits(priv->desc_ring[NETSEC_RING_RX].desc_phys));
f2c60e
+
f2c60e
+	netsec_writel(priv, netsec_desc_start_reg_addr_up[NETSEC_RING_TX],
f2c60e
+		      upper_32_bits(priv->desc_ring[NETSEC_RING_TX].desc_phys));
f2c60e
+	netsec_writel(priv, netsec_desc_start_reg_addr_lw[NETSEC_RING_TX],
f2c60e
+		      lower_32_bits(priv->desc_ring[NETSEC_RING_TX].desc_phys));
f2c60e
+
f2c60e
+	/* set normal tx desc ring config */
f2c60e
+	netsec_writel(priv, desc_ads[NETSEC_RING_TX],
f2c60e
+		      1 << NETSEC_REG_DESC_ENDIAN);
f2c60e
+	netsec_writel(priv, desc_ads[NETSEC_RING_RX],
f2c60e
+		      1 << NETSEC_REG_DESC_ENDIAN);
f2c60e
+
f2c60e
+	err = netsec_netdev_load_microcode(priv);
f2c60e
+	if (err) {
f2c60e
+		netif_err(priv, probe, priv->ndev,
f2c60e
+			  "%s: failed to load microcode (%d)\n", __func__, err);
f2c60e
+		return err;
f2c60e
+	}
f2c60e
+
f2c60e
+	/* start DMA engines */
f2c60e
+	netsec_writel(priv, NETSEC_REG_DMA_TMR_CTRL, priv->freq / 1000000 - 1);
f2c60e
+	netsec_writel(priv, NETSEC_REG_ADDR_DIS_CORE, 0);
f2c60e
+
f2c60e
+	usleep_range(1000, 2000);
f2c60e
+
f2c60e
+	if (!(netsec_readl(priv, NETSEC_REG_TOP_STATUS) &
f2c60e
+	      NETSEC_TOP_IRQ_REG_CODE_LOAD_END)) {
f2c60e
+		netif_err(priv, drv, priv->ndev, "microengine start failed\n");
f2c60e
+		return -ENXIO;
f2c60e
+	}
f2c60e
+	netsec_writel(priv, NETSEC_REG_TOP_STATUS,
f2c60e
+		      NETSEC_TOP_IRQ_REG_CODE_LOAD_END);
f2c60e
+
f2c60e
+	value = netsec_calc_pkt_ctrl_reg_param(&priv->param.pkt_ctrlaram);
f2c60e
+
f2c60e
+	if (priv->param.use_jumbo_pkt_flag)
f2c60e
+		value |= NETSEC_PKT_CTRL_REG_EN_JUMBO;
f2c60e
+
f2c60e
+	/* change to normal mode */
f2c60e
+	netsec_writel(priv, NETSEC_REG_DMA_MH_CTRL, MH_CTRL__MODE_TRANS);
f2c60e
+	netsec_writel(priv, NETSEC_REG_PKT_CTRL, value);
f2c60e
+
f2c60e
+	while ((netsec_readl(priv, NETSEC_REG_MODE_TRANS_COMP_STATUS) &
f2c60e
+		NETSEC_MODE_TRANS_COMP_IRQ_T2N) == 0)
f2c60e
+		cpu_relax();
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_ring_irq_clr(struct netsec_priv *priv,
f2c60e
+				unsigned int id, u32 value)
f2c60e
+{
f2c60e
+	netsec_writel(priv, desc_ring_irq_status_reg_addr[id],
f2c60e
+		      value & (NETSEC_IRQ_EMPTY | NETSEC_IRQ_ERR));
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_napi_tx_processing(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	netsec_ring_irq_clr(priv, NETSEC_RING_TX, NETSEC_IRQ_EMPTY);
f2c60e
+	netsec_clean_tx_desc_ring(priv);
f2c60e
+
f2c60e
+	if (netif_queue_stopped(priv->ndev) &&
f2c60e
+	    netsec_get_tx_avail_num(priv) >= NETSEC_NETDEV_TX_PKT_SCAT_NUM_MAX)
f2c60e
+		netif_wake_queue(priv->ndev);
f2c60e
+}
f2c60e
+
f2c60e
+int netsec_netdev_napi_poll(struct napi_struct *napi_p, int budget)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = container_of(napi_p, struct netsec_priv,
f2c60e
+						napi);
f2c60e
+	struct net_device *ndev = priv->ndev;
f2c60e
+	struct netsec_rx_pkt_info rx_info;
f2c60e
+	int ret, done = 0, rx_num = 0;
f2c60e
+	struct netsec_frag_info frag;
f2c60e
+	struct sk_buff *skb;
f2c60e
+	u16 len;
f2c60e
+
f2c60e
+	netsec_napi_tx_processing(priv);
f2c60e
+
f2c60e
+	while (done < budget) {
f2c60e
+		if (!rx_num) {
f2c60e
+			rx_num = netsec_get_rx_num(priv);
f2c60e
+			if (!rx_num)
f2c60e
+				break;
f2c60e
+		}
f2c60e
+		done++;
f2c60e
+		rx_num--;
f2c60e
+		ret = netsec_get_rx_pkt_data(priv, &rx_info, &frag, &len, &skb);
f2c60e
+		if (unlikely(ret == -ENOMEM)) {
f2c60e
+			netif_err(priv, drv, priv->ndev,
f2c60e
+				  "%s: rx fail %d\n", __func__, ret);
f2c60e
+			ndev->stats.rx_dropped++;
f2c60e
+			continue;
f2c60e
+		}
f2c60e
+		dma_unmap_single(priv->dev, frag.dma_addr, frag.len,
f2c60e
+				 DMA_FROM_DEVICE);
f2c60e
+		skb_put(skb, len);
f2c60e
+		skb->protocol = eth_type_trans(skb, priv->ndev);
f2c60e
+
f2c60e
+		if (priv->rx_cksum_offload_flag &&
f2c60e
+		    rx_info.rx_cksum_result == NETSEC_RX_CKSUM_OK)
f2c60e
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
f2c60e
+
f2c60e
+		if (napi_gro_receive(napi_p, skb) != GRO_DROP) {
f2c60e
+			ndev->stats.rx_packets++;
f2c60e
+			ndev->stats.rx_bytes += len;
f2c60e
+		}
f2c60e
+	}
f2c60e
+
f2c60e
+	if (done < budget && napi_complete_done(napi_p, done))
f2c60e
+		netsec_writel(priv, NETSEC_REG_INTEN_SET,
f2c60e
+			      NETSEC_IRQ_TX | NETSEC_IRQ_RX);
f2c60e
+	return done;
f2c60e
+}
f2c60e
+
f2c60e
+static netdev_tx_t netsec_netdev_start_xmit(struct sk_buff *skb,
f2c60e
+					    struct net_device *ndev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = netdev_priv(ndev);
f2c60e
+	struct netsec_tx_pkt_ctrl tx_ctrl = {};
f2c60e
+	u16 pend_tx, tso_seg_len = 0;
f2c60e
+	skb_frag_t *frag;
f2c60e
+	int count_frags;
f2c60e
+	int ret, i;
f2c60e
+
f2c60e
+	netsec_ring_irq_clr(priv, NETSEC_RING_TX, NETSEC_IRQ_EMPTY);
f2c60e
+
f2c60e
+	count_frags = skb_shinfo(skb)->nr_frags + 1;
f2c60e
+
f2c60e
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
f2c60e
+		if ((skb->protocol == htons(ETH_P_IP) &&
f2c60e
+		     ip_hdr(skb)->protocol == IPPROTO_TCP) ||
f2c60e
+		    (skb->protocol == htons(ETH_P_IPV6) &&
f2c60e
+		     ipv6_hdr(skb)->nexthdr == IPPROTO_TCP))
f2c60e
+			tx_ctrl.cksum_offload_flag = true;
f2c60e
+		else
f2c60e
+			skb_checksum_help(skb);
f2c60e
+	}
f2c60e
+
f2c60e
+	if (skb_is_gso(skb))
f2c60e
+		tso_seg_len = skb_shinfo(skb)->gso_size;
f2c60e
+
f2c60e
+	if (tso_seg_len > 0) {
f2c60e
+		if (skb->protocol == htons(ETH_P_IP)) {
f2c60e
+			ip_hdr(skb)->tot_len = 0;
f2c60e
+			tcp_hdr(skb)->check =
f2c60e
+				~tcp_v4_check(0, ip_hdr(skb)->saddr,
f2c60e
+					      ip_hdr(skb)->daddr, 0);
f2c60e
+		} else {
f2c60e
+			ipv6_hdr(skb)->payload_len = 0;
f2c60e
+			tcp_hdr(skb)->check =
f2c60e
+				~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
f2c60e
+						 &ipv6_hdr(skb)->daddr,
f2c60e
+						 0, IPPROTO_TCP, 0);
f2c60e
+		}
f2c60e
+
f2c60e
+		tx_ctrl.tcp_seg_offload_flag = true;
f2c60e
+		tx_ctrl.tcp_seg_len = tso_seg_len;
f2c60e
+	}
f2c60e
+
f2c60e
+	priv->tx_info[0].dma_addr = dma_map_single(priv->dev, skb->data,
f2c60e
+						   skb_headlen(skb),
f2c60e
+						   DMA_TO_DEVICE);
f2c60e
+	if (dma_mapping_error(priv->dev, priv->tx_info[0].dma_addr)) {
f2c60e
+		netif_err(priv, drv, priv->ndev,
f2c60e
+			  "%s: DMA mapping failed\n", __func__);
f2c60e
+		return NETDEV_TX_OK;
f2c60e
+	}
f2c60e
+	priv->tx_info[0].addr = skb->data;
f2c60e
+	priv->tx_info[0].len = skb_headlen(skb);
f2c60e
+
f2c60e
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
f2c60e
+		frag = &skb_shinfo(skb)->frags[i];
f2c60e
+		priv->tx_info[i + 1].dma_addr =
f2c60e
+			skb_frag_dma_map(priv->dev, frag, 0,
f2c60e
+					 skb_frag_size(frag), DMA_TO_DEVICE);
f2c60e
+		priv->tx_info[i + 1].addr = skb_frag_address(frag);
f2c60e
+		priv->tx_info[i + 1].len = frag->size;
f2c60e
+	}
f2c60e
+
f2c60e
+	netsec_mark_skb_type(skb, NETSEC_RING_TX);
f2c60e
+
f2c60e
+	ret = netsec_set_tx_pkt_data(priv, &tx_ctrl, count_frags,
f2c60e
+				     priv->tx_info, skb);
f2c60e
+	if (ret) {
f2c60e
+		netif_info(priv, drv, priv->ndev,
f2c60e
+			   "set tx pkt failed %d\n", ret);
f2c60e
+		for (i = 0; i < count_frags; i++)
f2c60e
+			dma_unmap_single(priv->dev, priv->tx_info[i].dma_addr,
f2c60e
+					 priv->tx_info[i].len, DMA_TO_DEVICE);
f2c60e
+		ndev->stats.tx_dropped++;
f2c60e
+
f2c60e
+		return NETDEV_TX_OK;
f2c60e
+	}
f2c60e
+
f2c60e
+	netdev_sent_queue(priv->ndev, skb->len);
f2c60e
+
f2c60e
+	spin_lock(&priv->tx_queue_lock);
f2c60e
+	pend_tx = netsec_get_tx_avail_num(priv);
f2c60e
+
f2c60e
+	if (pend_tx < NETSEC_NETDEV_TX_PKT_SCAT_NUM_MAX) {
f2c60e
+		netsec_ring_irq_enable(priv, NETSEC_RING_TX, NETSEC_IRQ_EMPTY);
f2c60e
+		netif_stop_queue(ndev);
f2c60e
+		goto err;
f2c60e
+	}
f2c60e
+	if (pend_tx <= DESC_NUM - 2) {
f2c60e
+		netsec_ring_irq_enable(priv, NETSEC_RING_TX, NETSEC_IRQ_EMPTY);
f2c60e
+		goto err;
f2c60e
+	}
f2c60e
+	netsec_ring_irq_disable(priv, NETSEC_RING_TX, NETSEC_IRQ_EMPTY);
f2c60e
+
f2c60e
+err:
f2c60e
+	spin_unlock(&priv->tx_queue_lock);
f2c60e
+
f2c60e
+	return NETDEV_TX_OK;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_netdev_set_features(struct net_device *ndev,
f2c60e
+				      netdev_features_t features)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = netdev_priv(ndev);
f2c60e
+
f2c60e
+	priv->rx_cksum_offload_flag = !!(features & NETIF_F_RXCSUM);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_phy_adjust_link(struct net_device *ndev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = netdev_priv(ndev);
f2c60e
+
f2c60e
+	if (priv->actual_link_speed == ndev->phydev->speed &&
f2c60e
+	    priv->actual_duplex == ndev->phydev->duplex)
f2c60e
+		return;
f2c60e
+
f2c60e
+	phy_print_status(ndev->phydev);
f2c60e
+
f2c60e
+	netsec_stop_gmac(priv);
f2c60e
+	netsec_start_gmac(priv);
f2c60e
+}
f2c60e
+
f2c60e
+static irqreturn_t netsec_irq_handler(int irq, void *dev_id)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = dev_id;
f2c60e
+	u32 status = netsec_readl(priv, NETSEC_REG_TOP_STATUS) &
f2c60e
+		     netsec_readl(priv, NETSEC_REG_TOP_INTEN);
f2c60e
+
f2c60e
+	if (!status)
f2c60e
+		return IRQ_NONE;
f2c60e
+
f2c60e
+	if (status & (NETSEC_IRQ_TX | NETSEC_IRQ_RX)) {
f2c60e
+		netsec_writel(priv, NETSEC_REG_INTEN_CLR,
f2c60e
+			      status & (NETSEC_IRQ_TX | NETSEC_IRQ_RX));
f2c60e
+		napi_schedule(&priv->napi);
f2c60e
+	}
f2c60e
+
f2c60e
+	return IRQ_HANDLED;
f2c60e
+}
f2c60e
+
f2c60e
+static void netsec_reset_hardware(struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	/* stop DMA engines */
f2c60e
+	if (!netsec_readl(priv, NETSEC_REG_ADDR_DIS_CORE)) {
f2c60e
+		netsec_writel(priv, NETSEC_REG_DMA_HM_CTRL,
f2c60e
+			      NETSEC_DMA_CTRL_REG_STOP);
f2c60e
+		netsec_writel(priv, NETSEC_REG_DMA_MH_CTRL,
f2c60e
+			      NETSEC_DMA_CTRL_REG_STOP);
f2c60e
+
f2c60e
+		while (netsec_readl(priv, NETSEC_REG_DMA_HM_CTRL) &
f2c60e
+		       NETSEC_DMA_CTRL_REG_STOP)
f2c60e
+			cpu_relax();
f2c60e
+
f2c60e
+		while (netsec_readl(priv, NETSEC_REG_DMA_MH_CTRL) &
f2c60e
+		       NETSEC_DMA_CTRL_REG_STOP)
f2c60e
+			cpu_relax();
f2c60e
+	}
f2c60e
+
f2c60e
+	netsec_writel(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RESET);
f2c60e
+	netsec_writel(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RUN);
f2c60e
+	netsec_writel(priv, NETSEC_REG_COM_INIT, NETSEC_COM_INIT_REG_ALL);
f2c60e
+
f2c60e
+	while (netsec_readl(priv, NETSEC_REG_COM_INIT) != 0)
f2c60e
+		cpu_relax();
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_netdev_open(struct net_device *ndev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = netdev_priv(ndev);
f2c60e
+	int ret, n;
f2c60e
+
f2c60e
+	pm_runtime_get_sync(priv->dev);
f2c60e
+
f2c60e
+	netsec_reset_hardware(priv);
f2c60e
+
f2c60e
+	for (n = 0; n <= NETSEC_RING_MAX; n++) {
f2c60e
+		ret = netsec_alloc_desc_ring(priv, n);
f2c60e
+		if (ret) {
f2c60e
+			netif_err(priv, probe, priv->ndev,
f2c60e
+				  "%s: alloc ring failed\n", __func__);
f2c60e
+			goto err;
f2c60e
+		}
f2c60e
+	}
f2c60e
+
f2c60e
+	ret = netsec_setup_rx_desc(priv, &priv->desc_ring[NETSEC_RING_RX]);
f2c60e
+	if (ret) {
f2c60e
+		netif_err(priv, probe, priv->ndev,
f2c60e
+			  "%s: fail setup ring\n", __func__);
f2c60e
+		goto err1;
f2c60e
+	}
f2c60e
+
f2c60e
+	ret = netsec_init_hardware(priv);
f2c60e
+	if (ret) {
f2c60e
+		netif_err(priv, probe, priv->ndev,
f2c60e
+			  "%s: netsec_init_hardware fail %d\n", __func__, ret);
f2c60e
+		goto err1;
f2c60e
+	}
f2c60e
+
f2c60e
+	ret = request_irq(priv->ndev->irq, netsec_irq_handler,
f2c60e
+			  IRQF_SHARED, "netsec", priv);
f2c60e
+	if (ret) {
f2c60e
+		netif_err(priv, drv, priv->ndev, "request_irq failed\n");
f2c60e
+		goto err1;
f2c60e
+	}
f2c60e
+	priv->irq_registered = true;
f2c60e
+
f2c60e
+	ret = netsec_clean_rx_desc_ring(priv);
f2c60e
+	if (ret) {
f2c60e
+		netif_err(priv, drv, priv->ndev,
f2c60e
+			  "%s: clean rx desc fail\n", __func__);
f2c60e
+		goto err2;
f2c60e
+	}
f2c60e
+
f2c60e
+	ret = netsec_clean_tx_desc_ring(priv);
f2c60e
+	if (ret) {
f2c60e
+		netif_err(priv, drv, priv->ndev,
f2c60e
+			  "%s: clean tx desc fail\n", __func__);
f2c60e
+		goto err2;
f2c60e
+	}
f2c60e
+
f2c60e
+	netsec_ring_irq_clr(priv, NETSEC_RING_TX, NETSEC_IRQ_EMPTY);
f2c60e
+
f2c60e
+	if (dev_of_node(priv->dev)) {
f2c60e
+		if (!of_phy_connect(priv->ndev, priv->phy_np,
f2c60e
+				    netsec_phy_adjust_link, 0,
f2c60e
+				    priv->phy_interface)) {
f2c60e
+			netif_err(priv, link, priv->ndev, "missing PHY\n");
f2c60e
+			goto err2;
f2c60e
+		}
f2c60e
+	} else {
f2c60e
+		ret = phy_connect_direct(priv->ndev, priv->phydev,
f2c60e
+					 netsec_phy_adjust_link,
f2c60e
+					 priv->phy_interface);
f2c60e
+		if (ret) {
f2c60e
+			netif_err(priv, link, priv->ndev,
f2c60e
+				  "phy_connect_direct() failed (%d)\n", ret);
f2c60e
+			goto err2;
f2c60e
+		}
f2c60e
+	}
f2c60e
+
f2c60e
+	phy_start_aneg(ndev->phydev);
f2c60e
+
f2c60e
+	netsec_ring_irq_disable(priv, NETSEC_RING_TX, NETSEC_IRQ_EMPTY);
f2c60e
+
f2c60e
+	netsec_start_gmac(priv);
f2c60e
+	napi_enable(&priv->napi);
f2c60e
+	netif_start_queue(ndev);
f2c60e
+
f2c60e
+	netsec_writel(priv, NETSEC_REG_INTEN_SET,
f2c60e
+		      NETSEC_IRQ_TX | NETSEC_IRQ_RX);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+
f2c60e
+err2:
f2c60e
+	pm_runtime_put_sync(priv->dev);
f2c60e
+	free_irq(priv->ndev->irq, priv);
f2c60e
+	priv->irq_registered = false;
f2c60e
+err1:
f2c60e
+	for (n = 0; n <= NETSEC_RING_MAX; n++)
f2c60e
+		netsec_free_desc_ring(priv, &priv->desc_ring[n]);
f2c60e
+err:
f2c60e
+	pm_runtime_put_sync(priv->dev);
f2c60e
+
f2c60e
+	return ret;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_netdev_stop(struct net_device *ndev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = netdev_priv(ndev);
f2c60e
+	int n;
f2c60e
+
f2c60e
+	phy_stop(ndev->phydev);
f2c60e
+	phy_disconnect(ndev->phydev);
f2c60e
+
f2c60e
+	netif_stop_queue(priv->ndev);
f2c60e
+	napi_disable(&priv->napi);
f2c60e
+
f2c60e
+	netsec_writel(priv, NETSEC_REG_INTEN_CLR, ~0);
f2c60e
+	netsec_stop_gmac(priv);
f2c60e
+
f2c60e
+	pm_runtime_put_sync(priv->dev);
f2c60e
+
f2c60e
+	for (n = 0; n <= NETSEC_RING_MAX; n++)
f2c60e
+		netsec_free_desc_ring(priv, &priv->desc_ring[n]);
f2c60e
+
f2c60e
+	free_irq(priv->ndev->irq, priv);
f2c60e
+	priv->irq_registered = false;
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+const struct net_device_ops netsec_netdev_ops = {
f2c60e
+	.ndo_open		= netsec_netdev_open,
f2c60e
+	.ndo_stop		= netsec_netdev_stop,
f2c60e
+	.ndo_start_xmit		= netsec_netdev_start_xmit,
f2c60e
+	.ndo_set_features	= netsec_netdev_set_features,
f2c60e
+	.ndo_set_mac_address    = eth_mac_addr,
f2c60e
+	.ndo_validate_addr	= eth_validate_addr,
f2c60e
+};
f2c60e
diff --git a/drivers/net/ethernet/socionext/netsec/netsec_platform.c b/drivers/net/ethernet/socionext/netsec/netsec_platform.c
f2c60e
new file mode 100644
f2c60e
index 0000000..624f6a7
f2c60e
--- /dev/null
f2c60e
+++ b/drivers/net/ethernet/socionext/netsec/netsec_platform.c
f2c60e
@@ -0,0 +1,435 @@
f2c60e
+/**
f2c60e
+ * drivers/net/ethernet/socionext/netsec/netsec_platform.c
f2c60e
+ *
f2c60e
+ *  Copyright (C) 2013-2014 Fujitsu Semiconductor Limited.
f2c60e
+ *  Copyright (C) 2014-2017 Linaro Ltd. All rights reserved.
f2c60e
+ *     Andy Green <andy.green@linaro.org>
f2c60e
+ *     Jassi Brar <jaswinder.singh@linaro.org>
f2c60e
+ *     Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
+ *
f2c60e
+ *  This program is free software; you can redistribute it and/or
f2c60e
+ *  modify it under the terms of the GNU General Public License
f2c60e
+ *  as published by the Free Software Foundation; either version 2
f2c60e
+ *  of the License, or (at your option) any later version.
f2c60e
+ */
f2c60e
+
f2c60e
+#include <linux/acpi.h>
f2c60e
+#include <linux/device.h>
f2c60e
+#include <linux/ctype.h>
f2c60e
+#include <linux/netdevice.h>
f2c60e
+#include <linux/types.h>
f2c60e
+#include <linux/bitops.h>
f2c60e
+#include <linux/dma-mapping.h>
f2c60e
+#include <linux/module.h>
f2c60e
+#include <linux/sizes.h>
f2c60e
+#include <linux/platform_device.h>
f2c60e
+#include <linux/clk.h>
f2c60e
+#include <linux/of.h>
f2c60e
+#include <linux/of_device.h>
f2c60e
+#include <linux/of_net.h>
f2c60e
+#include <linux/io.h>
f2c60e
+#include <linux/pm_runtime.h>
f2c60e
+
f2c60e
+#include "netsec.h"
f2c60e
+
f2c60e
+#define NETSEC_F_NETSEC_VER_MAJOR_NUM(x) (x & 0xffff0000)
f2c60e
+
f2c60e
+static int napi_weight = 64;
f2c60e
+static u16 pause_time = 256;
f2c60e
+
f2c60e
+static int netsec_of_probe(struct platform_device *pdev,
f2c60e
+			   struct netsec_priv *priv)
f2c60e
+{
f2c60e
+	int clk_count, ret, i;
f2c60e
+
f2c60e
+	priv->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
f2c60e
+	if (!priv->phy_np) {
f2c60e
+		dev_err(&pdev->dev, "missing required property 'phy-handle'\n");
f2c60e
+		return -EINVAL;
f2c60e
+	}
f2c60e
+
f2c60e
+	/* we require named clocks if there is more than one */
f2c60e
+	clk_count = of_property_count_strings(pdev->dev.of_node, "clock-names");
f2c60e
+	if (clk_count > 1) {
f2c60e
+		if (clk_count > ARRAY_SIZE(priv->clk)) {
f2c60e
+			dev_err(&pdev->dev, "too many clocks specified (%d)\n",
f2c60e
+				clk_count);
f2c60e
+			return -EINVAL;
f2c60e
+		}
f2c60e
+
f2c60e
+		for (i = 0; i < clk_count; i++) {
f2c60e
+			const char *clk_name;
f2c60e
+
f2c60e
+			ret = of_property_read_string_index(pdev->dev.of_node,
f2c60e
+							    "clock-names", i,
f2c60e
+							    &clk_name);
f2c60e
+			if (ret) {
f2c60e
+				dev_err(&pdev->dev,
f2c60e
+					"failed to parse 'clock-names'\n");
f2c60e
+				return ret;
f2c60e
+			}
f2c60e
+			priv->clk[i] = devm_clk_get(&pdev->dev, clk_name);
f2c60e
+			if (!strcmp(clk_name, "phy_refclk")) {
f2c60e
+				priv->freq = clk_get_rate(priv->clk[i]);
f2c60e
+				dev_dbg(&pdev->dev,
f2c60e
+					"found PHY refclock #%d freq %u\n",
f2c60e
+					i, priv->freq);
f2c60e
+			}
f2c60e
+		}
f2c60e
+		priv->clock_count = clk_count;
f2c60e
+	} else {
f2c60e
+		priv->clk[0] = devm_clk_get(&pdev->dev, NULL);
f2c60e
+		if (IS_ERR(priv->clk)) {
f2c60e
+			dev_err(&pdev->dev,
f2c60e
+				"missing required property 'clocks'\n");
f2c60e
+			return PTR_ERR(priv->clk);
f2c60e
+		}
f2c60e
+		priv->freq = clk_get_rate(priv->clk[0]);
f2c60e
+		priv->clock_count = 1;
f2c60e
+	}
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_acpi_probe(struct platform_device *pdev,
f2c60e
+			     struct netsec_priv *priv, u32 *phy_addr)
f2c60e
+{
f2c60e
+	int ret;
f2c60e
+
f2c60e
+	if (!IS_ENABLED(CONFIG_ACPI))
f2c60e
+		return -ENODEV;
f2c60e
+
f2c60e
+	ret = device_property_read_u32(&pdev->dev, "phy-channel", phy_addr);
f2c60e
+	if (ret) {
f2c60e
+		dev_err(&pdev->dev,
f2c60e
+			"missing required property 'phy-channel'\n");
f2c60e
+		return ret;
f2c60e
+	}
f2c60e
+
f2c60e
+	ret = device_property_read_u32(&pdev->dev,
f2c60e
+				       "socionext,phy-clock-frequency",
f2c60e
+				       &priv->freq);
f2c60e
+	if (ret)
f2c60e
+		dev_err(&pdev->dev,
f2c60e
+			"missing required property 'socionext,phy-clock-frequency'\n");
f2c60e
+	return ret;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_probe(struct platform_device *pdev)
f2c60e
+{
f2c60e
+	struct net_device *ndev;
f2c60e
+	struct netsec_priv *priv;
f2c60e
+	struct resource *mmio_res, *eeprom_res, *irq_res;
f2c60e
+	u8 *mac, macbuf[ETH_ALEN];
f2c60e
+	u32 hw_ver, phy_addr;
f2c60e
+	int ret;
f2c60e
+
f2c60e
+	mmio_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
f2c60e
+	if (!mmio_res) {
f2c60e
+		dev_err(&pdev->dev, "No MMIO resource found.\n");
f2c60e
+		return -ENODEV;
f2c60e
+	}
f2c60e
+
f2c60e
+	eeprom_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
f2c60e
+	if (!eeprom_res) {
f2c60e
+		dev_info(&pdev->dev, "No EEPROM resource found.\n");
f2c60e
+		return -ENODEV;
f2c60e
+	}
f2c60e
+
f2c60e
+	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
f2c60e
+	if (!irq_res) {
f2c60e
+		dev_err(&pdev->dev, "No IRQ resource found.\n");
f2c60e
+		return -ENODEV;
f2c60e
+	}
f2c60e
+
f2c60e
+	ndev = alloc_etherdev(sizeof(*priv));
f2c60e
+	if (!ndev)
f2c60e
+		return -ENOMEM;
f2c60e
+
f2c60e
+	priv = netdev_priv(ndev);
f2c60e
+	priv->ndev = ndev;
f2c60e
+	SET_NETDEV_DEV(ndev, &pdev->dev);
f2c60e
+	platform_set_drvdata(pdev, priv);
f2c60e
+	priv->dev = &pdev->dev;
f2c60e
+
f2c60e
+	priv->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV |
f2c60e
+			   NETIF_MSG_LINK | NETIF_MSG_PROBE;
f2c60e
+
f2c60e
+	ndev->irq = irq_res->start;
f2c60e
+
f2c60e
+	priv->phy_interface = device_get_phy_mode(&pdev->dev);
f2c60e
+	if (priv->phy_interface < 0) {
f2c60e
+		dev_err(&pdev->dev, "missing required property 'phy-mode'\n");
f2c60e
+		ret = -ENODEV;
f2c60e
+		goto free_ndev;
f2c60e
+	}
f2c60e
+
f2c60e
+	priv->ioaddr = devm_ioremap(&pdev->dev, mmio_res->start,
f2c60e
+				    resource_size(mmio_res));
f2c60e
+	if (!priv->ioaddr) {
f2c60e
+		dev_err(&pdev->dev, "devm_ioremap() failed\n");
f2c60e
+		ret = -ENXIO;
f2c60e
+		goto free_ndev;
f2c60e
+	}
f2c60e
+
f2c60e
+	priv->eeprom_base = devm_memremap(&pdev->dev, eeprom_res->start,
f2c60e
+					  resource_size(eeprom_res),
f2c60e
+					  MEMREMAP_WT);
f2c60e
+	if (!priv->eeprom_base) {
f2c60e
+		dev_err(&pdev->dev, "devm_memremap() failed for EEPROM\n");
f2c60e
+		ret = -ENXIO;
f2c60e
+		goto free_ndev;
f2c60e
+	}
f2c60e
+
f2c60e
+	mac = device_get_mac_address(&pdev->dev, macbuf, sizeof(macbuf));
f2c60e
+	if (mac)
f2c60e
+		ether_addr_copy(ndev->dev_addr, mac);
f2c60e
+
f2c60e
+	if (priv->eeprom_base &&
f2c60e
+	    (!mac || !is_valid_ether_addr(ndev->dev_addr))) {
f2c60e
+		const u8 *macp = priv->eeprom_base + NETSEC_EEPROM_MAC_ADDRESS;
f2c60e
+
f2c60e
+		ndev->dev_addr[0] = macp[3];
f2c60e
+		ndev->dev_addr[1] = macp[2];
f2c60e
+		ndev->dev_addr[2] = macp[1];
f2c60e
+		ndev->dev_addr[3] = macp[0];
f2c60e
+		ndev->dev_addr[4] = macp[7];
f2c60e
+		ndev->dev_addr[5] = macp[6];
f2c60e
+	}
f2c60e
+
f2c60e
+	if (!is_valid_ether_addr(ndev->dev_addr)) {
f2c60e
+		dev_warn(&pdev->dev, "No MAC address found, using random\n");
f2c60e
+		eth_hw_addr_random(ndev);
f2c60e
+	}
f2c60e
+
f2c60e
+	if (dev_of_node(&pdev->dev))
f2c60e
+		ret = netsec_of_probe(pdev, priv);
f2c60e
+	else
f2c60e
+		ret = netsec_acpi_probe(pdev, priv, &phy_addr);
f2c60e
+	if (ret)
f2c60e
+		goto free_ndev;
f2c60e
+
f2c60e
+	if (!priv->freq) {
f2c60e
+		dev_err(&pdev->dev, "missing PHY reference clock frequency\n");
f2c60e
+		ret = -ENODEV;
f2c60e
+		goto free_ndev;
f2c60e
+	}
f2c60e
+
f2c60e
+	/* disable by default */
f2c60e
+	priv->et_coalesce.rx_coalesce_usecs = 0;
f2c60e
+	priv->et_coalesce.rx_max_coalesced_frames = 1;
f2c60e
+	priv->et_coalesce.tx_coalesce_usecs = 0;
f2c60e
+	priv->et_coalesce.tx_max_coalesced_frames = 1;
f2c60e
+
f2c60e
+	ret = device_property_read_u32(&pdev->dev, "max-frame-size",
f2c60e
+				       &ndev->max_mtu);
f2c60e
+	if (ret < 0)
f2c60e
+		ndev->max_mtu = ETH_DATA_LEN;
f2c60e
+
f2c60e
+	priv->rx_pkt_buf_len = ndev->max_mtu + 22;
f2c60e
+	priv->param.use_jumbo_pkt_flag = (ndev->max_mtu > ETH_DATA_LEN);
f2c60e
+
f2c60e
+	pm_runtime_enable(&pdev->dev);
f2c60e
+	/* runtime_pm coverage just for probe, open/close also cover it */
f2c60e
+	pm_runtime_get_sync(&pdev->dev);
f2c60e
+
f2c60e
+	hw_ver = netsec_readl(priv, NETSEC_REG_F_TAIKI_VER);
f2c60e
+	/* this driver only supports F_TAIKI style NETSEC */
f2c60e
+	if (NETSEC_F_NETSEC_VER_MAJOR_NUM(hw_ver) !=
f2c60e
+	    NETSEC_F_NETSEC_VER_MAJOR_NUM(NETSEC_REG_NETSEC_VER_F_TAIKI)) {
f2c60e
+		ret = -ENODEV;
f2c60e
+		goto pm_disable;
f2c60e
+	}
f2c60e
+
f2c60e
+	dev_info(&pdev->dev, "hardware revision %d.%d\n",
f2c60e
+		 hw_ver >> 16, hw_ver & 0xffff);
f2c60e
+
f2c60e
+	priv->mac_mode.flow_start_th = NETSEC_FLOW_CONTROL_START_THRESHOLD;
f2c60e
+	priv->mac_mode.flow_stop_th = NETSEC_FLOW_CONTROL_STOP_THRESHOLD;
f2c60e
+	priv->mac_mode.pause_time = pause_time;
f2c60e
+	priv->mac_mode.flow_ctrl_enable_flag = false;
f2c60e
+
f2c60e
+	netif_napi_add(ndev, &priv->napi, netsec_netdev_napi_poll, napi_weight);
f2c60e
+
f2c60e
+	ndev->netdev_ops = &netsec_netdev_ops;
f2c60e
+	ndev->ethtool_ops = &netsec_ethtool_ops;
f2c60e
+	ndev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
f2c60e
+			 NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO |
f2c60e
+			 NETIF_F_HIGHDMA | NETIF_F_RXCSUM;
f2c60e
+	ndev->hw_features = ndev->features;
f2c60e
+
f2c60e
+	priv->rx_cksum_offload_flag = true;
f2c60e
+	spin_lock_init(&priv->tx_queue_lock);
f2c60e
+
f2c60e
+	ret = netsec_mii_register(priv);
f2c60e
+	if (ret) {
f2c60e
+		dev_err(&pdev->dev, "mii bus registration failed (%d)\n", ret);
f2c60e
+		goto pm_disable;
f2c60e
+	}
f2c60e
+
f2c60e
+	if (!dev_of_node(&pdev->dev)) { /* ACPI */
f2c60e
+		priv->phydev = get_phy_device(priv->mii_bus, phy_addr, false);
f2c60e
+		if (IS_ERR(priv->phydev)) {
f2c60e
+			dev_err(&pdev->dev, "get_phy_device() failed (%ld)\n",
f2c60e
+				PTR_ERR(priv->phydev));
f2c60e
+			ret = PTR_ERR(priv->phydev);
f2c60e
+			goto unregister_mii;
f2c60e
+		}
f2c60e
+
f2c60e
+		ret = phy_device_register(priv->phydev);
f2c60e
+		if (ret) {
f2c60e
+			dev_err(&pdev->dev,
f2c60e
+				"phy_device_register() failed (%d)\n", ret);
f2c60e
+			phy_device_free(priv->phydev);
f2c60e
+			goto unregister_mii;
f2c60e
+		}
f2c60e
+	}
f2c60e
+
f2c60e
+	/* disable all other interrupt sources */
f2c60e
+	netsec_writel(priv, NETSEC_REG_INTEN_CLR, ~0);
f2c60e
+	netsec_writel(priv, NETSEC_REG_INTEN_SET,
f2c60e
+		      NETSEC_IRQ_TX | NETSEC_IRQ_RX);
f2c60e
+
f2c60e
+	if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)))
f2c60e
+		dev_warn(&pdev->dev, "Failed to enable 64-bit DMA\n");
f2c60e
+
f2c60e
+	ret = register_netdev(ndev);
f2c60e
+	if (ret) {
f2c60e
+		netif_err(priv, probe, ndev, "register_netdev() failed\n");
f2c60e
+		goto unregister_mii;
f2c60e
+	}
f2c60e
+
f2c60e
+	pm_runtime_put_sync_suspend(&pdev->dev);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+
f2c60e
+unregister_mii:
f2c60e
+	netsec_mii_unregister(priv);
f2c60e
+
f2c60e
+pm_disable:
f2c60e
+	pm_runtime_put_sync_suspend(&pdev->dev);
f2c60e
+	pm_runtime_disable(&pdev->dev);
f2c60e
+
f2c60e
+free_ndev:
f2c60e
+	free_netdev(ndev);
f2c60e
+
f2c60e
+	dev_err(&pdev->dev, "init failed\n");
f2c60e
+
f2c60e
+	return ret;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_remove(struct platform_device *pdev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = platform_get_drvdata(pdev);
f2c60e
+
f2c60e
+	unregister_netdev(priv->ndev);
f2c60e
+	if (!dev_of_node(&pdev->dev)) { /* ACPI */
f2c60e
+		phy_device_remove(priv->phydev);
f2c60e
+		phy_device_free(priv->phydev);
f2c60e
+	}
f2c60e
+	netsec_mii_unregister(priv);
f2c60e
+	pm_runtime_disable(&pdev->dev);
f2c60e
+	free_netdev(priv->ndev);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+#ifdef CONFIG_PM
f2c60e
+static int netsec_runtime_suspend(struct device *dev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = dev_get_drvdata(dev);
f2c60e
+	int n;
f2c60e
+
f2c60e
+	netif_dbg(priv, drv, priv->ndev, "%s\n", __func__);
f2c60e
+
f2c60e
+	if (priv->irq_registered)
f2c60e
+		disable_irq(priv->ndev->irq);
f2c60e
+
f2c60e
+	netsec_writel(priv, NETSEC_REG_CLK_EN, 0);
f2c60e
+
f2c60e
+	for (n = priv->clock_count - 1; n >= 0; n--)
f2c60e
+		clk_disable_unprepare(priv->clk[n]);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_runtime_resume(struct device *dev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = dev_get_drvdata(dev);
f2c60e
+	int n;
f2c60e
+
f2c60e
+	netif_dbg(priv, drv, priv->ndev, "%s\n", __func__);
f2c60e
+
f2c60e
+	/* first let the clocks back on */
f2c60e
+
f2c60e
+	for (n = 0; n < priv->clock_count; n++)
f2c60e
+		clk_prepare_enable(priv->clk[n]);
f2c60e
+
f2c60e
+	netsec_writel(priv, NETSEC_REG_CLK_EN, NETSEC_CLK_EN_REG_DOM_D |
f2c60e
+					       NETSEC_CLK_EN_REG_DOM_C |
f2c60e
+					       NETSEC_CLK_EN_REG_DOM_G);
f2c60e
+
f2c60e
+	if (priv->irq_registered)
f2c60e
+		enable_irq(priv->ndev->irq);
f2c60e
+
f2c60e
+	return 0;
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_pm_suspend(struct device *dev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = dev_get_drvdata(dev);
f2c60e
+
f2c60e
+	netif_dbg(priv, drv, priv->ndev, "%s\n", __func__);
f2c60e
+
f2c60e
+	if (pm_runtime_status_suspended(dev))
f2c60e
+		return 0;
f2c60e
+
f2c60e
+	return netsec_runtime_suspend(dev);
f2c60e
+}
f2c60e
+
f2c60e
+static int netsec_pm_resume(struct device *dev)
f2c60e
+{
f2c60e
+	struct netsec_priv *priv = dev_get_drvdata(dev);
f2c60e
+
f2c60e
+	netif_dbg(priv, drv, priv->ndev, "%s\n", __func__);
f2c60e
+
f2c60e
+	if (pm_runtime_status_suspended(dev))
f2c60e
+		return 0;
f2c60e
+
f2c60e
+	return netsec_runtime_resume(dev);
f2c60e
+}
f2c60e
+#endif
f2c60e
+
f2c60e
+static const struct dev_pm_ops netsec_pm_ops = {
f2c60e
+	SET_SYSTEM_SLEEP_PM_OPS(netsec_pm_suspend, netsec_pm_resume)
f2c60e
+	SET_RUNTIME_PM_OPS(netsec_runtime_suspend, netsec_runtime_resume, NULL)
f2c60e
+};
f2c60e
+
f2c60e
+static const struct of_device_id netsec_dt_ids[] = {
f2c60e
+	{ .compatible = "socionext,synquacer-netsec" },
f2c60e
+	{ }
f2c60e
+};
f2c60e
+MODULE_DEVICE_TABLE(of, netsec_dt_ids);
f2c60e
+
f2c60e
+#ifdef CONFIG_ACPI
f2c60e
+static const struct acpi_device_id netsec_acpi_ids[] = {
f2c60e
+	{ "SCX0001" },
f2c60e
+	{ }
f2c60e
+};
f2c60e
+MODULE_DEVICE_TABLE(acpi, netsec_acpi_ids);
f2c60e
+#endif
f2c60e
+
f2c60e
+static struct platform_driver netsec_driver = {
f2c60e
+	.probe				= netsec_probe,
f2c60e
+	.remove				= netsec_remove,
f2c60e
+	.driver.name			= "netsec",
f2c60e
+	.driver.of_match_table		= netsec_dt_ids,
f2c60e
+	.driver.acpi_match_table	= ACPI_PTR(netsec_acpi_ids),
f2c60e
+	.driver.pm			= &netsec_pm_ops,
f2c60e
+};
f2c60e
+module_platform_driver(netsec_driver);
f2c60e
+
f2c60e
+MODULE_AUTHOR("Andy Green <andy.green@linaro.org>");
f2c60e
+MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
f2c60e
+MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
f2c60e
+MODULE_DESCRIPTION("NETSEC Ethernet driver");
f2c60e
+MODULE_LICENSE("GPL");
f2c60e
-- 
f2c60e
cgit v1.1
f2c60e
f2c60e
From 31a61532e7b859a797d36595ec5ab7485a9b24d5 Mon Sep 17 00:00:00 2001
f2c60e
From: Jassi Brar <jassisinghbrar@gmail.com>
f2c60e
Date: Wed, 30 Aug 2017 15:55:52 +0530
f2c60e
Subject: dt-bindings: net: Add DT bindings for Socionext Netsec
f2c60e
f2c60e
This patch adds documentation for Device-Tree bindings for the
f2c60e
Socionext NetSec Controller driver.
f2c60e
f2c60e
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
f2c60e
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
f2c60e
---
f2c60e
 .../devicetree/bindings/net/socionext-netsec.txt   | 43 ++++++++++++++++++++++
f2c60e
 1 file changed, 43 insertions(+)
f2c60e
 create mode 100644 Documentation/devicetree/bindings/net/socionext-netsec.txt
f2c60e
f2c60e
diff --git a/Documentation/devicetree/bindings/net/socionext-netsec.txt b/Documentation/devicetree/bindings/net/socionext-netsec.txt
f2c60e
new file mode 100644
f2c60e
index 0000000..4695969
f2c60e
--- /dev/null
f2c60e
+++ b/Documentation/devicetree/bindings/net/socionext-netsec.txt
f2c60e
@@ -0,0 +1,43 @@
f2c60e
+* Socionext NetSec Ethernet Controller IP
f2c60e
+
f2c60e
+Required properties:
f2c60e
+- compatible: Should be "socionext,synquacer-netsec"
f2c60e
+- reg: Address and length of the control register area, followed by the
f2c60e
+       address and length of the EEPROM holding the MAC address and
f2c60e
+       microengine firmware
f2c60e
+- interrupts: Should contain ethernet controller interrupt
f2c60e
+- clocks: phandle to the PHY reference clock, and any other clocks to be
f2c60e
+          switched by runtime_pm
f2c60e
+- clock-names: Required only if more than a single clock is listed in 'clocks'.
f2c60e
+               The PHY reference clock must be named 'phy_refclk'
f2c60e
+- phy-mode: See ethernet.txt file in the same directory
f2c60e
+- phy-handle: phandle to select child phy
f2c60e
+
f2c60e
+Optional properties: (See ethernet.txt file in the same directory)
f2c60e
+- local-mac-address
f2c60e
+- mac-address
f2c60e
+- max-speed
f2c60e
+- max-frame-size
f2c60e
+
f2c60e
+Required properties for the child phy:
f2c60e
+- reg: phy address
f2c60e
+
f2c60e
+Example:
f2c60e
+	eth0: netsec@522D0000 {
f2c60e
+		compatible = "socionext,synquacer-netsec";
f2c60e
+		reg = <0 0x522D0000 0x0 0x10000>, <0 0x10000000 0x0 0x10000>;
f2c60e
+		interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
f2c60e
+		clocks = <&clk_netsec>;
f2c60e
+		phy-mode = "rgmii";
f2c60e
+		max-speed = <1000>;
f2c60e
+		max-frame-size = <9000>;
f2c60e
+		phy-handle = <&ethphy0>;
f2c60e
+
f2c60e
+		#address-cells = <1>;
f2c60e
+		#size-cells = <0>;
f2c60e
+
f2c60e
+		ethphy0: ethernet-phy@1 {
f2c60e
+			compatible = "ethernet-phy-ieee802.3-c22";
f2c60e
+			reg = <1>;
f2c60e
+		};
f2c60e
+	};
f2c60e
-- 
f2c60e
cgit v1.1
f2c60e
f2c60e
From d2fc584f8237746a84e6ec8690d8884f148fc449 Mon Sep 17 00:00:00 2001
f2c60e
From: Peter Robinson <pbrobinson@gmail.com>
f2c60e
Date: Tue, 10 Oct 2017 11:35:51 +0100
f2c60e
Subject: [PATCH] add interrupt.h, sort alphabetically
f2c60e
f2c60e
Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
f2c60e
---
f2c60e
 drivers/net/ethernet/socionext/netsec/netsec_platform.c | 17 +++++++++--------
f2c60e
 1 file changed, 9 insertions(+), 8 deletions(-)
f2c60e
f2c60e
diff --git a/drivers/net/ethernet/socionext/netsec/netsec_platform.c b/drivers/net/ethernet/socionext/netsec/netsec_platform.c
f2c60e
index 624f6a7093f6..79072bae917d 100644
f2c60e
--- a/drivers/net/ethernet/socionext/netsec/netsec_platform.c
f2c60e
+++ b/drivers/net/ethernet/socionext/netsec/netsec_platform.c
f2c60e
@@ -14,21 +14,22 @@
f2c60e
  */
f2c60e
 
f2c60e
 #include <linux/acpi.h>
f2c60e
-#include <linux/device.h>
f2c60e
-#include <linux/ctype.h>
f2c60e
-#include <linux/netdevice.h>
f2c60e
-#include <linux/types.h>
f2c60e
 #include <linux/bitops.h>
f2c60e
+#include <linux/clk.h>
f2c60e
+#include <linux/ctype.h>
f2c60e
+#include <linux/device.h>
f2c60e
 #include <linux/dma-mapping.h>
f2c60e
+#include <linux/io.h>
f2c60e
+#include <linux/interrupt.h>
f2c60e
 #include <linux/module.h>
f2c60e
-#include <linux/sizes.h>
f2c60e
-#include <linux/platform_device.h>
f2c60e
-#include <linux/clk.h>
f2c60e
+#include <linux/netdevice.h>
f2c60e
 #include <linux/of.h>
f2c60e
 #include <linux/of_device.h>
f2c60e
 #include <linux/of_net.h>
f2c60e
-#include <linux/io.h>
f2c60e
+#include <linux/platform_device.h>
f2c60e
 #include <linux/pm_runtime.h>
f2c60e
+#include <linux/sizes.h>
f2c60e
+#include <linux/types.h>
f2c60e
 
f2c60e
 #include "netsec.h"
f2c60e
 
f2c60e
-- 
f2c60e
2.14.2
f2c60e