lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20170203181216.30214-5-antoine.tenart@free-electrons.com>
Date:   Fri,  3 Feb 2017 19:12:12 +0100
From:   Antoine Tenart <antoine.tenart@...e-electrons.com>
To:     netdev@...r.kernel.org, davem@...emloft.net,
        linux-arm-kernel@...ts.infradead.org
Cc:     Antoine Tenart <antoine.tenart@...e-electrons.com>,
        tsahee@...apurnalabs.com, rshitrit@...apurnalabs.com,
        saeed@...apurnalabs.com, barak@...apurnalabs.com,
        talz@...apurnalabs.com, thomas.petazzoni@...e-electrons.com,
        arnd@...db.de
Subject: [PATCH net-next 4/8] net: ethernet: add the Alpine Ethernet driver

This patch adds a driver for the so called Annapurna Labs unified
Ethernet adapter. These Ethernet adapters are exposed as integrated
PCIe endpoints.

The Ethernet unit is connected to the I/O Fabric and thus iofic and UDMA
blocks are exposed in PCIe BARs. This driver makes use of the Alpine
iofic and UDMA helpers.

Signed-off-by: Antoine Tenart <antoine.tenart@...e-electrons.com>
---
 drivers/net/ethernet/Kconfig                       |    1 +
 drivers/net/ethernet/Makefile                      |    1 +
 drivers/net/ethernet/annapurna/Kconfig             |   29 +
 drivers/net/ethernet/annapurna/Makefile            |    6 +
 drivers/net/ethernet/annapurna/al_eth.c            | 3062 ++++++++++++++++++++
 drivers/net/ethernet/annapurna/al_eth.h            |  282 ++
 drivers/net/ethernet/annapurna/al_hw_eth.h         | 1264 ++++++++
 drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h | 1088 +++++++
 .../net/ethernet/annapurna/al_hw_eth_mac_regs.h    |  727 +++++
 drivers/net/ethernet/annapurna/al_hw_eth_main.c    | 3050 +++++++++++++++++++
 .../ethernet/annapurna/al_hw_unit_adapter_regs.h   |   24 +
 11 files changed, 9534 insertions(+)
 create mode 100644 drivers/net/ethernet/annapurna/Kconfig
 create mode 100644 drivers/net/ethernet/annapurna/Makefile
 create mode 100644 drivers/net/ethernet/annapurna/al_eth.c
 create mode 100644 drivers/net/ethernet/annapurna/al_eth.h
 create mode 100644 drivers/net/ethernet/annapurna/al_hw_eth.h
 create mode 100644 drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h
 create mode 100644 drivers/net/ethernet/annapurna/al_hw_eth_mac_regs.h
 create mode 100644 drivers/net/ethernet/annapurna/al_hw_eth_main.c
 create mode 100644 drivers/net/ethernet/annapurna/al_hw_unit_adapter_regs.h

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 8c08f9deef92..0b43efaf1638 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -27,6 +27,7 @@ source "drivers/net/ethernet/alteon/Kconfig"
 source "drivers/net/ethernet/altera/Kconfig"
 source "drivers/net/ethernet/amazon/Kconfig"
 source "drivers/net/ethernet/amd/Kconfig"
+source "drivers/net/ethernet/annapurna/Kconfig"
 source "drivers/net/ethernet/apm/Kconfig"
 source "drivers/net/ethernet/apple/Kconfig"
 source "drivers/net/ethernet/aquantia/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 26dce5bf2c18..46cfeccdd3d8 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
 obj-$(CONFIG_ALTERA_TSE) += altera/
 obj-$(CONFIG_NET_VENDOR_AMAZON) += amazon/
 obj-$(CONFIG_NET_VENDOR_AMD) += amd/
+obj-$(CONFIG_NET_VENDOR_ALPINE) += annapurna/
 obj-$(CONFIG_NET_XGENE) += apm/
 obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
 obj-$(CONFIG_NET_VENDOR_AQUANTIA) += aquantia/
diff --git a/drivers/net/ethernet/annapurna/Kconfig b/drivers/net/ethernet/annapurna/Kconfig
new file mode 100644
index 000000000000..408e850024b2
--- /dev/null
+++ b/drivers/net/ethernet/annapurna/Kconfig
@@ -0,0 +1,29 @@
+#
+# Annapurna Labs driver configuration
+#
+
+config NET_VENDOR_ALPINE
+	bool "Annapurna Labs devices"
+
+if NET_VENDOR_ALPINE
+
+config NET_AL_ETH
+	tristate "Annapurna Labs unified 1G/10G Ethernet driver"
+	depends on PCI && INET
+	depends on ALPINE_UDMA
+	select PHYLIB
+	help
+	  This is the driver supports both standard and advanced Annapurna Labs
+	  1G and 10G Ethernet controllers.
+
+if NET_AL_ETH
+
+config NET_AL_ETH_NO_MSIX
+	bool "Disable MSI-X"
+	help
+	  Do not use the MSI-X feature in the Annapurna Labs unified
+	  1G/10G Ethernet driver.
+
+endif
+
+endif
diff --git a/drivers/net/ethernet/annapurna/Makefile b/drivers/net/ethernet/annapurna/Makefile
new file mode 100644
index 000000000000..fa361ecb2734
--- /dev/null
+++ b/drivers/net/ethernet/annapurna/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Annapurna network device drivers.
+#
+
+obj-$(CONFIG_NET_AL_ETH)	+= al_eth_drv.o
+al_eth_drv-objs			+= al_eth.o al_hw_eth_main.o
diff --git a/drivers/net/ethernet/annapurna/al_eth.c b/drivers/net/ethernet/annapurna/al_eth.c
new file mode 100644
index 000000000000..779a885de014
--- /dev/null
+++ b/drivers/net/ethernet/annapurna/al_eth.c
@@ -0,0 +1,3062 @@
+/*
+ * Copyright (C) 2017, Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/stringify.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/mdio.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/ethtool.h>
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <linux/cpu_rmap.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/checksum.h>
+#include <linux/prefetch.h>
+#include <linux/cache.h>
+#include <linux/i2c.h>
+#include <linux/soc/alpine/iofic.h>
+#include <linux/soc/alpine/al_hw_udma_iofic.h>
+#include <linux/soc/alpine/al_hw_udma_config.h>
+
+#include "al_hw_eth.h"
+#include "al_eth.h"
+
+#define DRV_MODULE_NAME		"al_eth"
+
+MODULE_AUTHOR("Saeed Bishara <saeed@...apurnaLabs.com>");
+MODULE_DESCRIPTION("AnnapurnaLabs unified 1GbE and 10GbE Ethernet driver");
+MODULE_LICENSE("GPL");
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (5 * HZ)
+
+/* Time in mSec to keep trying to read / write from MDIO in case of error */
+#define MDIO_TIMEOUT_MSEC	100
+
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+
+/* indexed by board_t */
+static struct {
+	char *name;
+	unsigned int bar; /* needed for NIC mode */
+} board_info[] = {
+	{
+		.name = "AnnapurnaLabs unified 1Gbe/10Gbe",
+	},
+	{
+		.name = "AnnapurnaLabs unified 1Gbe/10Gbe pcie NIC",
+		.bar = 5,
+	},
+};
+
+#define PCI_DEVICE_ID_AL_ETH		0x1
+#define PCI_DEVICE_ID_AL_ETH_ADVANCED	0x2
+#define PCI_DEVICE_ID_AL_ETH_NIC	0x3
+
+static const struct pci_device_id al_eth_pci_tbl[] = {
+	{ PCI_VENDOR_ID_ANNAPURNA_LABS, PCI_DEVICE_ID_AL_ETH,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, ALPINE_INTEGRATED },
+	{ PCI_VENDOR_ID_ANNAPURNA_LABS, PCI_DEVICE_ID_AL_ETH_ADVANCED,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, ALPINE_INTEGRATED },
+	{ PCI_VENDOR_ID_ANNAPURNA_LABS, PCI_DEVICE_ID_AL_ETH_NIC,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, ALPINE_NIC },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, al_eth_pci_tbl);
+
+/* MDIO */
+#define AL_ETH_MDIO_C45_DEV_MASK	0x1f0000
+#define AL_ETH_MDIO_C45_DEV_SHIFT	16
+#define AL_ETH_MDIO_C45_REG_MASK	0xffff
+
+static int al_mdio_read(struct mii_bus *bp, int mii_id, int reg)
+{
+	struct al_eth_adapter *adapter = bp->priv;
+	u16 value = 0;
+	int rc;
+	int timeout = MDIO_TIMEOUT_MSEC;
+
+	while (timeout > 0) {
+		if (reg & MII_ADDR_C45) {
+			netdev_dbg(adapter->netdev, "[c45]: dev %x reg %x val %x\n",
+				   ((reg & AL_ETH_MDIO_C45_DEV_MASK) >> AL_ETH_MDIO_C45_DEV_SHIFT),
+				   (reg & AL_ETH_MDIO_C45_REG_MASK), value);
+			rc = al_eth_mdio_read(&adapter->hw_adapter, adapter->phy_addr,
+				((reg & AL_ETH_MDIO_C45_DEV_MASK) >> AL_ETH_MDIO_C45_DEV_SHIFT),
+				(reg & AL_ETH_MDIO_C45_REG_MASK), &value);
+		} else {
+			rc = al_eth_mdio_read(&adapter->hw_adapter, adapter->phy_addr,
+					      MDIO_DEVAD_NONE, reg, &value);
+		}
+
+		if (rc == 0)
+			return value;
+
+		netdev_dbg(adapter->netdev,
+			   "mdio read failed. try again in 10 msec\n");
+
+		timeout -= 10;
+		msleep(10);
+	}
+
+	if (rc)
+		netdev_err(adapter->netdev, "MDIO read failed on timeout\n");
+
+	return value;
+}
+
+static int al_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val)
+{
+	struct al_eth_adapter *adapter = bp->priv;
+	int rc;
+	int timeout = MDIO_TIMEOUT_MSEC;
+
+	while (timeout > 0) {
+		if (reg & MII_ADDR_C45) {
+			netdev_dbg(adapter->netdev, "[c45]: device %x reg %x val %x\n",
+				   ((reg & AL_ETH_MDIO_C45_DEV_MASK) >> AL_ETH_MDIO_C45_DEV_SHIFT),
+				   (reg & AL_ETH_MDIO_C45_REG_MASK), val);
+			rc = al_eth_mdio_write(&adapter->hw_adapter,
+					       adapter->phy_addr,
+					       ((reg & AL_ETH_MDIO_C45_DEV_MASK) >> AL_ETH_MDIO_C45_DEV_SHIFT),
+					       (reg & AL_ETH_MDIO_C45_REG_MASK),
+					       val);
+		} else {
+			rc = al_eth_mdio_write(&adapter->hw_adapter,
+					       adapter->phy_addr,
+					       MDIO_DEVAD_NONE, reg, val);
+		}
+
+		if (rc == 0)
+			return 0;
+
+		netdev_err(adapter->netdev,
+			   "mdio write failed. try again in 10 msec\n");
+
+		timeout -= 10;
+		msleep(10);
+	}
+
+	if (rc)
+		netdev_err(adapter->netdev, "MDIO write failed on timeout\n");
+
+	return rc;
+}
+
+static int al_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+	struct mii_ioctl_data *mdio = if_mii(ifr);
+	struct phy_device *phydev;
+
+	netdev_info(adapter->netdev, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
+		    mdio->phy_id, mdio->reg_num, mdio->val_in);
+
+	if (adapter->mdio_bus) {
+		phydev = mdiobus_get_phy(adapter->mdio_bus, adapter->phy_addr);
+		if (phydev)
+			return phy_mii_ioctl(phydev, ifr, cmd);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int al_eth_flow_ctrl_config(struct al_eth_adapter *adapter);
+static u8 al_eth_flow_ctrl_mutual_cap_get(struct al_eth_adapter *adapter);
+static void al_eth_down(struct al_eth_adapter *adapter);
+static int al_eth_up(struct al_eth_adapter *adapter);
+
+static void al_eth_adjust_link(struct net_device *dev)
+{
+	struct al_eth_adapter *adapter = netdev_priv(dev);
+	struct al_eth_link_config *link_config = &adapter->link_config;
+	struct phy_device *phydev = adapter->phydev;
+	enum al_eth_mac_mode mac_mode_needed = AL_ETH_MAC_MODE_RGMII;
+	int new_state = 0;
+	bool force_1000_base_x = false;
+
+	if (phydev->link) {
+		if (phydev->duplex != link_config->active_duplex) {
+			new_state = 1;
+			link_config->active_duplex = phydev->duplex;
+		}
+
+		if (phydev->speed != link_config->active_speed) {
+			new_state = 1;
+			switch (phydev->speed) {
+			case SPEED_1000:
+			case SPEED_100:
+			case SPEED_10:
+				mac_mode_needed = (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII) ?
+					AL_ETH_MAC_MODE_RGMII : AL_ETH_MAC_MODE_SGMII;
+				break;
+			case SPEED_10000:
+			case SPEED_2500:
+				mac_mode_needed = AL_ETH_MAC_MODE_10GbE_Serial;
+				break;
+			default:
+				if (netif_msg_link(adapter))
+					netdev_warn(adapter->netdev,
+						    "Ack!  Speed (%d) is not 10/100/1000!",
+						    phydev->speed);
+				break;
+			}
+			link_config->active_speed = phydev->speed;
+		}
+
+		if (!link_config->old_link) {
+			new_state = 1;
+			link_config->old_link = 1;
+		}
+
+		if (new_state) {
+			int rc;
+
+			if (adapter->mac_mode != mac_mode_needed) {
+				al_eth_down(adapter);
+				adapter->mac_mode = mac_mode_needed;
+				if (link_config->active_speed <= 1000)
+					force_1000_base_x = true;
+				al_eth_up(adapter);
+			}
+
+			if (adapter->mac_mode != AL_ETH_MAC_MODE_10GbE_Serial) {
+				/* change the MAC link configuration */
+				rc = al_eth_mac_link_config(&adapter->hw_adapter,
+							    force_1000_base_x,
+							    link_config->autoneg,
+							    link_config->active_speed,
+							    link_config->active_duplex
+							    ? true : false);
+				if (rc)
+					netdev_warn(adapter->netdev,
+						    "Failed to config the mac with the new link settings!");
+			}
+		}
+
+		if (link_config->flow_ctrl_supported & AL_ETH_FLOW_CTRL_AUTONEG) {
+			u8 new_flow_ctrl =
+				al_eth_flow_ctrl_mutual_cap_get(adapter);
+
+			if (new_flow_ctrl != link_config->flow_ctrl_active) {
+				link_config->flow_ctrl_active = new_flow_ctrl;
+				al_eth_flow_ctrl_config(adapter);
+			}
+		}
+	} else if (adapter->link_config.old_link) {
+		new_state = 1;
+		link_config->old_link = 0;
+		link_config->active_duplex = DUPLEX_UNKNOWN;
+		link_config->active_speed = SPEED_UNKNOWN;
+	}
+
+	if (new_state && netif_msg_link(adapter))
+		phy_print_status(phydev);
+}
+
+static int al_eth_phy_init(struct al_eth_adapter *adapter)
+{
+	struct phy_device *phydev = mdiobus_get_phy(adapter->mdio_bus, adapter->phy_addr);
+
+	adapter->link_config.old_link = 0;
+	adapter->link_config.active_duplex = DUPLEX_UNKNOWN;
+	adapter->link_config.active_speed = SPEED_UNKNOWN;
+
+	/* Attach the MAC to the PHY. */
+	phydev = phy_connect(adapter->netdev, dev_name(&phydev->mdio.dev), al_eth_adjust_link,
+			     PHY_INTERFACE_MODE_RGMII);
+	if (IS_ERR(phydev)) {
+		netdev_err(adapter->netdev, "Could not attach to PHY\n");
+		return PTR_ERR(phydev);
+	}
+
+	netdev_info(adapter->netdev, "phy[%d]: device %s, driver %s\n",
+		    phydev->mdio.addr, dev_name(&phydev->mdio.dev),
+		    phydev->drv ? phydev->drv->name : "unknown");
+
+	/* Mask with MAC supported features. */
+	phydev->supported &= (PHY_GBIT_FEATURES |
+				SUPPORTED_Pause |
+				SUPPORTED_Asym_Pause);
+
+	phydev->advertising = phydev->supported;
+
+	netdev_info(adapter->netdev, "phy[%d]:supported %x adv %x\n",
+		    phydev->mdio.addr, phydev->supported, phydev->advertising);
+
+	adapter->phydev = phydev;
+	/* Bring the PHY up */
+	phy_start(adapter->phydev);
+
+	return 0;
+}
+
+/* al_eth_mdiobus_setup - initialize mdiobus and register to kernel */
+static int al_eth_mdiobus_setup(struct al_eth_adapter *adapter)
+{
+	struct phy_device *phydev;
+	int i;
+	int ret = 0;
+
+	adapter->mdio_bus = mdiobus_alloc();
+	if (!adapter->mdio_bus)
+		return -ENOMEM;
+
+	adapter->mdio_bus->name     = "al mdio bus";
+	snprintf(adapter->mdio_bus->id, MII_BUS_ID_SIZE, "%x",
+		 (adapter->pdev->bus->number << 8) | adapter->pdev->devfn);
+	adapter->mdio_bus->priv     = adapter;
+	adapter->mdio_bus->parent   = &adapter->pdev->dev;
+	adapter->mdio_bus->read     = &al_mdio_read;
+	adapter->mdio_bus->write    = &al_mdio_write;
+	adapter->mdio_bus->phy_mask = ~BIT(adapter->phy_addr);
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		adapter->mdio_bus->irq[i] = PHY_POLL;
+
+	if (adapter->phy_if != AL_ETH_BOARD_PHY_IF_XMDIO) {
+		i = mdiobus_register(adapter->mdio_bus);
+		if (i) {
+			netdev_warn(adapter->netdev,
+				    "mdiobus_reg failed (0x%x)\n", i);
+			mdiobus_free(adapter->mdio_bus);
+			return i;
+		}
+
+		phydev = mdiobus_get_phy(adapter->mdio_bus, adapter->phy_addr);
+	} else {
+		adapter->mdio_bus->phy_mask = 0xffffffff;
+		i = mdiobus_register(adapter->mdio_bus);
+		if (i) {
+			netdev_warn(adapter->netdev,
+				    "mdiobus_reg failed (0x%x)\n", i);
+			mdiobus_free(adapter->mdio_bus);
+			return i;
+		}
+
+		phydev = get_phy_device(adapter->mdio_bus, adapter->phy_addr,
+					true);
+		if (!phydev) {
+			netdev_err(adapter->netdev, "phy device get failed\n");
+			goto error;
+		}
+
+		ret = phy_device_register(phydev);
+		if (ret) {
+			netdev_err(adapter->netdev,
+				   "phy device register failed\n");
+			goto error;
+		}
+	}
+
+	if (!phydev || !phydev->drv)
+		goto error;
+
+	return 0;
+
+error:
+	netdev_warn(adapter->netdev, "No PHY devices\n");
+	mdiobus_unregister(adapter->mdio_bus);
+	mdiobus_free(adapter->mdio_bus);
+	return -ENODEV;
+}
+
+/* al_eth_mdiobus_teardown - mdiobus unregister */
+static void al_eth_mdiobus_teardown(struct al_eth_adapter *adapter)
+{
+	if (!adapter->mdio_bus)
+		return;
+
+	mdiobus_unregister(adapter->mdio_bus);
+	mdiobus_free(adapter->mdio_bus);
+	phy_device_free(adapter->phydev);
+}
+
+static void al_eth_tx_timeout(struct net_device *dev)
+{
+	struct al_eth_adapter *adapter = netdev_priv(dev);
+
+	if (netif_msg_tx_err(adapter))
+		netdev_err(dev, "transmit timed out!!!!\n");
+}
+
+static int al_eth_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct al_eth_adapter *adapter = netdev_priv(dev);
+	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+
+	if ((new_mtu < AL_ETH_MIN_FRAME_LEN) || (new_mtu > AL_ETH_MAX_MTU) ||
+	    (max_frame > AL_ETH_MAX_FRAME_LEN)) {
+		netdev_err(dev, "Invalid MTU setting\n");
+		return -EINVAL;
+	}
+
+	netdev_dbg(adapter->netdev, "set MTU to %d\n", new_mtu);
+	al_eth_rx_pkt_limit_config(&adapter->hw_adapter,
+				   AL_ETH_MIN_FRAME_LEN, max_frame);
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+int al_eth_read_pci_config(void *handle, int where, u32 *val)
+{
+	/* handle is a pointer to the pci_dev */
+	pci_read_config_dword((struct pci_dev *)handle, where, val);
+	return 0;
+}
+
+int al_eth_write_pci_config(void *handle, int where, u32 val)
+{
+	/* handle is a pointer to the pci_dev */
+	pci_write_config_dword((struct pci_dev *)handle, where, val);
+	return 0;
+}
+
+static int al_eth_function_reset(struct al_eth_adapter *adapter)
+{
+	struct al_eth_board_params params;
+	int rc;
+
+	/* save board params so we restore it after reset */
+	al_eth_board_params_get(adapter->mac_base, &params);
+	al_eth_mac_addr_read(adapter->ec_base, 0, adapter->mac_addr);
+	rc = al_eth_flr_rmn(&al_eth_read_pci_config,
+			    &al_eth_write_pci_config,
+			    adapter->pdev, adapter->mac_base);
+
+	/* restore params */
+	al_eth_board_params_set(adapter->mac_base, &params);
+	al_eth_mac_addr_store(adapter->ec_base, 0, adapter->mac_addr);
+	return rc;
+}
+
+static void al_eth_setup_int_mode(struct al_eth_adapter *adapter, int dis_msi);
+static int al_eth_board_params_init(struct al_eth_adapter *adapter)
+{
+		struct al_eth_board_params params;
+		int rc;
+
+		rc = al_eth_board_params_get(adapter->mac_base, &params);
+		if (rc) {
+			dev_err(&adapter->pdev->dev, "board info not available\n");
+			return -1;
+		}
+
+		adapter->phy_exist = !!params.phy_exist;
+		adapter->phy_addr = params.phy_mdio_addr;
+		adapter->an_en = params.autoneg_enable;
+		adapter->lt_en = params.kr_lt_enable;
+		adapter->sfp_detection_needed = params.sfp_plus_module_exist;
+		adapter->i2c_adapter_id = params.i2c_adapter_id;
+		adapter->ref_clk_freq = params.ref_clk_freq;
+		adapter->link_config.active_duplex = !params.half_duplex;
+		adapter->link_config.autoneg = (adapter->phy_exist) ?
+						(params.an_mode == AL_ETH_BOARD_AUTONEG_IN_BAND) :
+						(!params.an_disable);
+		adapter->link_config.force_1000_base_x = params.force_1000_base_x;
+		adapter->retimer.exist = params.retimer_exist;
+		adapter->retimer.type = params.retimer_type;
+		adapter->retimer.bus_id = params.retimer_bus_id;
+		adapter->retimer.i2c_addr = params.retimer_i2c_addr;
+		adapter->retimer.channel = params.retimer_channel;
+		adapter->retimer.tx_channel = params.retimer_tx_channel;
+		adapter->phy_if = params.phy_if;
+
+		switch (params.speed) {
+		default:
+			dev_warn(&adapter->pdev->dev,
+				 "invalid speed (%d)\n", params.speed);
+		case AL_ETH_BOARD_1G_SPEED_1000M:
+			adapter->link_config.active_speed = 1000;
+			break;
+		case AL_ETH_BOARD_1G_SPEED_100M:
+			adapter->link_config.active_speed = 100;
+			break;
+		case AL_ETH_BOARD_1G_SPEED_10M:
+			adapter->link_config.active_speed = 10;
+			break;
+		}
+
+		switch (params.mdio_freq) {
+		default:
+			dev_warn(&adapter->pdev->dev,
+				 "invalid mdio freq (%d)\n", params.mdio_freq);
+		case AL_ETH_BOARD_MDIO_FREQ_2_5_MHZ:
+			adapter->mdio_freq = 2500;
+			break;
+		case AL_ETH_BOARD_MDIO_FREQ_1_MHZ:
+			adapter->mdio_freq = 1000;
+			break;
+		}
+
+		switch (params.media_type) {
+		case AL_ETH_BOARD_MEDIA_TYPE_RGMII:
+			if (params.sfp_plus_module_exist)
+				/* Backward compatibility */
+				adapter->mac_mode = AL_ETH_MAC_MODE_SGMII;
+			else
+				adapter->mac_mode = AL_ETH_MAC_MODE_RGMII;
+
+			break;
+		case AL_ETH_BOARD_MEDIA_TYPE_SGMII:
+			adapter->mac_mode = AL_ETH_MAC_MODE_SGMII;
+			break;
+		case AL_ETH_BOARD_MEDIA_TYPE_SGMII_2_5G:
+			adapter->mac_mode = AL_ETH_MAC_MODE_SGMII_2_5G;
+			break;
+		case AL_ETH_BOARD_MEDIA_TYPE_10GBASE_SR:
+			adapter->mac_mode = AL_ETH_MAC_MODE_10GbE_Serial;
+			break;
+		case AL_ETH_BOARD_MEDIA_TYPE_AUTO_DETECT:
+			adapter->sfp_detection_needed = true;
+			break;
+		case AL_ETH_BOARD_MEDIA_TYPE_AUTO_DETECT_AUTO_SPEED:
+			adapter->sfp_detection_needed = true;
+			break;
+		case AL_ETH_BOARD_MEDIA_TYPE_NBASE_T:
+			adapter->mac_mode = AL_ETH_MAC_MODE_10GbE_Serial;
+			break;
+		case AL_ETH_BOARD_MEDIA_TYPE_25G:
+			adapter->sfp_detection_needed = true;
+			break;
+		default:
+			dev_err(&adapter->pdev->dev,
+				"unsupported media type %d\n",
+				params.media_type);
+			return -1;
+		}
+		dev_info(&adapter->pdev->dev,
+			 "Board info: phy exist %s. phy addr %d. mdio freq %u Khz. SFP connected %s. media %d\n",
+			params.phy_exist ? "Yes" : "No",
+			params.phy_mdio_addr,
+			adapter->mdio_freq,
+			params.sfp_plus_module_exist ? "Yes" : "No",
+			params.media_type);
+
+	al_eth_mac_addr_read(adapter->ec_base, 0, adapter->mac_addr);
+
+	return 0;
+}
+
+static inline void al_eth_flow_ctrl_init(struct al_eth_adapter *adapter)
+{
+	u8 default_flow_ctrl;
+
+	default_flow_ctrl = AL_ETH_FLOW_CTRL_TX_PAUSE;
+	default_flow_ctrl |= AL_ETH_FLOW_CTRL_RX_PAUSE;
+
+	adapter->link_config.flow_ctrl_supported = default_flow_ctrl;
+}
+
+static u8 al_eth_flow_ctrl_mutual_cap_get(struct al_eth_adapter *adapter)
+{
+	struct phy_device *phydev = mdiobus_get_phy(adapter->mdio_bus, adapter->phy_addr);
+	struct al_eth_link_config *link_config = &adapter->link_config;
+	u8 peer_flow_ctrl = AL_ETH_FLOW_CTRL_AUTONEG;
+	u8 new_flow_ctrl = AL_ETH_FLOW_CTRL_AUTONEG;
+
+	if (phydev->pause)
+		peer_flow_ctrl |= (AL_ETH_FLOW_CTRL_TX_PAUSE |
+				  AL_ETH_FLOW_CTRL_RX_PAUSE);
+	if (phydev->asym_pause)
+		peer_flow_ctrl ^= (AL_ETH_FLOW_CTRL_RX_PAUSE);
+
+	/*
+	 * in autoneg mode, supported flow ctrl is also
+	 * the current advertising
+	 */
+	if ((peer_flow_ctrl & AL_ETH_FLOW_CTRL_TX_PAUSE) ==
+	    (link_config->flow_ctrl_supported & AL_ETH_FLOW_CTRL_TX_PAUSE))
+		new_flow_ctrl |= AL_ETH_FLOW_CTRL_TX_PAUSE;
+	if ((peer_flow_ctrl & AL_ETH_FLOW_CTRL_RX_PAUSE) ==
+	    (link_config->flow_ctrl_supported & AL_ETH_FLOW_CTRL_RX_PAUSE))
+		new_flow_ctrl |= AL_ETH_FLOW_CTRL_RX_PAUSE;
+
+	return new_flow_ctrl;
+}
+
+static int al_eth_flow_ctrl_config(struct al_eth_adapter *adapter)
+{
+	struct al_eth_flow_control_params *flow_ctrl_params;
+	u8 active = adapter->link_config.flow_ctrl_active;
+	int i;
+
+	flow_ctrl_params = &adapter->flow_ctrl_params;
+
+	flow_ctrl_params->type = AL_ETH_FLOW_CONTROL_TYPE_LINK_PAUSE;
+	flow_ctrl_params->obay_enable =
+		((active & AL_ETH_FLOW_CTRL_RX_PAUSE) != 0);
+	flow_ctrl_params->gen_enable =
+		((active & AL_ETH_FLOW_CTRL_TX_PAUSE) != 0);
+
+	flow_ctrl_params->rx_fifo_th_high = AL_ETH_FLOW_CTRL_RX_FIFO_TH_HIGH;
+	flow_ctrl_params->rx_fifo_th_low = AL_ETH_FLOW_CTRL_RX_FIFO_TH_LOW;
+	flow_ctrl_params->quanta = AL_ETH_FLOW_CTRL_QUANTA;
+	flow_ctrl_params->quanta_th = AL_ETH_FLOW_CTRL_QUANTA_TH;
+
+	/* map priority to queue index, queue id = priority/2 */
+	for (i = 0; i < AL_ETH_FWD_PRIO_TABLE_NUM; i++)
+		flow_ctrl_params->prio_q_map[0][i] =  BIT((i >> 1));
+
+	al_eth_flow_control_config(&adapter->hw_adapter, flow_ctrl_params);
+
+	return 0;
+}
+
+static void al_eth_flow_ctrl_enable(struct al_eth_adapter *adapter)
+{
+	/*
+	 * change the active configuration to the default / force by ethtool
+	 * and call to configure
+	 */
+	adapter->link_config.flow_ctrl_active =
+				adapter->link_config.flow_ctrl_supported;
+
+	al_eth_flow_ctrl_config(adapter);
+}
+
+static void al_eth_flow_ctrl_disable(struct al_eth_adapter *adapter)
+{
+	adapter->link_config.flow_ctrl_active = 0;
+	al_eth_flow_ctrl_config(adapter);
+}
+
+static int al_eth_hw_init_adapter(struct al_eth_adapter *adapter)
+{
+	struct al_eth_adapter_params *params = &adapter->eth_hw_params;
+	int rc;
+
+	params->rev_id = adapter->rev_id;
+	params->udma_id = 0;
+	params->enable_rx_parser = 1; /* enable rx epe parser*/
+	params->udma_regs_base = adapter->udma_base; /* UDMA register base address */
+	params->ec_regs_base = adapter->ec_base; /* Ethernet controller registers base address */
+	params->mac_regs_base = adapter->mac_base; /* Ethernet MAC registers base address */
+	params->name = adapter->name;
+	params->netdev = adapter->netdev;
+
+	rc = al_eth_adapter_init(&adapter->hw_adapter, params);
+	if (rc)
+		dev_err(&adapter->pdev->dev, "Adapter init failed\n");
+
+	return rc;
+}
+
+static int al_eth_hw_init(struct al_eth_adapter *adapter)
+{
+	int rc;
+
+	rc = al_eth_hw_init_adapter(adapter);
+	if (rc)
+		return rc;
+
+	rc = al_eth_mac_config(&adapter->hw_adapter, adapter->mac_mode);
+	if (rc < 0) {
+		dev_err(&adapter->pdev->dev, "Failed to configure mac!\n");
+		return rc;
+	}
+
+	if ((adapter->mac_mode == AL_ETH_MAC_MODE_SGMII) ||
+	    (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII && adapter->phy_exist == false)) {
+		rc = al_eth_mac_link_config(&adapter->hw_adapter,
+					    adapter->link_config.force_1000_base_x,
+					    adapter->link_config.autoneg,
+					    adapter->link_config.active_speed,
+					    adapter->link_config.active_duplex);
+		if (rc) {
+			dev_err(&adapter->pdev->dev,
+				"Failed to configure link parameters!\n");
+			return rc;
+		}
+	}
+
+	rc = al_eth_mdio_config(&adapter->hw_adapter,
+				(adapter->phy_if == AL_ETH_BOARD_PHY_IF_XMDIO) ?
+				AL_ETH_MDIO_TYPE_CLAUSE_45 : AL_ETH_MDIO_TYPE_CLAUSE_22,
+				true,
+				adapter->ref_clk_freq, adapter->mdio_freq);
+	if (rc) {
+		dev_err(&adapter->pdev->dev, "failed at mdio config!\n");
+		return rc;
+	}
+
+	al_eth_flow_ctrl_init(adapter);
+
+	return rc;
+}
+
+static int al_eth_hw_stop(struct al_eth_adapter *adapter)
+{
+	al_eth_mac_stop(&adapter->hw_adapter);
+
+	/*
+	 * wait till pending rx packets written and UDMA becomes idle,
+	 * the MAC has ~10KB fifo, 10us should be enought time for the
+	 * UDMA to write to the memory
+	 */
+	udelay(10);
+
+	al_eth_adapter_stop(&adapter->hw_adapter);
+
+	adapter->flags |= AL_ETH_FLAG_RESET_REQUESTED;
+
+	/* disable flow ctrl to avoid pause packets*/
+	al_eth_flow_ctrl_disable(adapter);
+
+	return 0;
+}
+
+static int al_eth_udma_queue_enable(struct al_eth_adapter *adapter,
+				    enum al_udma_type type, int qid)
+{
+	int rc = 0;
+	char *name = (type == UDMA_TX) ? "Tx" : "Rx";
+	struct al_udma_q_params *q_params;
+
+	if (type == UDMA_TX)
+		q_params = &adapter->tx_ring[qid].q_params;
+	else
+		q_params = &adapter->rx_ring[qid].q_params;
+
+	rc = al_eth_queue_config(&adapter->hw_adapter, type, qid, q_params);
+	if (rc < 0) {
+		netdev_err(adapter->netdev, "config %s queue %u failed\n", name,
+			   qid);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int al_eth_udma_queues_enable_all(struct al_eth_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		al_eth_udma_queue_enable(adapter, UDMA_TX, i);
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		al_eth_udma_queue_enable(adapter, UDMA_RX, i);
+	return 0;
+}
+
+static void al_eth_init_rings(struct al_eth_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct al_eth_ring *ring = &adapter->tx_ring[i];
+
+		ring->dev = &adapter->pdev->dev;
+		ring->netdev = adapter->netdev;
+		al_udma_q_handle_get(&adapter->hw_adapter.tx_udma, i, &ring->dma_q);
+		ring->sw_count = adapter->tx_ring_count;
+		ring->hw_count = adapter->tx_descs_count;
+		ring->unmask_reg_offset = al_udma_iofic_unmask_offset_get(
+						(struct unit_regs *)adapter->udma_base,
+						AL_UDMA_IOFIC_LEVEL_PRIMARY,
+						AL_INT_GROUP_C);
+		ring->unmask_val = ~BIT(i);
+	}
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct al_eth_ring *ring = &adapter->rx_ring[i];
+
+		ring->dev = &adapter->pdev->dev;
+		ring->netdev = adapter->netdev;
+		ring->napi = &adapter->al_napi[AL_ETH_RXQ_NAPI_IDX(adapter, i)].napi;
+		al_udma_q_handle_get(&adapter->hw_adapter.rx_udma, i, &ring->dma_q);
+		ring->sw_count = adapter->rx_ring_count;
+		ring->hw_count = adapter->rx_descs_count;
+		ring->unmask_reg_offset = al_udma_iofic_unmask_offset_get(
+						(struct unit_regs *)adapter->udma_base,
+						AL_UDMA_IOFIC_LEVEL_PRIMARY,
+						AL_INT_GROUP_B);
+		ring->unmask_val = ~BIT(i);
+	}
+}
+
+/*
+ * al_eth_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: network interface device structure
+ * @qid: queue index
+ *
+ * Return 0 on success, negative on failure
+ */
+static int al_eth_setup_tx_resources(struct al_eth_adapter *adapter, int qid)
+{
+	struct al_eth_ring *tx_ring = &adapter->tx_ring[qid];
+	struct device *dev = tx_ring->dev;
+	struct al_udma_q_params *q_params = &tx_ring->q_params;
+	int size;
+
+	size = sizeof(struct al_eth_tx_buffer) * tx_ring->sw_count;
+
+	tx_ring->tx_buffer_info = kzalloc(size, GFP_KERNEL);
+	if (!tx_ring->tx_buffer_info)
+		return -ENOMEM;
+
+	tx_ring->descs_size = tx_ring->hw_count * sizeof(union al_udma_desc);
+	q_params->size = tx_ring->hw_count;
+
+	q_params->desc_base = dma_alloc_coherent(dev,
+					tx_ring->descs_size,
+					&q_params->desc_phy_base,
+					GFP_KERNEL);
+
+	if (!q_params->desc_base)
+		return -ENOMEM;
+
+	q_params->cdesc_base = NULL; /* completion queue not used for tx */
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+	return 0;
+}
+
+/*
+ * al_eth_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: network interface device structure
+ * @qid: queue index
+ *
+ * Free all transmit software resources
+ */
+static void al_eth_free_tx_resources(struct al_eth_adapter *adapter, int qid)
+{
+	struct al_eth_ring *tx_ring = &adapter->tx_ring[qid];
+	struct al_udma_q_params *q_params = &tx_ring->q_params;
+
+	kfree(tx_ring->tx_buffer_info);
+	tx_ring->tx_buffer_info = NULL;
+
+	/* if not set, then don't free */
+	if (!q_params->desc_base)
+		return;
+
+	dma_free_coherent(tx_ring->dev, tx_ring->descs_size,
+			  q_params->desc_base,
+			  q_params->desc_phy_base);
+
+	q_params->desc_base = NULL;
+}
+
+/*
+ * al_eth_setup_all_tx_resources - allocate all queues Tx resources
+ * @adapter: private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+static int al_eth_setup_all_tx_resources(struct al_eth_adapter *adapter)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		rc = al_eth_setup_tx_resources(adapter, i);
+		if (!rc)
+			continue;
+
+		netdev_err(adapter->netdev, "Allocation for Tx Queue %u failed\n", i);
+		goto err_setup_tx;
+	}
+
+	return 0;
+err_setup_tx:
+	/* rewind the index freeing the rings as we go */
+	while (i--)
+		al_eth_free_tx_resources(adapter, i);
+	return rc;
+}
+
+/*
+ * al_eth_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+static void al_eth_free_all_tx_resources(struct al_eth_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		if (adapter->tx_ring[i].q_params.desc_base)
+			al_eth_free_tx_resources(adapter, i);
+}
+
+/*
+ * al_eth_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: network interface device structure
+ * @qid: queue index
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int al_eth_setup_rx_resources(struct al_eth_adapter *adapter,
+				     unsigned int qid)
+{
+	struct al_eth_ring *rx_ring = &adapter->rx_ring[qid];
+	struct device *dev = rx_ring->dev;
+	struct al_udma_q_params *q_params = &rx_ring->q_params;
+	int size;
+
+	size = sizeof(struct al_eth_rx_buffer) * rx_ring->sw_count;
+
+	/* alloc extra element so in rx path we can always prefetch rx_info + 1*/
+	size += 1;
+
+	rx_ring->rx_buffer_info = kzalloc(size, GFP_KERNEL);
+	if (!rx_ring->rx_buffer_info)
+		return -ENOMEM;
+
+	rx_ring->descs_size = rx_ring->hw_count * sizeof(union al_udma_desc);
+	q_params->size = rx_ring->hw_count;
+
+	q_params->desc_base = dma_alloc_coherent(dev, rx_ring->descs_size,
+					&q_params->desc_phy_base,
+					GFP_KERNEL);
+	if (!q_params->desc_base)
+		return -ENOMEM;
+
+	rx_ring->cdescs_size = rx_ring->hw_count * AL_ETH_UDMA_RX_CDESC_SZ;
+	q_params->cdesc_base = dma_alloc_coherent(dev, rx_ring->cdescs_size,
+						  &q_params->cdesc_phy_base,
+						  GFP_KERNEL);
+	if (!q_params->cdesc_base)
+		return -ENOMEM;
+
+	/* Zero out the descriptor ring */
+	memset(q_params->cdesc_base, 0, rx_ring->cdescs_size);
+
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
+
+	return 0;
+}
+
+/*
+ * al_eth_free_rx_resources - Free Rx Resources
+ * @adapter: network interface device structure
+ * @qid: queue index
+ *
+ * Free all receive software resources
+ */
+static void al_eth_free_rx_resources(struct al_eth_adapter *adapter,
+				     unsigned int qid)
+{
+	struct al_eth_ring *rx_ring = &adapter->rx_ring[qid];
+	struct al_udma_q_params *q_params = &rx_ring->q_params;
+
+	kfree(rx_ring->rx_buffer_info);
+	rx_ring->rx_buffer_info = NULL;
+
+	/* if not set, then don't free */
+	if (!q_params->desc_base)
+		return;
+
+	dma_free_coherent(rx_ring->dev, rx_ring->descs_size,
+			  q_params->desc_base,
+			  q_params->desc_phy_base);
+
+	q_params->desc_base = NULL;
+
+	/* if not set, then don't free */
+	if (!q_params->cdesc_base)
+		return;
+
+	dma_free_coherent(rx_ring->dev, rx_ring->cdescs_size,
+			  q_params->cdesc_base,
+			  q_params->cdesc_phy_base);
+
+	q_params->cdesc_phy_base = 0;
+}
+
+/*
+ * al_eth_setup_all_rx_resources - allocate all queues Rx resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+static int al_eth_setup_all_rx_resources(struct al_eth_adapter *adapter)
+{
+	int i, rc;
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		rc = al_eth_setup_rx_resources(adapter, i);
+		if (!rc)
+			continue;
+
+		netdev_err(adapter->netdev, "Allocation for Rx Queue %u failed\n", i);
+		goto err_setup_rx;
+	}
+
+	return 0;
+
+err_setup_rx:
+	/* rewind the index freeing the rings as we go */
+	while (i--)
+		al_eth_free_rx_resources(adapter, i);
+	return rc;
+}
+
+/*
+ * al_eth_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ */
+static void al_eth_free_all_rx_resources(struct al_eth_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		if (adapter->rx_ring[i].q_params.desc_base)
+			al_eth_free_rx_resources(adapter, i);
+}
+
+static inline int al_eth_alloc_rx_frag(struct al_eth_adapter *adapter,
+				       struct al_eth_ring *rx_ring,
+				       struct al_eth_rx_buffer *rx_info)
+{
+	struct al_buf *al_buf;
+	dma_addr_t dma;
+	u8 *data;
+
+	/* if previous allocated frag is not used */
+	if (rx_info->data)
+		return 0;
+
+	rx_info->data_size = min_t(unsigned int,
+				  (rx_ring->netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN),
+				   adapter->max_rx_buff_alloc_size);
+
+	rx_info->data_size = max_t(unsigned int,
+				   rx_info->data_size,
+				   AL_ETH_DEFAULT_MIN_RX_BUFF_ALLOC_SIZE);
+
+	rx_info->frag_size = SKB_DATA_ALIGN(rx_info->data_size + AL_ETH_RX_OFFSET) +
+			     SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+	data = netdev_alloc_frag(rx_info->frag_size);
+
+	if (!data)
+		return -ENOMEM;
+
+	dma = dma_map_single(rx_ring->dev, data + AL_ETH_RX_OFFSET,
+			     rx_info->data_size, DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(rx_ring->dev, dma))) {
+		put_page(virt_to_head_page(data));
+		return -EIO;
+	}
+	netdev_dbg(rx_ring->netdev, "alloc frag %p, rx_info %p len %x skb size %x\n",
+		   data, rx_info, rx_info->data_size, rx_info->frag_size);
+
+	rx_info->data = data;
+
+	WARN_ON(!virt_addr_valid(rx_info->data));
+	rx_info->page = virt_to_head_page(rx_info->data);
+	rx_info->page_offset = (unsigned long)rx_info->data -
+			       (unsigned long)page_address(rx_info->page);
+	al_buf = &rx_info->al_buf;
+	dma_unmap_addr_set(al_buf, addr, dma);
+	dma_unmap_addr_set(rx_info, dma, dma);
+	dma_unmap_len_set(al_buf, len, rx_info->data_size);
+	return 0;
+}
+
+static void al_eth_free_rx_frag(struct al_eth_adapter *adapter,
+				struct al_eth_rx_buffer *rx_info)
+{
+	u8 *data = rx_info->data;
+	struct al_buf *al_buf = &rx_info->al_buf;
+
+	if (!data)
+		return;
+
+	dma_unmap_single(&adapter->pdev->dev, dma_unmap_addr(al_buf, addr),
+			 rx_info->data_size, DMA_FROM_DEVICE);
+
+	put_page(virt_to_head_page(data));
+	rx_info->data = NULL;
+}
+
+static int al_eth_refill_rx_bufs(struct al_eth_adapter *adapter,
+				 unsigned int qid, unsigned int num)
+{
+	struct al_eth_ring *rx_ring = &adapter->rx_ring[qid];
+	u16 next_to_use;
+	unsigned int i;
+
+	next_to_use = rx_ring->next_to_use;
+
+	for (i = 0; i < num; i++) {
+		int rc;
+		struct al_eth_rx_buffer *rx_info = &rx_ring->rx_buffer_info[next_to_use];
+
+		if (unlikely(al_eth_alloc_rx_frag(adapter, rx_ring, rx_info) < 0)) {
+			netdev_warn(adapter->netdev,
+				    "failed to alloc buffer for rx queue %d\n",
+				    qid);
+			break;
+		}
+		rc = al_eth_rx_buffer_add(&adapter->hw_adapter, rx_ring->dma_q,
+					  &rx_info->al_buf, AL_ETH_RX_FLAGS_INT,
+					  NULL);
+		if (unlikely(rc)) {
+			netdev_warn(adapter->netdev,
+				    "failed to add buffer for rx queue %d\n",
+				    qid);
+			break;
+		}
+		next_to_use = AL_ETH_RX_RING_IDX_NEXT(rx_ring, next_to_use);
+	}
+
+	if (unlikely(i < num)) {
+		netdev_warn(adapter->netdev,
+			    "refilled rx queue %d with %d pages only - available %d\n",
+			    qid, i, al_udma_available_get(rx_ring->dma_q));
+	}
+
+	if (likely(i))
+		al_eth_rx_buffer_action(&adapter->hw_adapter, rx_ring->dma_q,
+					i);
+
+	rx_ring->next_to_use = next_to_use;
+
+	return i;
+}
+
+static void al_eth_free_rx_bufs(struct al_eth_adapter *adapter, unsigned int qid)
+{
+	struct al_eth_ring *rx_ring = &adapter->rx_ring[qid];
+	unsigned int i;
+
+	for (i = 0; i < AL_ETH_DEFAULT_RX_DESCS; i++) {
+		struct al_eth_rx_buffer *rx_info = &rx_ring->rx_buffer_info[i];
+
+		if (rx_info->data)
+			al_eth_free_rx_frag(adapter, rx_info);
+	}
+}
+
+/*
+ * al_eth_refill_all_rx_bufs - allocate all queues Rx buffers
+ * @adapter: board private structure
+ */
+static void al_eth_refill_all_rx_bufs(struct al_eth_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		al_eth_refill_rx_bufs(adapter, i, AL_ETH_DEFAULT_RX_DESCS - 1);
+}
+
+static void al_eth_free_all_rx_bufs(struct al_eth_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		al_eth_free_rx_bufs(adapter, i);
+}
+
+/*
+ * al_eth_free_tx_bufs - Free Tx Buffers per Queue
+ * @adapter: network interface device structure
+ * @qid: queue index
+ */
+static void al_eth_free_tx_bufs(struct al_eth_adapter *adapter,
+				unsigned int qid)
+{
+	struct al_eth_ring *tx_ring = &adapter->tx_ring[qid];
+	unsigned int i;
+
+	for (i = 0; i < AL_ETH_DEFAULT_TX_SW_DESCS; i++) {
+		struct al_eth_tx_buffer *tx_info = &tx_ring->tx_buffer_info[i];
+		struct al_buf *al_buf;
+		int nr_frags;
+		int j;
+
+		if (!tx_info->skb)
+			continue;
+
+		netdev_warn(adapter->netdev,
+			    "free uncompleted tx skb qid %d idx 0x%x\n",
+			    qid, i);
+
+		al_buf = tx_info->hw_pkt.bufs;
+		dma_unmap_single(&adapter->pdev->dev,
+				 dma_unmap_addr(al_buf, addr),
+				 dma_unmap_len(al_buf, len), DMA_TO_DEVICE);
+
+		/* unmap remaining mapped pages */
+		nr_frags = tx_info->hw_pkt.num_of_bufs - 1;
+		for (j = 0; j < nr_frags; j++) {
+			al_buf++;
+			dma_unmap_page(&adapter->pdev->dev,
+				       dma_unmap_addr(al_buf, addr),
+				       dma_unmap_len(al_buf, len),
+				       DMA_TO_DEVICE);
+		}
+
+		dev_kfree_skb_any(tx_info->skb);
+	}
+	netdev_tx_reset_queue(netdev_get_tx_queue(adapter->netdev, qid));
+}
+
+static void al_eth_free_all_tx_bufs(struct al_eth_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		al_eth_free_tx_bufs(adapter, i);
+}
+
+/*
+ * al_eth_tx_poll - NAPI Tx polling callback
+ * @napi: structure for representing this polling device
+ * @budget: how many packets driver is allowed to clean
+ *
+ * This function is used for legacy and MSI, NAPI mode
+ */
+static int al_eth_tx_poll(struct napi_struct *napi, int budget)
+{
+	struct al_eth_napi *al_napi = container_of(napi, struct al_eth_napi, napi);
+	struct al_eth_adapter *adapter = al_napi->adapter;
+	unsigned int qid = al_napi->qid;
+	struct al_eth_ring *tx_ring = &adapter->tx_ring[qid];
+	struct netdev_queue *txq;
+	unsigned int tx_bytes = 0;
+	unsigned int total_done;
+	u16 next_to_clean;
+	int tx_pkt = 0;
+
+	total_done = al_eth_comp_tx_get(&adapter->hw_adapter, tx_ring->dma_q);
+	dev_dbg(&adapter->pdev->dev, "tx_poll: q %d total completed descs %x\n",
+		qid, total_done);
+	next_to_clean = tx_ring->next_to_clean;
+	txq = netdev_get_tx_queue(adapter->netdev, qid);
+
+	while (total_done) {
+		struct al_eth_tx_buffer *tx_info;
+		struct sk_buff *skb;
+		struct al_buf *al_buf;
+		int i, nr_frags;
+
+		tx_info = &tx_ring->tx_buffer_info[next_to_clean];
+		/* stop if not all descriptors of the packet are completed */
+		if (tx_info->tx_descs > total_done)
+			break;
+
+		skb = tx_info->skb;
+
+		/* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
+		prefetch(&skb->end);
+
+		tx_info->skb = NULL;
+		al_buf = tx_info->hw_pkt.bufs;
+		dma_unmap_single(tx_ring->dev, dma_unmap_addr(al_buf, addr),
+				 dma_unmap_len(al_buf, len), DMA_TO_DEVICE);
+
+		/* unmap remaining mapped pages */
+		nr_frags = tx_info->hw_pkt.num_of_bufs - 1;
+		for (i = 0; i < nr_frags; i++) {
+			al_buf++;
+			dma_unmap_page(tx_ring->dev, dma_unmap_addr(al_buf, addr),
+				       dma_unmap_len(al_buf, len), DMA_TO_DEVICE);
+		}
+
+		tx_bytes += skb->len;
+		dev_dbg(&adapter->pdev->dev, "tx_poll: q %d skb %p completed\n",
+			qid, skb);
+		dev_kfree_skb(skb);
+		tx_pkt++;
+		total_done -= tx_info->tx_descs;
+		next_to_clean = AL_ETH_TX_RING_IDX_NEXT(tx_ring, next_to_clean);
+	}
+
+	netdev_tx_completed_queue(txq, tx_pkt, tx_bytes);
+
+	tx_ring->next_to_clean = next_to_clean;
+
+	dev_dbg(&adapter->pdev->dev, "tx_poll: q %d done next to clean %x\n",
+		qid, next_to_clean);
+
+	/*
+	 * We need to make the rings circular update visible to
+	 * al_eth_start_xmit() before checking for netif_queue_stopped().
+	 */
+	smp_mb();
+
+	if (unlikely(netif_tx_queue_stopped(txq) &&
+		     (al_udma_available_get(tx_ring->dma_q) > AL_ETH_TX_WAKEUP_THRESH))) {
+		__netif_tx_lock(txq, smp_processor_id());
+		if (netif_tx_queue_stopped(txq) &&
+		    (al_udma_available_get(tx_ring->dma_q) > AL_ETH_TX_WAKEUP_THRESH))
+			netif_tx_wake_queue(txq);
+		__netif_tx_unlock(txq);
+	}
+
+	/* all work done, exit the polling mode */
+	napi_complete(napi);
+	writel_relaxed(tx_ring->unmask_val, tx_ring->unmask_reg_offset);
+	return 0;
+}
+
+static struct sk_buff *al_eth_rx_skb(struct al_eth_adapter *adapter,
+				     struct al_eth_ring *rx_ring,
+				     struct al_eth_pkt *hw_pkt,
+				     unsigned int descs, u16 *next_to_clean)
+{
+	struct sk_buff *skb = NULL;
+	struct al_eth_rx_buffer *rx_info =
+		&rx_ring->rx_buffer_info[*next_to_clean];
+	unsigned int len;
+	unsigned int buf = 0;
+
+	len = hw_pkt->bufs[0].len;
+	netdev_dbg(adapter->netdev, "rx_info %p data %p\n", rx_info,
+		   rx_info->data);
+
+	prefetch(rx_info->data + AL_ETH_RX_OFFSET);
+
+	if (len <= adapter->rx_copybreak) {
+		netdev_dbg(adapter->netdev, "rx small packet. len %d\n", len);
+
+		skb = netdev_alloc_skb_ip_align(adapter->netdev,
+						adapter->rx_copybreak);
+		if (unlikely(!skb))
+			return NULL;
+
+		pci_dma_sync_single_for_cpu(adapter->pdev, rx_info->dma,
+					    len, DMA_FROM_DEVICE);
+		skb_copy_to_linear_data(skb, rx_info->data + AL_ETH_RX_OFFSET,
+					len);
+		pci_dma_sync_single_for_device(adapter->pdev, rx_info->dma, len,
+					       DMA_FROM_DEVICE);
+		skb_put(skb, len);
+		skb->protocol = eth_type_trans(skb, adapter->netdev);
+		*next_to_clean = AL_ETH_RX_RING_IDX_NEXT(rx_ring,
+							 *next_to_clean);
+		return skb;
+	}
+
+	skb = napi_get_frags(rx_ring->napi);
+	if (unlikely(!skb))
+		return NULL;
+
+	skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+			   rx_info->page,
+			   rx_info->page_offset + AL_ETH_RX_OFFSET, len);
+
+	skb->len += len;
+	skb->data_len += len;
+	skb->truesize += len;
+
+	netdev_dbg(adapter->netdev, "rx skb updated. len %d. data_len %d\n",
+		   skb->len, skb->data_len);
+
+	rx_info->data = NULL;
+	*next_to_clean = AL_ETH_RX_RING_IDX_NEXT(rx_ring, *next_to_clean);
+
+	while (--descs) {
+		rx_info = &rx_ring->rx_buffer_info[*next_to_clean];
+		len = hw_pkt->bufs[++buf].len;
+
+		dma_unmap_single(rx_ring->dev, dma_unmap_addr(rx_info, dma),
+				 rx_info->data_size, DMA_FROM_DEVICE);
+
+		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+				rx_info->page,
+				rx_info->page_offset + AL_ETH_RX_OFFSET,
+				len, rx_info->data_size);
+
+		netdev_dbg(adapter->netdev, "rx skb updated. len %d. "
+			   "data_len %d\n", skb->len, skb->data_len);
+
+		rx_info->data = NULL;
+
+		*next_to_clean = AL_ETH_RX_RING_IDX_NEXT(rx_ring, *next_to_clean);
+	}
+
+	return skb;
+}
+
+/*
+ * al_eth_rx_checksum - indicate in skb if hw indicated a good cksum
+ * @adapter: structure containing adapter specific data
+ * @hw_pkt: HAL structure for the packet
+ * @skb: skb currently being received and modified
+ */
+static inline void al_eth_rx_checksum(struct al_eth_adapter *adapter,
+				      struct al_eth_pkt *hw_pkt,
+				      struct sk_buff *skb)
+{
+	skb_checksum_none_assert(skb);
+
+	/* Rx csum disabled */
+	if (unlikely(!(adapter->netdev->features & NETIF_F_RXCSUM))) {
+		netdev_dbg(adapter->netdev, "hw checksum offloading disabled\n");
+		return;
+	}
+
+	/* if IP and error */
+	if (unlikely((hw_pkt->l3_proto_idx == AL_ETH_PROTO_ID_IPv4) &&
+		     (hw_pkt->flags & AL_ETH_RX_FLAGS_L3_CSUM_ERR))) {
+		/* ipv4 checksum error */
+		netdev_dbg(adapter->netdev, "rx ipv4 header checksum error\n");
+		return;
+	}
+
+	/* if TCP/UDP */
+	if (likely((hw_pkt->l4_proto_idx == AL_ETH_PROTO_ID_TCP) ||
+		   (hw_pkt->l4_proto_idx == AL_ETH_PROTO_ID_UDP))) {
+		if (unlikely(hw_pkt->flags & AL_ETH_RX_FLAGS_L4_CSUM_ERR)) {
+			/* TCP/UDP checksum error */
+			netdev_dbg(adapter->netdev, "rx L4 checksum error\n");
+			return;
+		}
+
+		netdev_dbg(adapter->netdev, "rx checksum correct\n");
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	}
+}
+
+/*
+ * al_eth_rx_poll - NAPI Rx polling callback
+ * @napi: structure for representing this polling device
+ * @budget: how many packets driver is allowed to clean
+ *
+ * This function is used for legacy and MSI, NAPI mode
+ */
+static int al_eth_rx_poll(struct napi_struct *napi, int budget)
+{
+	struct al_eth_napi *al_napi = container_of(napi, struct al_eth_napi, napi);
+	struct al_eth_adapter *adapter = al_napi->adapter;
+	unsigned int qid = al_napi->qid;
+	struct al_eth_ring *rx_ring = &adapter->rx_ring[qid];
+	struct al_eth_pkt *hw_pkt = &rx_ring->hw_pkt;
+	int work_done = 0;
+	u16 next_to_clean = rx_ring->next_to_clean;
+	int refill_required;
+	int refill_actual;
+
+	do {
+		struct sk_buff *skb;
+		unsigned int descs;
+
+		descs = al_eth_pkt_rx(&adapter->hw_adapter, rx_ring->dma_q,
+				      hw_pkt);
+		if (unlikely(descs == 0))
+			break;
+
+		netdev_dbg(adapter->netdev, "rx_poll: q %d flags %x. l3 proto %d l4 proto %d\n",
+			   qid, hw_pkt->flags, hw_pkt->l3_proto_idx,
+			   hw_pkt->l4_proto_idx);
+
+		/* ignore if detected dma or eth controller errors */
+		if (hw_pkt->flags & (AL_ETH_RX_ERROR | AL_UDMA_CDESC_ERROR)) {
+			netdev_dbg(adapter->netdev, "receive packet with error. flags = 0x%x\n", hw_pkt->flags);
+			next_to_clean = AL_ETH_RX_RING_IDX_ADD(rx_ring, next_to_clean, descs);
+			goto next;
+		}
+
+		/* allocate skb and fill it */
+		skb = al_eth_rx_skb(adapter, rx_ring, hw_pkt, descs,
+				    &next_to_clean);
+
+		/* exit if we failed to retrieve a buffer */
+		if (unlikely(!skb)) {
+			next_to_clean = AL_ETH_RX_RING_IDX_ADD(rx_ring,
+							       next_to_clean,
+							       descs);
+			break;
+		}
+
+		al_eth_rx_checksum(adapter, hw_pkt, skb);
+		if (likely(adapter->netdev->features & NETIF_F_RXHASH)) {
+			enum pkt_hash_types type = PKT_HASH_TYPE_L3;
+
+			if (likely((hw_pkt->l4_proto_idx == AL_ETH_PROTO_ID_TCP) ||
+				   (hw_pkt->l4_proto_idx == AL_ETH_PROTO_ID_UDP)))
+				type = PKT_HASH_TYPE_L4;
+			skb_set_hash(skb, hw_pkt->rxhash, type);
+		}
+
+		skb_record_rx_queue(skb, qid);
+
+		if (hw_pkt->bufs[0].len <= adapter->rx_copybreak)
+			napi_gro_receive(napi, skb);
+		else
+			napi_gro_frags(napi);
+
+next:
+		budget--;
+		work_done++;
+	} while (likely(budget));
+
+	rx_ring->next_to_clean = next_to_clean;
+
+	refill_required = al_udma_available_get(rx_ring->dma_q);
+	refill_actual = al_eth_refill_rx_bufs(adapter, qid, refill_required);
+
+	if (unlikely(refill_actual < refill_required)) {
+		netdev_warn(adapter->netdev, "Rescheduling rx queue %d\n", qid);
+		napi_reschedule(napi);
+	} else if (budget > 0) {
+		dev_dbg(&adapter->pdev->dev, "rx_poll: q %d done next to clean %x\n",
+			qid, next_to_clean);
+		napi_complete(napi);
+		writel_relaxed(rx_ring->unmask_val,
+			       rx_ring->unmask_reg_offset);
+	}
+
+	return work_done;
+}
+
+/*
+ * al_eth_intr_intx_all - Legacy Interrupt Handler for all interrupts
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ */
+static irqreturn_t al_eth_intr_intx_all(int irq, void *data)
+{
+	struct al_eth_adapter *adapter = data;
+	struct unit_regs __iomem *udma_base = (struct unit_regs __iomem *)adapter->udma_base;
+	void __iomem *regs_base = udma_base;
+	u32 reg;
+
+	reg = al_udma_iofic_read_cause(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY,
+				       AL_INT_GROUP_A);
+	if (reg & AL_INT_GROUP_A_GROUP_B_SUM) {
+		u32 cause_b = al_udma_iofic_read_cause(regs_base,
+							    AL_UDMA_IOFIC_LEVEL_PRIMARY,
+							    AL_INT_GROUP_B);
+		int qid;
+
+		for (qid = 0; qid < adapter->num_rx_queues; qid++) {
+			if (cause_b & BIT(qid)) {
+				/* mask */
+				al_udma_iofic_mask(
+					(struct unit_regs __iomem *)adapter->udma_base,
+					AL_UDMA_IOFIC_LEVEL_PRIMARY,
+					AL_INT_GROUP_B, BIT(qid));
+
+				napi_schedule(&adapter->al_napi[AL_ETH_RXQ_NAPI_IDX(adapter, qid)].napi);
+			}
+		}
+	}
+	if (reg & AL_INT_GROUP_A_GROUP_C_SUM) {
+		u32 cause_c = al_udma_iofic_read_cause(regs_base,
+						       AL_UDMA_IOFIC_LEVEL_PRIMARY,
+						       AL_INT_GROUP_C);
+		int qid;
+
+		for (qid = 0; qid < adapter->num_tx_queues; qid++) {
+			if (cause_c & BIT(qid)) {
+				/* mask */
+				al_udma_iofic_mask(
+					(struct unit_regs __iomem *)adapter->udma_base,
+					AL_UDMA_IOFIC_LEVEL_PRIMARY,
+					AL_INT_GROUP_C, BIT(qid));
+
+				napi_schedule(&adapter->al_napi[AL_ETH_TXQ_NAPI_IDX(adapter, qid)].napi);
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * al_eth_intr_msix_mgmt - MSIX Interrupt Handler for Management interrupts
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ */
+static irqreturn_t al_eth_intr_msix_mgmt(int irq, void *data)
+{
+	/* TODO: check for dma errors */
+	return IRQ_HANDLED;
+}
+
+/*
+ * al_eth_intr_msix_tx - MSIX Interrupt Handler for Tx
+ * @irq: interrupt number
+ * @data: pointer to a network interface private napi device structure
+ */
+static irqreturn_t al_eth_intr_msix_tx(int irq, void *data)
+{
+	struct al_eth_napi *al_napi = data;
+
+	napi_schedule(&al_napi->napi);
+	return IRQ_HANDLED;
+}
+
+/*
+ * al_eth_intr_msix_rx - MSIX Interrupt Handler for Rx
+ * @irq: interrupt number
+ * @data: pointer to a network interface private napi device structure
+ */
+static irqreturn_t al_eth_intr_msix_rx(int irq, void *data)
+{
+	struct al_eth_napi *al_napi = data;
+
+	napi_schedule(&al_napi->napi);
+	return IRQ_HANDLED;
+}
+
+static void al_eth_enable_msix(struct al_eth_adapter *adapter)
+{
+	int i, msix_vecs, rc;
+
+	msix_vecs = 1 + adapter->num_rx_queues + adapter->num_tx_queues;
+
+	dev_dbg(&adapter->pdev->dev, "Try to enable MSIX, vectors %d\n",
+		msix_vecs);
+
+	adapter->msix_entries = kcalloc(msix_vecs,
+					sizeof(struct msix_entry), GFP_KERNEL);
+
+	if (!adapter->msix_entries) {
+		dev_err(&adapter->pdev->dev,
+			"failed to allocate msix_entries, vectors %d\n",
+			msix_vecs);
+		return;
+	}
+
+	/* management vector (GROUP_A) */
+	adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].entry = 2;
+	adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].vector = 0;
+
+	/* rx queues start */
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		int	irq_idx = AL_ETH_RXQ_IRQ_IDX(adapter, i);
+
+		adapter->msix_entries[irq_idx].entry = 3 + i;
+		adapter->msix_entries[irq_idx].vector = 0;
+	}
+	/* tx queues start */
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		int	irq_idx = AL_ETH_TXQ_IRQ_IDX(adapter, i);
+
+		adapter->msix_entries[irq_idx].entry = 3 + AL_ETH_MAX_HW_QUEUES + i;
+		adapter->msix_entries[irq_idx].vector = 0;
+	}
+
+	rc = pci_enable_msix(adapter->pdev, adapter->msix_entries,
+			     msix_vecs);
+	if (rc) {
+		dev_dbg(&adapter->pdev->dev, "failed to enable MSIX, vectors %d\n",
+			msix_vecs);
+		adapter->msix_vecs = 0;
+		kfree(adapter->msix_entries);
+		adapter->msix_entries = NULL;
+		return;
+	}
+	dev_dbg(&adapter->pdev->dev, "enable MSIX, vectors %d\n", msix_vecs);
+
+	adapter->msix_vecs = msix_vecs;
+	adapter->flags |= AL_ETH_FLAG_MSIX_ENABLED;
+}
+
+static void al_eth_setup_int_mode(struct al_eth_adapter *adapter, int dis_msi)
+{
+	int i;
+	unsigned int cpu;
+
+	if (!dis_msi)
+		al_eth_enable_msix(adapter);
+
+	if (adapter->msix_vecs == 1) {
+		netdev_err(adapter->netdev, "single MSI-X mode unsupported\n");
+		return;
+	}
+
+	adapter->irq_vecs = max(1, adapter->msix_vecs);
+
+	/* single INTX mode */
+	if (adapter->msix_vecs == 0) {
+		snprintf(adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].name,
+			 AL_ETH_IRQNAME_SIZE, "al-eth-intx-all@pci:%s",
+			 pci_name(adapter->pdev));
+		adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].handler = al_eth_intr_intx_all;
+		adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector = adapter->pdev->irq;
+		adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].data = adapter;
+
+		cpu = cpumask_first(cpu_online_mask);
+		cpumask_set_cpu(cpu, &adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].affinity_hint_mask);
+
+		return;
+	}
+
+	/* MSI-X per queue */
+	snprintf(adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].name, AL_ETH_IRQNAME_SIZE,
+		"al-eth-msix-mgmt@pci:%s", pci_name(adapter->pdev));
+	adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].handler = al_eth_intr_msix_mgmt;
+
+	adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].data = adapter;
+	adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector = adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].vector;
+	cpu = cpumask_first(cpu_online_mask);
+	cpumask_set_cpu(cpu, &adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].affinity_hint_mask);
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		int irq_idx = AL_ETH_RXQ_IRQ_IDX(adapter, i);
+		int napi_idx = AL_ETH_RXQ_NAPI_IDX(adapter, i);
+
+		snprintf(adapter->irq_tbl[irq_idx].name, AL_ETH_IRQNAME_SIZE,
+			 "al-eth-rx-comp-%d@pci:%s", i,
+			 pci_name(adapter->pdev));
+		adapter->irq_tbl[irq_idx].handler = al_eth_intr_msix_rx;
+		adapter->irq_tbl[irq_idx].data = &adapter->al_napi[napi_idx];
+		adapter->irq_tbl[irq_idx].vector = adapter->msix_entries[irq_idx].vector;
+
+		cpu = cpumask_next((i % num_online_cpus() - 1), cpu_online_mask);
+		cpumask_set_cpu(cpu, &adapter->irq_tbl[irq_idx].affinity_hint_mask);
+	}
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		int irq_idx = AL_ETH_TXQ_IRQ_IDX(adapter, i);
+		int napi_idx = AL_ETH_TXQ_NAPI_IDX(adapter, i);
+
+		snprintf(adapter->irq_tbl[irq_idx].name,
+			 AL_ETH_IRQNAME_SIZE, "al-eth-tx-comp-%d@pci:%s", i,
+			 pci_name(adapter->pdev));
+		adapter->irq_tbl[irq_idx].handler = al_eth_intr_msix_tx;
+		adapter->irq_tbl[irq_idx].data = &adapter->al_napi[napi_idx];
+		adapter->irq_tbl[irq_idx].vector = adapter->msix_entries[irq_idx].vector;
+
+		cpu = cpumask_next((i % num_online_cpus() - 1), cpu_online_mask);
+		cpumask_set_cpu(cpu, &adapter->irq_tbl[irq_idx].affinity_hint_mask);
+	}
+}
+
+static int al_eth_configure_int_mode(struct al_eth_adapter *adapter)
+{
+	enum al_iofic_mode int_mode;
+	u32 m2s_errors_disable = 0x480;
+	u32 m2s_aborts_disable = 0x480;
+	u32 s2m_errors_disable = 0x1e0;
+	u32 s2m_aborts_disable = 0x1e0;
+
+	/* single INTX mode */
+	if (adapter->msix_vecs == 0) {
+		int_mode = AL_IOFIC_MODE_LEGACY;
+	} else if (adapter->msix_vecs > 1) {
+		int_mode = AL_IOFIC_MODE_MSIX_PER_Q;
+	} else {
+		netdev_err(adapter->netdev,
+			   "udma doesn't support single MSI-X mode.\n");
+		return -EIO;
+	}
+
+	m2s_errors_disable |= 0x3f << 25;
+	s2m_aborts_disable |= 0x3f << 25;
+
+	if (al_udma_iofic_config((struct unit_regs __iomem *)adapter->udma_base,
+				 int_mode, m2s_errors_disable,
+				 m2s_aborts_disable, s2m_errors_disable,
+				 s2m_aborts_disable)) {
+		netdev_err(adapter->netdev, "al_udma_unit_int_config failed!.\n");
+		return -EIO;
+	}
+	adapter->int_mode = int_mode;
+	netdev_info(adapter->netdev, "using %s interrupt mode",
+		    int_mode == AL_IOFIC_MODE_LEGACY ? "INTx" :
+		    int_mode == AL_IOFIC_MODE_MSIX_PER_Q ?
+		    "MSI-X per Queue" : "Unknown");
+	/* set interrupt moderation resolution to 15us */
+	al_iofic_moder_res_config(&((struct unit_regs *)(adapter->udma_base))->gen.interrupt_regs.main_iofic,
+				  AL_INT_GROUP_B, 15);
+	al_iofic_moder_res_config(&((struct unit_regs *)(adapter->udma_base))->gen.interrupt_regs.main_iofic,
+				  AL_INT_GROUP_C, 15);
+
+	return 0;
+}
+
+static int al_eth_request_irq(struct al_eth_adapter *adapter)
+{
+	unsigned long flags;
+	struct al_eth_irq *irq;
+	int rc = 0, i;
+
+	if (adapter->flags & AL_ETH_FLAG_MSIX_ENABLED)
+		flags = 0;
+	else
+		flags = IRQF_SHARED;
+
+	for (i = 0; i < adapter->irq_vecs; i++) {
+		irq = &adapter->irq_tbl[i];
+		rc = request_irq(irq->vector, irq->handler, flags, irq->name,
+				 irq->data);
+		if (rc) {
+			netdev_err(adapter->netdev,
+				   "failed to request irq. index %d rc %d\n",
+				   i, rc);
+			break;
+		}
+		irq->requested = 1;
+
+		netdev_dbg(adapter->netdev,
+			   "set affinity hint of irq. index %d to 0x%lx (irq vector: %d)\n",
+			   i, irq->affinity_hint_mask.bits[0], irq->vector);
+
+		irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);
+	}
+	return rc;
+}
+
+static void __al_eth_free_irq(struct al_eth_adapter *adapter)
+{
+	struct al_eth_irq *irq;
+	int i;
+
+	for (i = 0; i < adapter->irq_vecs; i++) {
+		irq = &adapter->irq_tbl[i];
+		if (irq->requested) {
+			irq_set_affinity_hint(irq->vector, NULL);
+			free_irq(irq->vector, irq->data);
+		}
+		irq->requested = 0;
+	}
+}
+
+static void al_eth_free_irq(struct al_eth_adapter *adapter)
+{
+	__al_eth_free_irq(adapter);
+	if (adapter->flags & AL_ETH_FLAG_MSIX_ENABLED)
+		pci_disable_msix(adapter->pdev);
+
+	adapter->flags &= ~AL_ETH_FLAG_MSIX_ENABLED;
+
+	kfree(adapter->msix_entries);
+	adapter->msix_entries = NULL;
+}
+
+static void al_eth_interrupts_mask(struct al_eth_adapter *adapter);
+
+static void al_eth_disable_int_sync(struct al_eth_adapter *adapter)
+{
+	int i;
+
+	if (!netif_running(adapter->netdev))
+		return;
+
+	/* mask hw interrupts */
+	al_eth_interrupts_mask(adapter);
+
+	for (i = 0; i < adapter->irq_vecs; i++)
+		synchronize_irq(adapter->irq_tbl[i].vector);
+}
+
+static void al_eth_interrupts_unmask(struct al_eth_adapter *adapter)
+{
+	u32 group_a_mask = AL_INT_GROUP_A_GROUP_D_SUM; /* enable group D summery */
+	u32 group_b_mask = BIT(adapter->num_rx_queues) - 1;/* bit per Rx q*/
+	u32 group_c_mask = BIT(adapter->num_tx_queues) - 1;/* bit per Tx q*/
+	u32 group_d_mask = 3 << 8;
+	struct unit_regs __iomem *regs_base = (struct unit_regs __iomem *)adapter->udma_base;
+
+	if (adapter->int_mode == AL_IOFIC_MODE_LEGACY)
+		group_a_mask |= AL_INT_GROUP_A_GROUP_B_SUM |
+				AL_INT_GROUP_A_GROUP_C_SUM |
+				AL_INT_GROUP_A_GROUP_D_SUM;
+
+	al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY,
+			     AL_INT_GROUP_A, group_a_mask);
+	al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY,
+			     AL_INT_GROUP_B, group_b_mask);
+	al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY,
+			     AL_INT_GROUP_C, group_c_mask);
+	al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY,
+			     AL_INT_GROUP_D, group_d_mask);
+}
+
+static void al_eth_interrupts_mask(struct al_eth_adapter *adapter)
+{
+	struct unit_regs __iomem *regs_base = (struct unit_regs __iomem *)adapter->udma_base;
+
+	/* mask all interrupts */
+	al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY,
+			   AL_INT_GROUP_A, 0x7);
+	al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY,
+			   AL_INT_GROUP_B, 0xF);
+	al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY,
+			   AL_INT_GROUP_C, 0xF);
+	al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY,
+			   AL_INT_GROUP_D, 0xFFFFFFFF);
+}
+
+static void al_eth_del_napi(struct al_eth_adapter *adapter)
+{
+	int i;
+	int napi_num = adapter->num_rx_queues + adapter->num_tx_queues;
+
+	for (i = 0; i < napi_num; i++)
+		netif_napi_del(&adapter->al_napi[i].napi);
+}
+
+static void al_eth_init_napi(struct al_eth_adapter *adapter)
+{
+	int i;
+	int napi_num = adapter->num_rx_queues + adapter->num_tx_queues;
+
+	for (i = 0; i < napi_num; i++) {
+		struct al_eth_napi *napi = &adapter->al_napi[i];
+		int (*poll)(struct napi_struct *, int);
+
+		if (i < adapter->num_rx_queues) {
+			poll = al_eth_rx_poll;
+			napi->qid = i;
+		} else {
+			poll = al_eth_tx_poll;
+			napi->qid = i - adapter->num_rx_queues;
+		}
+		netif_napi_add(adapter->netdev, &adapter->al_napi[i].napi,
+			       poll, 64);
+		napi->adapter = adapter;
+	}
+}
+
+static void al_eth_napi_disable_all(struct al_eth_adapter *adapter)
+{
+	int i;
+	int napi_num = adapter->num_rx_queues + adapter->num_tx_queues;
+
+	for (i = 0; i < napi_num; i++)
+		napi_disable(&adapter->al_napi[i].napi);
+}
+
+static void al_eth_napi_enable_all(struct al_eth_adapter *adapter)
+
+{
+	int i;
+	int napi_num = adapter->num_rx_queues + adapter->num_tx_queues;
+
+	for (i = 0; i < napi_num; i++)
+		napi_enable(&adapter->al_napi[i].napi);
+}
+
+/*
+ * init FSM, no tunneling supported yet, if packet is tcp/udp over ipv4/ipv6,
+ * use 4 tuple hash
+ */
+static void al_eth_fsm_table_init(struct al_eth_adapter *adapter)
+{
+	u32 val;
+	int i;
+
+	for (i = 0; i < AL_ETH_RX_FSM_TABLE_SIZE; i++) {
+		switch (AL_ETH_FSM_ENTRY_OUTER(i)) {
+		case AL_ETH_FSM_ENTRY_IPV4_TCP:
+		case AL_ETH_FSM_ENTRY_IPV4_UDP:
+		case AL_ETH_FSM_ENTRY_IPV6_TCP:
+		case AL_ETH_FSM_ENTRY_IPV6_UDP:
+			val = AL_ETH_FSM_DATA_OUTER_4_TUPLE | AL_ETH_FSM_DATA_HASH_SEL;
+			break;
+		case AL_ETH_FSM_ENTRY_IPV6_NO_UDP_TCP:
+		case AL_ETH_FSM_ENTRY_IPV4_NO_UDP_TCP:
+			val = AL_ETH_FSM_DATA_OUTER_2_TUPLE | AL_ETH_FSM_DATA_HASH_SEL;
+			break;
+		default:
+			val = (0 << AL_ETH_FSM_DATA_DEFAULT_Q_SHIFT |
+			      (BIT(0) << AL_ETH_FSM_DATA_DEFAULT_UDMA_SHIFT));
+		}
+		al_eth_fsm_table_set(&adapter->hw_adapter, i, val);
+	}
+}
+
+#define AL_ETH_MAC_TABLE_UNICAST_IDX_BASE	0
+#define AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT	4
+#define AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX	(AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + \
+						 AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT)
+
+#define AL_ETH_MAC_TABLE_DROP_IDX		(AL_ETH_FWD_MAC_NUM - 1)
+#define AL_ETH_MAC_TABLE_BROADCAST_IDX		(AL_ETH_MAC_TABLE_DROP_IDX - 1)
+
+#define MAC_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ADDR(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
+
+static void al_eth_mac_table_unicast_add(struct al_eth_adapter *adapter, u8 idx,
+					 u8 *addr, u8 udma_mask)
+{
+	struct al_eth_fwd_mac_table_entry entry = { { 0 } };
+
+	memcpy(entry.addr, adapter->mac_addr, sizeof(adapter->mac_addr));
+
+	memset(entry.mask, 0xff, sizeof(entry.mask));
+	entry.rx_valid = true;
+	entry.tx_valid = false;
+	entry.udma_mask = udma_mask;
+	entry.filter = false;
+
+	netdev_dbg(adapter->netdev, "[%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n",
+		   idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask));
+
+	al_eth_fwd_mac_table_set(&adapter->hw_adapter, idx, &entry);
+}
+
+static void al_eth_mac_table_all_multicast_add(struct al_eth_adapter *adapter,
+					       u8 idx, u8 udma_mask)
+{
+	struct al_eth_fwd_mac_table_entry entry = { { 0 } };
+
+	memset(entry.addr, 0x00, sizeof(entry.addr));
+	memset(entry.mask, 0x00, sizeof(entry.mask));
+	entry.mask[0] |= BIT(0);
+	entry.addr[0] |= BIT(0);
+
+	entry.rx_valid = true;
+	entry.tx_valid = false;
+	entry.udma_mask = udma_mask;
+	entry.filter = false;
+
+	netdev_dbg(adapter->netdev, "[%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n",
+		   idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask));
+
+	al_eth_fwd_mac_table_set(&adapter->hw_adapter, idx, &entry);
+}
+
+static void al_eth_mac_table_broadcast_add(struct al_eth_adapter *adapter,
+					   u8 idx, u8 udma_mask)
+{
+	struct al_eth_fwd_mac_table_entry entry = { { 0 } };
+
+	memset(entry.addr, 0xff, sizeof(entry.addr));
+	memset(entry.mask, 0xff, sizeof(entry.mask));
+
+	entry.rx_valid = true;
+	entry.tx_valid = false;
+	entry.udma_mask = udma_mask;
+	entry.filter = false;
+
+	netdev_dbg(adapter->netdev, "[%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n",
+		   idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask));
+
+	al_eth_fwd_mac_table_set(&adapter->hw_adapter, idx, &entry);
+}
+
+static void al_eth_mac_table_promiscuous_set(struct al_eth_adapter *adapter,
+					     bool promiscuous)
+{
+	struct al_eth_fwd_mac_table_entry entry = { { 0 } };
+
+	memset(entry.addr, 0x00, sizeof(entry.addr));
+	memset(entry.mask, 0x00, sizeof(entry.mask));
+
+	entry.rx_valid = true;
+	entry.tx_valid = false;
+	entry.udma_mask = (promiscuous) ? 1 : 0;
+	entry.filter = (promiscuous) ? false : true;
+
+	netdev_dbg(adapter->netdev, "%s promiscuous mode\n",
+		   (promiscuous) ? "enter" : "exit");
+
+	al_eth_fwd_mac_table_set(&adapter->hw_adapter,
+				 AL_ETH_MAC_TABLE_DROP_IDX,
+				 &entry);
+}
+
+static void al_eth_mac_table_entry_clear(struct al_eth_adapter *adapter, u8 idx)
+{
+	struct al_eth_fwd_mac_table_entry entry = { { 0 } };
+
+	al_eth_fwd_mac_table_set(&adapter->hw_adapter, idx, &entry);
+}
+
+/*
+ * Configure the RX forwarding (UDMA/QUEUE.. selection).
+ * Currently we don't use the full control table, we use only the default
+ * configuration.
+ */
+
+static void al_eth_config_rx_fwd(struct al_eth_adapter *adapter)
+{
+	struct al_eth_fwd_ctrl_table_entry entry;
+	int i;
+
+	/* let priority be equal to pbits */
+	for (i = 0; i < AL_ETH_FWD_PBITS_TABLE_NUM; i++)
+		al_eth_fwd_pbits_table_set(&adapter->hw_adapter, i, i);
+
+	/* map priority to queue index, queue id = priority/2 */
+	for (i = 0; i < AL_ETH_FWD_PRIO_TABLE_NUM; i++)
+		al_eth_fwd_priority_table_set(&adapter->hw_adapter, i, i >> 1);
+
+	entry.prio_sel = AL_ETH_CTRL_TABLE_PRIO_SEL_VAL_0;
+	entry.queue_sel_1 = AL_ETH_CTRL_TABLE_QUEUE_SEL_1_THASH_TABLE;
+	entry.queue_sel_2 = AL_ETH_CTRL_TABLE_QUEUE_SEL_2_NO_PRIO;
+	entry.udma_sel = AL_ETH_CTRL_TABLE_UDMA_SEL_MAC_TABLE;
+	entry.filter = false;
+
+	al_eth_ctrl_table_def_set(&adapter->hw_adapter, false, &entry);
+
+	/*
+	 * By default set the mac table to forward all unicast packets to our
+	 * MAC address and all broadcast. all the rest will be dropped.
+	 */
+	al_eth_mac_table_unicast_add(adapter, AL_ETH_MAC_TABLE_UNICAST_IDX_BASE,
+				     adapter->mac_addr, 1);
+	al_eth_mac_table_broadcast_add(adapter, AL_ETH_MAC_TABLE_BROADCAST_IDX, 1);
+	al_eth_mac_table_promiscuous_set(adapter, false);
+
+	/* set toeplitz hash keys */
+	get_random_bytes(adapter->toeplitz_hash_key,
+			 sizeof(adapter->toeplitz_hash_key));
+
+	for (i = 0; i < AL_ETH_RX_HASH_KEY_NUM; i++)
+		al_eth_hash_key_set(&adapter->hw_adapter, i,
+				    htonl(adapter->toeplitz_hash_key[i]));
+
+	for (i = 0; i < AL_ETH_RX_RSS_TABLE_SIZE; i++)
+		al_eth_thash_table_set(&adapter->hw_adapter, i, 0,
+				       adapter->rss_ind_tbl[i]);
+
+	al_eth_fsm_table_init(adapter);
+}
+
+static void al_eth_restore_ethtool_params(struct al_eth_adapter *adapter)
+{
+	int i;
+	unsigned int tx_usecs = adapter->tx_usecs;
+	unsigned int rx_usecs = adapter->rx_usecs;
+
+	adapter->tx_usecs = 0;
+	adapter->rx_usecs = 0;
+
+	for (i = 0; i < AL_ETH_RX_RSS_TABLE_SIZE; i++)
+		al_eth_thash_table_set(&adapter->hw_adapter, i, 0,
+				       adapter->rss_ind_tbl[i]);
+}
+
+static void al_eth_up_complete(struct al_eth_adapter *adapter)
+{
+	al_eth_configure_int_mode(adapter);
+
+	/* config rx fwd */
+	al_eth_config_rx_fwd(adapter);
+
+	al_eth_init_napi(adapter);
+	al_eth_napi_enable_all(adapter);
+
+	al_eth_change_mtu(adapter->netdev, adapter->netdev->mtu);
+	/* enable hw queues */
+	al_eth_udma_queues_enable_all(adapter);
+
+	al_eth_refill_all_rx_bufs(adapter);
+
+	al_eth_interrupts_unmask(adapter);
+
+	/* enable transmits */
+	netif_tx_start_all_queues(adapter->netdev);
+
+	/* enable flow control */
+	al_eth_flow_ctrl_enable(adapter);
+
+	al_eth_restore_ethtool_params(adapter);
+
+	/* enable the mac tx and rx paths */
+	al_eth_mac_start(&adapter->hw_adapter);
+}
+
+static int al_eth_up(struct al_eth_adapter *adapter)
+{
+	int rc;
+
+	if (adapter->flags & AL_ETH_FLAG_RESET_REQUESTED) {
+		al_eth_function_reset(adapter);
+		adapter->flags &= ~AL_ETH_FLAG_RESET_REQUESTED;
+	}
+
+	rc = al_eth_hw_init(adapter);
+	if (rc)
+		goto err_hw_init_open;
+
+	al_eth_setup_int_mode(adapter, IS_ENABLED(CONFIG_NET_AL_ETH_NO_MSIX));
+
+	/* allocate transmit descriptors */
+	rc = al_eth_setup_all_tx_resources(adapter);
+	if (rc)
+		goto err_setup_tx;
+
+	/* allocate receive descriptors */
+	rc = al_eth_setup_all_rx_resources(adapter);
+	if (rc)
+		goto err_setup_rx;
+
+	rc = al_eth_request_irq(adapter);
+	if (rc)
+		goto err_req_irq;
+
+	al_eth_up_complete(adapter);
+
+	adapter->up = true;
+
+	return rc;
+
+err_req_irq:
+	al_eth_free_all_rx_resources(adapter);
+err_setup_rx:
+	al_eth_free_all_tx_resources(adapter);
+err_setup_tx:
+	al_eth_free_irq(adapter);
+	al_eth_hw_stop(adapter);
+err_hw_init_open:
+	al_eth_function_reset(adapter);
+
+	return rc;
+}
+
+static void al_eth_down(struct al_eth_adapter *adapter)
+{
+	adapter->up = false;
+
+	netif_carrier_off(adapter->netdev);
+	al_eth_disable_int_sync(adapter);
+	al_eth_napi_disable_all(adapter);
+	netif_tx_disable(adapter->netdev);
+	al_eth_free_irq(adapter);
+	al_eth_hw_stop(adapter);
+	al_eth_del_napi(adapter);
+
+	al_eth_free_all_tx_bufs(adapter);
+	al_eth_free_all_rx_bufs(adapter);
+	al_eth_free_all_tx_resources(adapter);
+	al_eth_free_all_rx_resources(adapter);
+}
+
+/*
+ * al_eth_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int al_eth_open(struct net_device *netdev)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+	int rc;
+
+	netif_carrier_off(netdev);
+
+	/* Notify the stack of the actual queue counts. */
+	rc = netif_set_real_num_tx_queues(netdev, adapter->num_tx_queues);
+	if (rc)
+		return rc;
+
+	rc = netif_set_real_num_rx_queues(netdev, adapter->num_rx_queues);
+	if (rc)
+		return rc;
+
+	adapter->last_establish_failed = false;
+
+	rc = al_eth_up(adapter);
+	if (rc)
+		return rc;
+
+	if (adapter->phy_exist) {
+		rc = al_eth_mdiobus_setup(adapter);
+		if (rc) {
+			netdev_err(netdev, "failed at mdiobus setup!\n");
+			goto err_mdiobus_setup;
+		}
+	}
+
+	if (adapter->mdio_bus)
+		rc = al_eth_phy_init(adapter);
+	else
+		netif_carrier_on(adapter->netdev);
+
+	return rc;
+
+err_mdiobus_setup:
+	al_eth_down(adapter);
+
+	return rc;
+}
+
+/*
+ * al_eth_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static int al_eth_close(struct net_device *netdev)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+
+	cancel_delayed_work_sync(&adapter->link_status_task);
+
+	if (adapter->phydev) {
+		phy_stop(adapter->phydev);
+		phy_disconnect(adapter->phydev);
+		al_eth_mdiobus_teardown(adapter);
+	}
+
+	if (adapter->up)
+		al_eth_down(adapter);
+
+	return 0;
+}
+
+static int al_eth_get_settings(struct net_device *netdev,
+			       struct ethtool_cmd *ecmd)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+	struct phy_device *phydev = adapter->phydev;
+
+	if (phydev)
+		return phy_ethtool_gset(phydev, ecmd);
+
+	ecmd->speed = adapter->link_config.active_speed;
+	ecmd->duplex = adapter->link_config.active_duplex;
+	ecmd->autoneg = adapter->link_config.autoneg;
+
+	return 0;
+}
+
+static int al_eth_set_settings(struct net_device *netdev,
+			       struct ethtool_cmd *ecmd)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+	struct phy_device *phydev = adapter->phydev;
+	int rc = 0;
+
+	if (phydev)
+		return phy_ethtool_sset(phydev, ecmd);
+
+	/* in case no phy exist set only mac parameters */
+	adapter->link_config.active_speed = ecmd->speed;
+	adapter->link_config.active_duplex = ecmd->duplex;
+	adapter->link_config.autoneg = ecmd->autoneg;
+
+	if (adapter->up)
+		dev_warn(&adapter->pdev->dev,
+			 "this action will take place in the next activation (up)\n");
+
+	return rc;
+}
+
+static int al_eth_nway_reset(struct net_device *netdev)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+	struct phy_device *phydev = adapter->phydev;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_start_aneg(phydev);
+}
+
+static u32 al_eth_get_msglevel(struct net_device *netdev)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+	return adapter->msg_enable;
+}
+
+static void al_eth_set_msglevel(struct net_device *netdev, u32 value)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+
+	adapter->msg_enable = value;
+}
+
+static void al_eth_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
+{
+	struct al_eth_adapter *adapter = netdev_priv(dev);
+
+	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+	strlcpy(info->bus_info, pci_name(adapter->pdev), sizeof(info->bus_info));
+}
+
+static void al_eth_get_pauseparam(struct net_device *netdev,
+				  struct ethtool_pauseparam *pause)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+	struct al_eth_link_config *link_config = &adapter->link_config;
+
+	pause->autoneg = ((link_config->flow_ctrl_active &
+					AL_ETH_FLOW_CTRL_AUTONEG) != 0);
+	pause->rx_pause = ((link_config->flow_ctrl_active &
+					AL_ETH_FLOW_CTRL_RX_PAUSE) != 0);
+	pause->tx_pause = ((link_config->flow_ctrl_active &
+					AL_ETH_FLOW_CTRL_TX_PAUSE) != 0);
+}
+
+static int al_eth_set_pauseparam(struct net_device *netdev,
+				 struct ethtool_pauseparam *pause)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+	struct al_eth_link_config *link_config = &adapter->link_config;
+	u32 newadv;
+
+	/* auto negotiation and receive pause are currently not supported */
+	if (pause->autoneg == AUTONEG_ENABLE)
+		return -EINVAL;
+
+	link_config->flow_ctrl_supported = 0;
+
+	if (pause->rx_pause) {
+		link_config->flow_ctrl_supported |= AL_ETH_FLOW_CTRL_RX_PAUSE;
+
+		if (pause->tx_pause) {
+			link_config->flow_ctrl_supported |= AL_ETH_FLOW_CTRL_TX_PAUSE;
+			newadv = ADVERTISED_Pause;
+		} else
+			newadv = ADVERTISED_Pause |
+				 ADVERTISED_Asym_Pause;
+	} else if (pause->tx_pause) {
+		link_config->flow_ctrl_supported |= AL_ETH_FLOW_CTRL_TX_PAUSE;
+		newadv = ADVERTISED_Asym_Pause;
+	} else {
+		newadv = 0;
+	}
+
+	if (pause->autoneg) {
+		struct phy_device *phydev;
+		u32 oldadv;
+
+		phydev = mdiobus_get_phy(adapter->mdio_bus, adapter->phy_addr);
+		oldadv = phydev->advertising &
+				     (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+		link_config->flow_ctrl_supported |= AL_ETH_FLOW_CTRL_AUTONEG;
+
+		if (oldadv != newadv) {
+			phydev->advertising &= ~(ADVERTISED_Pause |
+							ADVERTISED_Asym_Pause);
+			phydev->advertising |= newadv;
+
+			if (phydev->autoneg)
+				return phy_start_aneg(phydev);
+		}
+	} else {
+		link_config->flow_ctrl_active = link_config->flow_ctrl_supported;
+		al_eth_flow_ctrl_config(adapter);
+	}
+
+	return 0;
+}
+
+static int al_eth_get_rxnfc(struct net_device *netdev,
+			    struct ethtool_rxnfc *info,
+			    u32 *rules __always_unused)
+{
+	switch (info->cmd) {
+	case ETHTOOL_GRXRINGS:
+		info->data = AL_ETH_NUM_QUEUES;
+		return 0;
+	default:
+		netdev_err(netdev, "Command parameters not supported\n");
+		return -EOPNOTSUPP;
+	}
+}
+
+static u32 al_eth_get_rxfh_indir_size(struct net_device *netdev)
+{
+	return AL_ETH_RX_RSS_TABLE_SIZE;
+}
+
+static const struct ethtool_ops al_eth_ethtool_ops = {
+	.get_settings		= al_eth_get_settings,
+	.set_settings		= al_eth_set_settings,
+	.get_drvinfo		= al_eth_get_drvinfo,
+	.get_msglevel		= al_eth_get_msglevel,
+	.set_msglevel		= al_eth_set_msglevel,
+
+	.nway_reset		= al_eth_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_pauseparam		= al_eth_get_pauseparam,
+	.set_pauseparam		= al_eth_set_pauseparam,
+	.get_rxnfc		= al_eth_get_rxnfc,
+	.get_rxfh_indir_size    = al_eth_get_rxfh_indir_size,
+};
+
+static void al_eth_tx_csum(struct al_eth_ring *tx_ring,
+			   struct al_eth_tx_buffer *tx_info,
+			   struct al_eth_pkt *hw_pkt, struct sk_buff *skb)
+{
+	u32 mss = skb_shinfo(skb)->gso_size;
+
+	if ((skb->ip_summed == CHECKSUM_PARTIAL) || mss) {
+		struct al_eth_meta_data *meta = &tx_ring->hw_meta;
+		if (mss)
+			hw_pkt->flags |= AL_ETH_TX_FLAGS_TSO |
+					 AL_ETH_TX_FLAGS_L4_CSUM;
+		else
+			hw_pkt->flags |= AL_ETH_TX_FLAGS_L4_CSUM |
+					 AL_ETH_TX_FLAGS_L4_PARTIAL_CSUM;
+
+		switch (skb->protocol) {
+		case htons(ETH_P_IP):
+			hw_pkt->l3_proto_idx = AL_ETH_PROTO_ID_IPv4;
+			if (mss)
+				hw_pkt->flags |= AL_ETH_TX_FLAGS_IPV4_L3_CSUM;
+			if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+				hw_pkt->l4_proto_idx = AL_ETH_PROTO_ID_TCP;
+			else
+				hw_pkt->l4_proto_idx = AL_ETH_PROTO_ID_UDP;
+			break;
+		case htons(ETH_P_IPV6):
+			hw_pkt->l3_proto_idx = AL_ETH_PROTO_ID_IPv6;
+			if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+				hw_pkt->l4_proto_idx = AL_ETH_PROTO_ID_TCP;
+			else
+				hw_pkt->l4_proto_idx = AL_ETH_PROTO_ID_UDP;
+			break;
+		default:
+			break;
+		}
+
+		meta->words_valid = 4;
+		meta->l3_header_len = skb_network_header_len(skb);
+		meta->l3_header_offset = skb_network_offset(skb);
+		meta->l4_header_len = tcp_hdr(skb)->doff; /* only for TSO */
+		meta->mss_idx_sel = 0;
+		meta->mss_val = skb_shinfo(skb)->gso_size;
+		hw_pkt->meta = meta;
+	} else {
+		hw_pkt->meta = NULL;
+	}
+}
+
+/* Called with netif_tx_lock. */
+static netdev_tx_t al_eth_start_xmit(struct sk_buff *skb,
+				     struct net_device *dev)
+{
+	struct al_eth_adapter *adapter = netdev_priv(dev);
+	dma_addr_t dma;
+	struct al_eth_tx_buffer *tx_info;
+	struct al_eth_pkt *hw_pkt;
+	struct al_buf *al_buf;
+	u32 len, last_frag;
+	u16 next_to_use;
+	int i, qid;
+	struct al_eth_ring *tx_ring;
+	struct netdev_queue *txq;
+
+	/*  Determine which tx ring we will be placed on */
+	qid = skb_get_queue_mapping(skb);
+	tx_ring = &adapter->tx_ring[qid];
+	txq = netdev_get_tx_queue(dev, qid);
+
+	len = skb_headlen(skb);
+
+	dma = dma_map_single(tx_ring->dev, skb->data, len, DMA_TO_DEVICE);
+	if (dma_mapping_error(tx_ring->dev, dma)) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	next_to_use = tx_ring->next_to_use;
+	tx_info = &tx_ring->tx_buffer_info[next_to_use];
+	tx_info->skb = skb;
+	hw_pkt = &tx_info->hw_pkt;
+
+	/* set flags and meta data */
+	hw_pkt->flags = AL_ETH_TX_FLAGS_INT;
+	al_eth_tx_csum(tx_ring, tx_info, hw_pkt, skb);
+
+	al_buf = hw_pkt->bufs;
+
+	dma_unmap_addr_set(al_buf, addr, dma);
+	dma_unmap_len_set(al_buf, len, len);
+
+	last_frag = skb_shinfo(skb)->nr_frags;
+
+	for (i = 0; i < last_frag; i++) {
+		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		al_buf++;
+
+		len = skb_frag_size(frag);
+		dma = skb_frag_dma_map(tx_ring->dev, frag, 0, len,
+				       DMA_TO_DEVICE);
+		if (dma_mapping_error(tx_ring->dev, dma))
+			goto dma_error;
+		dma_unmap_addr_set(al_buf, addr, dma);
+		dma_unmap_len_set(al_buf, len, len);
+	}
+
+	hw_pkt->num_of_bufs = 1 + last_frag;
+	if (unlikely(last_frag > (AL_ETH_PKT_MAX_BUFS - 2))) {
+		int i;
+
+		netdev_err(adapter->netdev,
+			   "too much descriptors. last_frag %d!\n", last_frag);
+		for (i = 0; i <= last_frag; i++)
+			netdev_err(adapter->netdev,
+				   "frag[%d]: addr:0x%llx, len 0x%x\n", i,
+				   (unsigned long long)hw_pkt->bufs[i].addr,
+				   hw_pkt->bufs[i].len);
+	}
+	netdev_tx_sent_queue(txq, skb->len);
+
+	tx_ring->next_to_use = AL_ETH_TX_RING_IDX_NEXT(tx_ring, next_to_use);
+
+	/* prepare the packet's descriptors to dma engine */
+	tx_info->tx_descs = al_eth_tx_pkt_prepare(&adapter->hw_adapter,
+						  tx_ring->dma_q, hw_pkt);
+
+	/*
+	 * stop the queue when no more space available, the packet can have up
+	 * to MAX_SKB_FRAGS + 1 buffers and a meta descriptor
+	 */
+	if (unlikely(al_udma_available_get(tx_ring->dma_q) <
+				(MAX_SKB_FRAGS + 2))) {
+		netdev_dbg(adapter->netdev, "stop queue %d\n", qid);
+		netif_tx_stop_queue(txq);
+	}
+
+	/* trigger the dma engine */
+	al_eth_tx_dma_action(tx_ring->dma_q, tx_info->tx_descs);
+
+	return NETDEV_TX_OK;
+
+dma_error:
+	/* save value of frag that failed */
+	last_frag = i;
+
+	/* start back at beginning and unmap skb */
+	tx_info->skb = NULL;
+	al_buf = hw_pkt->bufs;
+	dma_unmap_single(tx_ring->dev, dma_unmap_addr(al_buf, addr),
+			 dma_unmap_len(al_buf, len), DMA_TO_DEVICE);
+
+	/* unmap remaining mapped pages */
+	for (i = 0; i < last_frag; i++) {
+		al_buf++;
+		dma_unmap_page(tx_ring->dev, dma_unmap_addr(al_buf, addr),
+			       dma_unmap_len(al_buf, len), DMA_TO_DEVICE);
+	}
+
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+/* Return subqueue id on this core (one per core). */
+static u16 al_eth_select_queue(struct net_device *dev, struct sk_buff *skb,
+			       void *accel_priv,
+			       select_queue_fallback_t fallback)
+{
+	u16 qid = skb_rx_queue_recorded(skb);
+
+	if (!qid)
+		return fallback(dev, skb);
+
+	return qid;
+}
+
+static int al_eth_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct al_eth_adapter *adapter = netdev_priv(dev);
+	struct sockaddr *addr = p;
+	int err = 0;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	memcpy(adapter->mac_addr, addr->sa_data, dev->addr_len);
+	al_eth_mac_table_unicast_add(adapter, AL_ETH_MAC_TABLE_UNICAST_IDX_BASE,
+				     adapter->mac_addr, 1);
+
+	if (!netif_running(dev))
+		return 0;
+
+	return err;
+}
+
+/*
+ *  Unicast, Multicast and Promiscuous mode set
+ *  @netdev: network interface device structure
+ *
+ *  The set_rx_mode entry point is called whenever the unicast or multicast
+ *  address lists or the network interface flags are updated.  This routine is
+ *  responsible for configuring the hardware for proper unicast, multicast,
+ *  promiscuous mode, and all-multi behavior.
+ */
+static void al_eth_set_rx_mode(struct net_device *netdev)
+{
+	struct al_eth_adapter *adapter = netdev_priv(netdev);
+
+	if (netdev->flags & IFF_PROMISC) {
+		al_eth_mac_table_promiscuous_set(adapter, true);
+	} else {
+		if (netdev->flags & IFF_ALLMULTI) {
+			al_eth_mac_table_all_multicast_add(adapter,
+							   AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX,
+							   1);
+		} else {
+			if (netdev_mc_empty(netdev))
+				al_eth_mac_table_entry_clear(adapter,
+					AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX);
+			else
+				al_eth_mac_table_all_multicast_add(adapter,
+								   AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX,
+								   1);
+		}
+
+		if (!netdev_uc_empty(netdev)) {
+			struct netdev_hw_addr *ha;
+			u8 i = AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 1;
+
+			if (netdev_uc_count(netdev) >
+				AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT) {
+				/*
+				 * In this case there are more addresses then
+				 * entries in the mac table - set promiscuous
+				 */
+				al_eth_mac_table_promiscuous_set(adapter, true);
+				return;
+			}
+
+			/* clear the last configuration */
+			while (i < (AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 1 +
+				    AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT)) {
+				al_eth_mac_table_entry_clear(adapter, i);
+				i++;
+			}
+
+			/* set new addresses */
+			i = AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 1;
+			netdev_for_each_uc_addr(ha, netdev) {
+				al_eth_mac_table_unicast_add(adapter, i,
+							     ha->addr, 1);
+				i++;
+			}
+		}
+
+		al_eth_mac_table_promiscuous_set(adapter, false);
+	}
+}
+
+static const struct net_device_ops al_eth_netdev_ops = {
+	.ndo_open		= al_eth_open,
+	.ndo_stop		= al_eth_close,
+	.ndo_start_xmit		= al_eth_start_xmit,
+	.ndo_select_queue	= al_eth_select_queue,
+	.ndo_do_ioctl		= al_eth_ioctl,
+	.ndo_tx_timeout		= al_eth_tx_timeout,
+	.ndo_change_mtu		= al_eth_change_mtu,
+	.ndo_set_mac_address	= al_eth_set_mac_addr,
+	.ndo_set_rx_mode	= al_eth_set_rx_mode,
+};
+
+/*
+ * al_eth_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in al_eth_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * al_eth_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ */
+static int al_eth_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct al_eth_adapter *adapter;
+	void __iomem * const *iomap;
+	struct al_hw_eth_adapter *hw_adapter;
+	static int adapters_found;
+	u16 dev_id;
+	u8 rev_id;
+	int rc, i;
+
+	rc = pcim_enable_device(pdev);
+	if (rc) {
+		dev_err(&pdev->dev, "pcim_enable_device failed!\n");
+		return rc;
+	}
+
+	if (ent->driver_data == ALPINE_INTEGRATED)
+		rc = pcim_iomap_regions(pdev, BIT(0) | BIT(2) | BIT(4),
+					DRV_MODULE_NAME);
+	else
+		rc = pcim_iomap_regions(pdev,
+					BIT(board_info[ent->driver_data].bar),
+					DRV_MODULE_NAME);
+
+	if (rc) {
+		dev_err(&pdev->dev,
+			"pci_request_selected_regions failed 0x%x\n", rc);
+		return rc;
+	}
+
+	iomap = pcim_iomap_table(pdev);
+	if (!iomap) {
+		dev_err(&pdev->dev, "pcim_iomap_table failed\n");
+		return -ENOMEM;
+	}
+
+	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(40));
+	if (rc) {
+		dev_err(&pdev->dev, "pci_set_dma_mask failed 0x%x\n", rc);
+		return rc;
+	}
+
+	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40));
+	if (rc) {
+		dev_err(&pdev->dev,
+			"err_pci_set_consistent_dma_mask failed 0x%x\n", rc);
+		return rc;
+	}
+
+	pci_set_master(pdev);
+	pci_save_state(pdev);
+
+	/* dev zeroed in init_etherdev */
+	netdev = alloc_etherdev_mq(sizeof(struct al_eth_adapter),
+				   AL_ETH_NUM_QUEUES);
+	if (!netdev) {
+		dev_err(&pdev->dev, "alloc_etherdev_mq failed\n");
+		return -ENOMEM;
+	}
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	adapter = netdev_priv(netdev);
+	pci_set_drvdata(pdev, adapter);
+
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+	hw_adapter = &adapter->hw_adapter;
+	adapter->msg_enable = netif_msg_init(-1, DEFAULT_MSG_ENABLE);
+
+	adapter->udma_base = iomap[AL_ETH_UDMA_BAR];
+	adapter->ec_base = iomap[AL_ETH_EC_BAR];
+	adapter->mac_base = iomap[AL_ETH_MAC_BAR];
+
+	pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+
+	adapter->rev_id = rev_id;
+	adapter->dev_id = dev_id;
+	adapter->id_number = adapters_found;
+
+	/* set default ring sizes */
+	adapter->tx_ring_count = AL_ETH_DEFAULT_TX_SW_DESCS;
+	adapter->tx_descs_count = AL_ETH_DEFAULT_TX_HW_DESCS;
+	adapter->rx_ring_count = AL_ETH_DEFAULT_RX_DESCS;
+	adapter->rx_descs_count = AL_ETH_DEFAULT_RX_DESCS;
+
+	adapter->num_tx_queues = AL_ETH_NUM_QUEUES;
+	adapter->num_rx_queues = AL_ETH_NUM_QUEUES;
+
+	adapter->rx_copybreak = AL_ETH_DEFAULT_SMALL_PACKET_LEN;
+	adapter->link_poll_interval = AL_ETH_DEFAULT_LINK_POLL_INTERVAL;
+	adapter->max_rx_buff_alloc_size = AL_ETH_DEFAULT_MAX_RX_BUFF_ALLOC_SIZE;
+	adapter->link_config.force_1000_base_x = AL_ETH_DEFAULT_FORCE_1000_BASEX;
+
+	snprintf(adapter->name, AL_ETH_NAME_MAX_LEN, "al_eth_%d",
+		 adapter->id_number);
+	rc = al_eth_board_params_init(adapter);
+	if (rc)
+		goto err_hw_init;
+
+	al_eth_function_reset(adapter);
+
+	rc = al_eth_hw_init_adapter(adapter);
+	if (rc)
+		goto err_hw_init;
+
+	al_eth_init_rings(adapter);
+
+	netdev->netdev_ops = &al_eth_netdev_ops;
+	netdev->watchdog_timeo = TX_TIMEOUT;
+	netdev->ethtool_ops = &al_eth_ethtool_ops;
+
+	if (!is_valid_ether_addr(adapter->mac_addr)) {
+		eth_hw_addr_random(netdev);
+		memcpy(adapter->mac_addr, netdev->dev_addr, ETH_ALEN);
+	} else {
+		memcpy(netdev->dev_addr, adapter->mac_addr, ETH_ALEN);
+	}
+
+	memcpy(adapter->netdev->perm_addr, adapter->mac_addr, netdev->addr_len);
+
+	netdev->hw_features = NETIF_F_SG |
+			      NETIF_F_IP_CSUM |
+			      NETIF_F_IPV6_CSUM |
+			      NETIF_F_TSO |
+			      NETIF_F_TSO_ECN |
+			      NETIF_F_TSO6 |
+			      NETIF_F_RXCSUM |
+			      NETIF_F_NTUPLE |
+			      NETIF_F_RXHASH |
+			      NETIF_F_HIGHDMA;
+
+	netdev->features = netdev->hw_features;
+	netdev->priv_flags |= IFF_UNICAST_FLT;
+
+	for (i = 0; i < AL_ETH_RX_RSS_TABLE_SIZE; i++)
+		adapter->rss_ind_tbl[i] =
+			ethtool_rxfh_indir_default(i, AL_ETH_NUM_QUEUES);
+
+	rc = register_netdev(netdev);
+	if (rc) {
+		dev_err(&pdev->dev, "Cannot register net device\n");
+		goto err_register;
+	}
+
+	netdev_info(netdev, "%s found at mem %lx, mac addr %pM\n",
+		    board_info[ent->driver_data].name,
+		    (long)pci_resource_start(pdev, 0), netdev->dev_addr);
+
+	adapters_found++;
+	return 0;
+err_register:
+err_hw_init:
+	free_netdev(netdev);
+	return rc;
+}
+
+/*
+ * al_eth_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * al_eth_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+static void al_eth_remove(struct pci_dev *pdev)
+{
+	struct al_eth_adapter *adapter = pci_get_drvdata(pdev);
+	struct net_device *dev = adapter->netdev;
+
+	al_eth_hw_stop(adapter);
+
+	unregister_netdev(dev);
+
+	free_netdev(dev);
+
+	pci_set_drvdata(pdev, NULL);
+	pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int al_eth_resume(struct pci_dev *pdev)
+{
+	struct al_eth_adapter *adapter = pci_get_drvdata(pdev);
+	struct net_device *netdev = adapter->netdev;
+	u32 err;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	/*
+	 * pci_restore_state clears dev->state_saved so call
+	 * pci_save_state to restore it.
+	 */
+	pci_save_state(pdev);
+
+	err = pci_enable_device_mem(pdev);
+	if (err) {
+		netdev_err(adapter->netdev,
+			   "Cannot enable PCI device from suspend\n");
+		return err;
+	}
+	pci_set_master(pdev);
+
+	pci_wake_from_d3(pdev, false);
+
+	al_eth_wol_disable(&adapter->hw_adapter);
+
+	netif_device_attach(netdev);
+
+	return 0;
+}
+
+static int al_eth_wol_config(struct al_eth_adapter *adapter)
+{
+	struct al_eth_wol_params wol = {0};
+
+	if (adapter->wol & WAKE_UCAST) {
+		wol.int_mask = AL_ETH_WOL_INT_UNICAST;
+		wol.forward_mask = AL_ETH_WOL_FWRD_UNICAST;
+	}
+
+	if (adapter->wol & WAKE_MCAST) {
+		wol.int_mask = AL_ETH_WOL_INT_MULTICAST;
+		wol.forward_mask = AL_ETH_WOL_FWRD_MULTICAST;
+	}
+
+	if (adapter->wol & WAKE_BCAST) {
+		wol.int_mask = AL_ETH_WOL_INT_BROADCAST;
+		wol.forward_mask = AL_ETH_WOL_FWRD_BROADCAST;
+	}
+
+	if (wol.int_mask != 0) {
+		al_eth_wol_enable(&adapter->hw_adapter, &wol);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int al_eth_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct al_eth_adapter *adapter = pci_get_drvdata(pdev);
+
+	if (al_eth_wol_config(adapter)) {
+		pci_prepare_to_sleep(pdev);
+	} else {
+		pci_wake_from_d3(pdev, false);
+		pci_set_power_state(pdev, PCI_D3hot);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver al_eth_pci_driver = {
+	.name		= DRV_MODULE_NAME,
+	.id_table	= al_eth_pci_tbl,
+	.probe		= al_eth_probe,
+	.remove		= al_eth_remove,
+#ifdef CONFIG_PM
+	.suspend	= al_eth_suspend,
+	.resume		= al_eth_resume,
+#endif
+};
+
+static int __init al_eth_init(void)
+{
+	return pci_register_driver(&al_eth_pci_driver);
+}
+
+static void __exit al_eth_cleanup(void)
+{
+	pci_unregister_driver(&al_eth_pci_driver);
+}
+
+module_init(al_eth_init);
+module_exit(al_eth_cleanup);
diff --git a/drivers/net/ethernet/annapurna/al_eth.h b/drivers/net/ethernet/annapurna/al_eth.h
new file mode 100644
index 000000000000..8a2d8ffa3ff1
--- /dev/null
+++ b/drivers/net/ethernet/annapurna/al_eth.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2017, Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef AL_ETH_H
+#define AL_ETH_H
+
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inetdevice.h>
+
+#include "al_hw_eth.h"
+#include <linux/soc/alpine/al_hw_udma_iofic.h>
+
+enum board_t {
+	ALPINE_INTEGRATED = 0,
+	ALPINE_NIC = 1,
+};
+
+#define AL_ETH_MAX_HW_QUEUES	4
+#define AL_ETH_NUM_QUEUES	4
+#define AL_ETH_MAX_MSIX_VEC	(1 + 2 * AL_ETH_MAX_HW_QUEUES)
+
+#define AL_ETH_DEFAULT_TX_SW_DESCS	(512)
+#define AL_ETH_DEFAULT_TX_HW_DESCS	(512)
+#define AL_ETH_DEFAULT_RX_DESCS		(512)
+
+#if ((AL_ETH_DEFAULT_TX_SW_DESCS / 4) < (MAX_SKB_FRAGS + 2))
+#define AL_ETH_TX_WAKEUP_THRESH		(AL_ETH_DEFAULT_TX_SW_DESCS / 4)
+#else
+#define AL_ETH_TX_WAKEUP_THRESH		(MAX_SKB_FRAGS + 2)
+#endif
+#define AL_ETH_DEFAULT_SMALL_PACKET_LEN		(128 - NET_IP_ALIGN)
+
+#define AL_ETH_DEFAULT_MAX_RX_BUFF_ALLOC_SIZE 1536
+/*
+ * minimum the buffer size to 600 to avoid situation the mtu will be changed
+ * from too little buffer to very big one and then the number of buffer per
+ * packet could reach the maximum AL_ETH_PKT_MAX_BUFS
+ */
+#define AL_ETH_DEFAULT_MIN_RX_BUFF_ALLOC_SIZE 600
+#define AL_ETH_DEFAULT_FORCE_1000_BASEX false
+
+#define AL_ETH_DEFAULT_LINK_POLL_INTERVAL 100
+
+#define AL_ETH_NAME_MAX_LEN	20
+#define AL_ETH_IRQNAME_SIZE	40
+
+#define AL_ETH_MAX_MTU			9216
+
+struct al_eth_irq {
+	irq_handler_t	handler;
+	void		*data;
+	unsigned int	vector;
+	u8		requested;
+	cpumask_t	affinity_hint_mask;
+	char		name[AL_ETH_IRQNAME_SIZE];
+};
+
+struct al_eth_napi {
+	struct napi_struct napi ____cacheline_aligned;
+	struct al_eth_adapter *adapter;
+	unsigned int qid;
+};
+
+struct al_eth_tx_buffer {
+	struct sk_buff *skb;
+	struct al_eth_pkt hw_pkt;
+	unsigned int tx_descs;
+};
+
+struct al_eth_rx_buffer {
+	struct sk_buff *skb;
+	struct page *page;
+	unsigned int page_offset;
+	u8 *data;
+	unsigned int data_size;
+	unsigned int frag_size; /* used in rx skb allocation */
+	DEFINE_DMA_UNMAP_ADDR(dma);
+	struct al_buf	al_buf;
+};
+
+#define AL_ETH_RX_OFFSET	(NET_SKB_PAD + NET_IP_ALIGN)
+
+struct al_eth_ring {
+	struct device *dev;
+	struct napi_struct *napi;
+	struct al_eth_pkt hw_pkt;
+	struct al_udma_q *dma_q; /* udma queue handler */
+	u16 next_to_use;
+	u16 next_to_clean;
+	u32 __iomem *unmask_reg_offset; /* the offset of the interrupt unmask register */
+	/*
+	 * the value to write to the above register to unmask the interrupt
+	 * of this ring
+	 */
+	u32 unmask_val;
+	/* need to use union here */
+	struct al_eth_meta_data hw_meta;
+	struct al_eth_tx_buffer *tx_buffer_info; /* contex of tx packet */
+	struct al_eth_rx_buffer *rx_buffer_info; /* contex of rx packet */
+	int sw_count; /* number of tx/rx_buffer_info's entries */
+	int hw_count; /* number of hw descriptors */
+	size_t descs_size; /* size (in bytes) of hw descriptors */
+	/* size (in bytes) of hw completion descriptors, used for rx */
+	size_t cdescs_size;
+
+	struct net_device *netdev;
+	struct al_udma_q_params	q_params;
+};
+
+#define AL_ETH_TX_RING_IDX_NEXT(tx_ring, idx) (((idx) + 1) & (AL_ETH_DEFAULT_TX_SW_DESCS - 1))
+
+#define AL_ETH_RX_RING_IDX_NEXT(rx_ring, idx) (((idx) + 1) & (AL_ETH_DEFAULT_RX_DESCS - 1))
+#define AL_ETH_RX_RING_IDX_ADD(rx_ring, idx, n) (((idx) + (n)) & (AL_ETH_DEFAULT_RX_DESCS - 1))
+
+/* flow control configuration */
+#define AL_ETH_FLOW_CTRL_RX_FIFO_TH_HIGH	0x160
+#define AL_ETH_FLOW_CTRL_RX_FIFO_TH_LOW		0x90
+#define AL_ETH_FLOW_CTRL_QUANTA			0xffff
+#define AL_ETH_FLOW_CTRL_QUANTA_TH		0x8000
+
+#define AL_ETH_FLOW_CTRL_AUTONEG  BIT(0)
+#define AL_ETH_FLOW_CTRL_RX_PAUSE BIT(1)
+#define AL_ETH_FLOW_CTRL_TX_PAUSE BIT(2)
+
+/* link configuration for 1G port */
+struct al_eth_link_config {
+	int old_link;
+	/* Describes what we actually have. */
+	int active_duplex;
+	int active_speed;
+
+	/* current flow control status */
+	u8 flow_ctrl_active;
+	/* supported configuration (can be changed from ethtool) */
+	u8 flow_ctrl_supported;
+
+	/* the following are not relevant to RGMII */
+	bool force_1000_base_x;
+	bool autoneg;
+};
+
+/* SFP detection event */
+enum al_eth_sfp_detect_evt {
+	/* No change (no connect, disconnect, or new SFP module */
+	AL_ETH_SFP_DETECT_EVT_NO_CHANGE,
+	/* SFP module connected */
+	AL_ETH_SFP_DETECT_EVT_CONNECTED,
+	/* SFP module disconnected */
+	AL_ETH_SFP_DETECT_EVT_DISCONNECTED,
+	/* SFP module replaced */
+	AL_ETH_SFP_DETECT_EVT_CHANGED,
+};
+
+/* Retimer parameters */
+struct al_eth_retimer_params {
+	bool				exist;
+	enum al_eth_retimer_type	type;
+	u8				bus_id;
+	u8				i2c_addr;
+	enum al_eth_retimer_channel	channel;
+	enum al_eth_retimer_channel	tx_channel;
+};
+
+/* board specific private data structure */
+struct al_eth_adapter {
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	u16 dev_id;
+	u8 rev_id;
+
+	/*
+	 * Some features need tri-state capability,
+	 * thus the additional *_CAPABLE flags.
+	 */
+	u32 flags;
+#define AL_ETH_FLAG_MSIX_ENABLED	BIT(2)
+#define AL_ETH_FLAG_RESET_REQUESTED	BIT(7)
+
+	struct al_hw_eth_adapter hw_adapter;
+
+	/*
+	 * rx packets that shorter that this len will be copied to the skb
+	 * header
+	 */
+	unsigned int rx_copybreak;
+
+	/* Maximum size for rx buffer */
+	unsigned int max_rx_buff_alloc_size;
+
+	/* Tx fast path data */
+	int num_tx_queues;
+
+	/* Rx fast path data */
+	int num_rx_queues;
+
+	/* TX */
+	struct al_eth_ring tx_ring[AL_ETH_NUM_QUEUES] ____cacheline_aligned_in_smp;
+
+	/* RX */
+	struct al_eth_ring rx_ring[AL_ETH_NUM_QUEUES];
+
+#define AL_ETH_RXQ_NAPI_IDX(adapter, q)	(q)
+#define AL_ETH_TXQ_NAPI_IDX(adapter, q)	((adapter)->num_rx_queues + (q))
+	struct al_eth_napi al_napi[2 * AL_ETH_NUM_QUEUES];
+
+	enum al_iofic_mode int_mode;
+
+#define AL_ETH_MGMT_IRQ_IDX		0
+#define AL_ETH_RXQ_IRQ_IDX(adapter, q)	(1 + (q))
+#define AL_ETH_TXQ_IRQ_IDX(adapter, q)	(1 + (adapter)->num_rx_queues + (q))
+	struct al_eth_irq irq_tbl[AL_ETH_MAX_MSIX_VEC];
+	struct msix_entry *msix_entries;
+	int msix_vecs;
+	int irq_vecs;
+
+	unsigned int tx_usecs, rx_usecs; /* interrupt coalescing */
+
+	unsigned int tx_ring_count;
+	unsigned int tx_descs_count;
+	unsigned int rx_ring_count;
+	unsigned int rx_descs_count;
+
+	/* RSS*/
+	u32 toeplitz_hash_key[AL_ETH_RX_HASH_KEY_NUM];
+#define AL_ETH_RX_RSS_TABLE_SIZE AL_ETH_RX_THASH_TABLE_SIZE
+	u8  rss_ind_tbl[AL_ETH_RX_RSS_TABLE_SIZE];
+
+	u32 msg_enable;
+	struct al_eth_mac_stats mac_stats;
+
+	enum al_eth_mac_mode mac_mode;
+	u8 mac_addr[ETH_ALEN];
+	/* mdio and phy*/
+	bool phy_exist;
+	struct mii_bus *mdio_bus;
+	struct phy_device *phydev;
+	u8 phy_addr;
+	struct al_eth_link_config link_config;
+
+	int id_number;
+	char name[AL_ETH_NAME_MAX_LEN];
+	void __iomem *internal_pcie_base; /* use for ALPINE_NIC devices */
+	void __iomem *udma_base;
+	void __iomem *ec_base;
+	void __iomem *mac_base;
+
+	struct al_eth_flow_control_params flow_ctrl_params;
+
+	struct al_eth_adapter_params eth_hw_params;
+
+	struct delayed_work link_status_task;
+	u32 link_poll_interval; /* task interval in mSec */
+
+	bool an_en;	/* run kr auto-negotiation */
+	bool lt_en;	/* run kr link-training */
+
+	bool sfp_detection_needed; /* true if need to run sfp detection */
+	u8 i2c_adapter_id; /* identifier for the i2c adapter to use to access SFP+ module */
+	enum al_eth_ref_clk_freq	ref_clk_freq; /* reference clock frequency */
+	unsigned int	mdio_freq; /* MDIO frequency [Khz] */
+	enum al_eth_board_ext_phy_if phy_if;
+
+	bool up;
+
+	bool last_link;
+	bool last_establish_failed;
+
+	u32 wol;
+
+	struct al_eth_retimer_params retimer;
+};
+
+#endif /* !(AL_ETH_H) */
diff --git a/drivers/net/ethernet/annapurna/al_hw_eth.h b/drivers/net/ethernet/annapurna/al_hw_eth.h
new file mode 100644
index 000000000000..b2fc58793b3a
--- /dev/null
+++ b/drivers/net/ethernet/annapurna/al_hw_eth.h
@@ -0,0 +1,1264 @@
+/*
+ * Copyright (C) 2017, Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __AL_HW_ETH_H__
+#define __AL_HW_ETH_H__
+
+#include <linux/types.h>
+#include <linux/soc/alpine/al_hw_udma.h>
+
+#ifndef AL_ETH_PKT_MAX_BUFS
+#ifndef AL_ETH_EX
+#define AL_ETH_PKT_MAX_BUFS 19
+#else
+#define AL_ETH_PKT_MAX_BUFS 30
+#endif
+#endif
+
+#define AL_ETH_UDMA_TX_QUEUES		4
+#define AL_ETH_UDMA_RX_QUEUES		4
+
+#define AL_ETH_UDMA_TX_CDESC_SZ		8
+#define AL_ETH_UDMA_RX_CDESC_SZ		16
+
+/* PCI Adapter Device/Revision ID */
+#define AL_ETH_REV_ID_1			1 /* Alpine V1 */
+#define AL_ETH_REV_ID_2			2 /* Alpine V2 basic */
+#define AL_ETH_REV_ID_3			3 /* Alpine V2 advanced */
+
+/* PCI BARs */
+#define AL_ETH_UDMA_BAR			0
+#define AL_ETH_EC_BAR			4
+#define AL_ETH_MAC_BAR			2
+
+#define AL_ETH_MAX_FRAME_LEN		10000
+#define AL_ETH_MIN_FRAME_LEN		60
+
+#define AL_ETH_TSO_MSS_MIN_VAL		1
+#define AL_ETH_TSO_MSS_MAX_VAL		(AL_ETH_MAX_FRAME_LEN - 200)
+
+enum AL_ETH_PROTO_ID {
+	AL_ETH_PROTO_ID_UNKNOWN = 0,
+	AL_ETH_PROTO_ID_IPv4	= 8,
+	AL_ETH_PROTO_ID_IPv6	= 11,
+	AL_ETH_PROTO_ID_TCP	= 12,
+	AL_ETH_PROTO_ID_UDP	= 13,
+	AL_ETH_PROTO_ID_FCOE    = 21,
+	AL_ETH_PROTO_ID_GRH     = 22, /* RoCE l3 header */
+	AL_ETH_PROTO_ID_BTH     = 23, /* RoCE l4 header */
+	AL_ETH_PROTO_ID_ANY	= 32, /* for sw usage only */
+};
+
+#define AL_ETH_PROTOCOLS_NUM	(AL_ETH_PROTO_ID_ANY)
+
+enum AL_ETH_TX_TUNNEL_MODE {
+	AL_ETH_NO_TUNNELING	= 0,
+	AL_ETH_TUNNEL_NO_UDP	= 1, /* NVGRE / IP over IP */
+	AL_ETH_TUNNEL_WITH_UDP	= 3,	/* VXLAN */
+};
+
+#define AL_ETH_RX_THASH_TABLE_SIZE	BIT(8)
+#define AL_ETH_RX_FSM_TABLE_SIZE	BIT(7)
+#define AL_ETH_RX_HASH_KEY_NUM		10
+#define AL_ETH_FWD_MAC_NUM		32
+#define AL_ETH_FWD_PBITS_TABLE_NUM	BIT(3)
+#define AL_ETH_FWD_PRIO_TABLE_NUM	BIT(3)
+
+/* MAC media mode */
+enum al_eth_mac_mode {
+	AL_ETH_MAC_MODE_RGMII,
+	AL_ETH_MAC_MODE_SGMII,
+	AL_ETH_MAC_MODE_SGMII_2_5G,
+	AL_ETH_MAC_MODE_10GbE_Serial,	/* Applies to XFI and KR modes */
+	AL_ETH_MAC_MODE_10G_SGMII,	/* SGMII using the 10G MAC, don't use*/
+	AL_ETH_MAC_MODE_XLG_LL_40G,	/* applies to 40G mode using the 40G low latency (LL) MAC */
+	AL_ETH_MAC_MODE_KR_LL_25G,	/* applies to 25G mode using the 10/25G low latency (LL) MAC */
+	AL_ETH_MAC_MODE_XLG_LL_50G,	/* applies to 50G mode using the 40/50G low latency (LL) MAC */
+	AL_ETH_MAC_MODE_XLG_LL_25G	/* applies to 25G mode using the 40/50G low latency (LL) MAC */
+};
+
+/* interface type used for MDIO */
+enum al_eth_mdio_if {
+	AL_ETH_MDIO_IF_1G_MAC = 0,
+	AL_ETH_MDIO_IF_10G_MAC = 1
+};
+
+/* MDIO protocol type */
+enum al_eth_mdio_type {
+	AL_ETH_MDIO_TYPE_CLAUSE_22 = 0,
+	AL_ETH_MDIO_TYPE_CLAUSE_45 = 1
+};
+
+/* flow control mode */
+enum al_eth_flow_control_type {
+	AL_ETH_FLOW_CONTROL_TYPE_LINK_PAUSE,
+	AL_ETH_FLOW_CONTROL_TYPE_PFC
+};
+
+/* Tx to Rx switching decision type */
+enum al_eth_tx_switch_dec_type {
+	AL_ETH_TX_SWITCH_TYPE_MAC = 0,
+	AL_ETH_TX_SWITCH_TYPE_VLAN_TABLE = 1,
+	AL_ETH_TX_SWITCH_TYPE_VLAN_TABLE_AND_MAC = 2,
+	AL_ETH_TX_SWITCH_TYPE_BITMAP = 3
+};
+
+/* Tx to Rx VLAN ID selection type */
+enum al_eth_tx_switch_vid_sel_type {
+	AL_ETH_TX_SWITCH_VID_SEL_TYPE_VLAN1 = 0,
+	AL_ETH_TX_SWITCH_VID_SEL_TYPE_VLAN2 = 1,
+	AL_ETH_TX_SWITCH_VID_SEL_TYPE_NEW_VLAN1 = 2,
+	AL_ETH_TX_SWITCH_VID_SEL_TYPE_NEW_VLAN2 = 3,
+	AL_ETH_TX_SWITCH_VID_SEL_TYPE_DEFAULT_VLAN1 = 4,
+	AL_ETH_TX_SWITCH_VID_SEL_TYPE_FINAL_VLAN1 = 5
+};
+
+/*
+ * Rx descriptor configurations
+ * Note: when selecting rx descriptor field to inner packet, then that field
+ * will be set according to inner packet when packet is tunneled, for non-tunneled
+ * packets, the field will be set according to the packets header
+ */
+
+/* selection of the LRO_context_value result in the Metadata */
+enum al_eth_rx_desc_lro_context_val_res {
+	AL_ETH_LRO_CONTEXT_VALUE = 0,	/* LRO_context_value */
+	AL_ETH_L4_OFFSET = 1,		/* L4_offset */
+};
+
+/* selection of the L4 offset in the Metadata */
+enum al_eth_rx_desc_l4_offset_sel {
+	AL_ETH_L4_OFFSET_OUTER = 0, /* set L4 offset of the outer packet */
+	AL_ETH_L4_OFFSET_INNER = 1, /* set L4 offset of the inner packet */
+};
+
+/* selection of the L4 checksum result in the Metadata */
+enum al_eth_rx_desc_l4_chk_res_sel {
+	AL_ETH_L4_INNER_CHK = 0, /* L4 checksum */
+	/* Logic AND between outer and inner L4 checksum result */
+	AL_ETH_L4_INNER_OUTER_CHK = 1,
+};
+
+/* selection of the L3 checksum result in the Metadata */
+enum al_eth_rx_desc_l3_chk_res_sel {
+	AL_ETH_L3_CHK_TYPE_0 = 0, /* L3 checksum */
+	/* L3 checksum or RoCE/FCoE CRC, based on outer header */
+	AL_ETH_L3_CHK_TYPE_1 = 1,
+	/*
+	 * If tunnel exist = 0, L3 checksum or RoCE/FCoE CRC, based on outer
+	 * header. Else, logic AND between outer L3 checksum (Ipv4) and inner
+	 * CRC (RoCE or FcoE)
+	 */
+	AL_ETH_L3_CHK_TYPE_2 = 2,
+	/*
+	 * combination of the L3 checksum result and CRC result,based on the
+	 * checksum and RoCE/FCoE CRC input selections.
+	 */
+	AL_ETH_L3_CHK_TYPE_3 = 3,
+};
+
+/* selection of the L3 protocol index in the Metadata */
+enum al_eth_rx_desc_l3_proto_idx_sel {
+	AL_ETH_L3_PROTO_IDX_OUTER = 0, /* set L3 proto index of the outer packet */
+	AL_ETH_L3_PROTO_IDX_INNER = 1, /* set L3 proto index of the inner packet */
+};
+
+/* selection of the L3 offset in the Metadata */
+enum al_eth_rx_desc_l3_offset_sel {
+	AL_ETH_L3_OFFSET_OUTER = 0, /* set L3 offset of the outer packet */
+	AL_ETH_L3_OFFSET_INNER = 1, /* set L3 offset of the inner packet */
+};
+
+/* selection of the L4 protocol index in the Metadata */
+enum al_eth_rx_desc_l4_proto_idx_sel {
+	AL_ETH_L4_PROTO_IDX_OUTER = 0, /* set L4 proto index of the outer packet */
+	AL_ETH_L4_PROTO_IDX_INNER = 1, /* set L4 proto index of the inner packet */
+};
+
+/* selection of the frag indication in the Metadata */
+enum al_eth_rx_desc_frag_sel {
+	AL_ETH_FRAG_OUTER = 0, /* set frag of the outer packet */
+	AL_ETH_FRAG_INNER = 1, /* set frag of the inner packet */
+};
+
+/* Ethernet Rx completion descriptor */
+struct al_eth_rx_cdesc {
+	u32 ctrl_meta;
+	u32 len;
+	u32 word2;
+	u32 word3;
+};
+
+/* Flow Contol parameters */
+struct al_eth_flow_control_params{
+	enum al_eth_flow_control_type type; /* flow control type */
+	bool		obay_enable; /* stop tx when pause received */
+	bool		gen_enable; /* generate pause frames */
+	u16	rx_fifo_th_high;
+	u16	rx_fifo_th_low;
+	u16	quanta;
+	u16	quanta_th;
+	/*
+	 * For each UDMA, defines the mapping between
+	 * PFC priority and queues(in bit mask).
+	 * same mapping used for obay and generation.
+	 * for example:
+	 * if prio_q_map[1][7] = 0xC, then TX queues 2
+	 * and 3 of UDMA 1 will be stopped when pause
+	 * received with priority 7, also, when RX queues
+	 * 2 and 3 of UDMA 1 become almost full, then
+	 * pause frame with priority 7 will be sent.
+	 *
+	 * note:
+	 * 1) if specific a queue is not used, the caller must
+	 * make set the prio_q_map to 0 otherwise that queue
+	 * will make the controller keep sending PAUSE packets.
+	 * 2) queues of unused UDMA must be treated as above.
+	 * 3) when working in LINK PAUSE mode, only entries at
+	 * priority 0 will be considered.
+	 */
+	u8	prio_q_map[4][8];
+};
+
+/* Packet Tx flags */
+#define AL_ETH_TX_FLAGS_TSO		BIT(7)  /* Enable TCP/UDP segmentation offloading */
+#define AL_ETH_TX_FLAGS_IPV4_L3_CSUM	BIT(13) /* Enable IPv4 header checksum calculation */
+#define AL_ETH_TX_FLAGS_L4_CSUM		BIT(14) /* Enable TCP/UDP checksum calculation */
+#define AL_ETH_TX_FLAGS_L4_PARTIAL_CSUM	BIT(17) /* L4 partial checksum calculation */
+#define AL_ETH_TX_FLAGS_L2_MACSEC_PKT	BIT(16) /* L2 Packet type 802_3 or 802_3_MACSEC, V2 */
+#define AL_ETH_TX_FLAGS_L2_DIS_FCS	BIT(15) /* Disable CRC calculation*/
+#define AL_ETH_TX_FLAGS_TS		BIT(21) /* Timestamp the packet */
+
+#define AL_ETH_TX_FLAGS_INT		AL_M2S_DESC_INT_EN
+#define AL_ETH_TX_FLAGS_NO_SNOOP	AL_M2S_DESC_NO_SNOOP_H
+
+/* this structure used for tx packet meta data */
+struct al_eth_meta_data{
+	u8 store :1; /* store the meta into the queues cache */
+	u8 words_valid :4; /* valid bit per word */
+
+	u8 vlan1_cfi_sel:2;
+	u8 vlan2_vid_sel:2;
+	u8 vlan2_cfi_sel:2;
+	u8 vlan2_pbits_sel:2;
+	u8 vlan2_ether_sel:2;
+
+	u16 vlan1_new_vid:12;
+	u8 vlan1_new_cfi :1;
+	u8 vlan1_new_pbits :3;
+	u16 vlan2_new_vid:12;
+	u8 vlan2_new_cfi :1;
+	u8 vlan2_new_pbits :3;
+
+	u8 l3_header_len; /* in bytes */
+	u8 l3_header_offset;
+	u8 l4_header_len; /* in words(32-bits) */
+
+	/* rev 0 specific */
+	u8 mss_idx_sel:3; /* for TSO, select the register that holds the MSS */
+
+	/* rev 1 specific */
+	u8 ts_index:4; /* index of regiser where to store the tx timestamp */
+	u16 mss_val :14; /* for TSO, set the mss value */
+	u8 outer_l3_offset; /* for tunneling mode. up to 64 bytes */
+	u8 outer_l3_len; /* for tunneling mode. up to 128 bytes */
+};
+
+/* Packet Rx flags when adding buffer to receive queue */
+
+/*
+ * Target-ID to be assigned to the packet descriptors
+ * Requires Target-ID in descriptor to be enabled for the specific UDMA
+ * queue.
+ */
+#define AL_ETH_RX_FLAGS_TGTID_MASK	GENMASK(15, 0)
+#define AL_ETH_RX_FLAGS_INT		AL_M2S_DESC_INT_EN
+
+/* Packet Rx flags set by HW when receiving packet */
+#define AL_ETH_RX_ERROR			BIT(16) /* layer 2 errors (FCS, bad len, etc) */
+#define AL_ETH_RX_FLAGS_L4_CSUM_ERR	BIT(14)
+#define AL_ETH_RX_FLAGS_L3_CSUM_ERR	BIT(13)
+
+/* Packet Rx flags - word 3 in Rx completion descriptor */
+
+/* packet structure. used for packet transmission and reception */
+struct al_eth_pkt {
+	u32 flags; /* see flags above, depends on context(tx or rx) */
+	enum AL_ETH_PROTO_ID l3_proto_idx;
+	enum AL_ETH_PROTO_ID l4_proto_idx;
+	u8 source_vlan_count:2;
+	u8 vlan_mod_add_count:2;
+	u8 vlan_mod_del_count:2;
+	u8 vlan_mod_v1_ether_sel:2;
+	u8 vlan_mod_v1_vid_sel:2;
+	u8 vlan_mod_v1_pbits_sel:2;
+
+	/* rev 1 specific */
+	enum AL_ETH_TX_TUNNEL_MODE tunnel_mode;
+	enum AL_ETH_PROTO_ID outer_l3_proto_idx; /* for tunneling mode */
+
+	/*
+	 * Target-ID to be assigned to the packet descriptors
+	 * Requires Target-ID in descriptor to be enabled for the specific UDMA
+	 * queue.
+	 */
+	u16 tgtid;
+
+	u32 rx_header_len; /* header buffer length of rx packet, not used */
+	struct al_eth_meta_data *meta; /* if null, then no meta added */
+	u16 rxhash;
+	u16 l3_offset;
+
+	u8 num_of_bufs;
+	struct al_buf bufs[AL_ETH_PKT_MAX_BUFS];
+};
+
+struct al_ec_regs;
+
+/* Ethernet Adapter private data structure used by this driver */
+struct al_hw_eth_adapter {
+	u8 rev_id; /* PCI adapter revision ID */
+	u8 udma_id; /* the id of the UDMA used by this adapter */
+
+	struct net_device *netdev;
+
+	struct unit_regs __iomem *unit_regs;
+	void __iomem *udma_regs_base;
+	struct al_ec_regs __iomem *ec_regs_base;
+	void __iomem *ec_ints_base;
+	struct al_eth_mac_regs __iomem *mac_regs_base;
+	struct interrupt_controller_ctrl __iomem *mac_ints_base;
+
+	char *name; /* the upper layer must keep the string area */
+
+	struct al_udma tx_udma;
+	struct al_udma rx_udma;
+
+	u8 enable_rx_parser; /* config and enable rx parsing */
+
+	enum al_eth_flow_control_type fc_type; /* flow control*/
+
+	enum al_eth_mac_mode mac_mode;
+	enum al_eth_mdio_if	mdio_if; /* which mac mdio interface to use */
+	enum al_eth_mdio_type mdio_type; /* mdio protocol type */
+	bool shared_mdio_if; /* when true, the mdio interface is shared with other controllers.*/
+	u8 curr_lt_unit;
+};
+
+/* parameters from upper layer */
+struct al_eth_adapter_params {
+	u8 rev_id; /* PCI adapter revision ID */
+	u8 udma_id; /* the id of the UDMA used by this adapter */
+	struct net_device *netdev;
+	u8 enable_rx_parser; /* when true, the rx epe parser will be enabled */
+	void __iomem *udma_regs_base; /* UDMA register base address */
+	void __iomem *ec_regs_base;
+	void __iomem *mac_regs_base;
+	char *name; /* the upper layer must keep the string area */
+};
+
+/*
+ * initialize the ethernet adapter's DMA
+ * - initialize the adapter data structure
+ * - initialize the Tx and Rx UDMA
+ * - enable the Tx and Rx UDMA, the rings will be still disabled at this point.
+ *
+ * @param adapter pointer to the private structure
+ * @param params the parameters passed from upper layer
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_adapter_init(struct al_hw_eth_adapter *adapter, struct al_eth_adapter_params *params);
+
+/*
+ * stop the DMA of the ethernet adapter
+ *
+ * @param adapter pointer to the private structure
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_adapter_stop(struct al_hw_eth_adapter *adapter);
+
+/*
+ * Configure and enable a queue ring
+ *
+ * @param adapter pointer to the private structure
+ * @param type tx or rx
+ * @param qid queue index
+ * @param q_params queue parameters
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_queue_config(struct al_hw_eth_adapter *adapter, enum al_udma_type type, u32 qid,
+			struct al_udma_q_params *q_params);
+
+/* MAC layer */
+
+/*
+ * configure the mac media type.
+ * this function only sets the mode, but not the speed as certain mac modes
+ * support multiple speeds as will be negotiated by the link layer.
+ * @param adapter pointer to the private structure.
+ * @param mode media mode
+ *
+ * @return 0 on success. negative errno on failure.
+ */
+int al_eth_mac_config(struct al_hw_eth_adapter *adapter, enum al_eth_mac_mode mode);
+
+/*
+ * stop the mac tx and rx paths.
+ * @param adapter pointer to the private structure.
+ *
+ * @return 0 on success. negative error on failure.
+ */
+int al_eth_mac_stop(struct al_hw_eth_adapter *adapter);
+
+/*
+ * start the mac tx and rx paths.
+ * @param adapter pointer to the private structure.
+ *
+ * @return 0 on success. negative error on failure.
+ */
+int al_eth_mac_start(struct al_hw_eth_adapter *adapter);
+
+/*
+ * Perform gearbox reset for tx lanes And/Or Rx lanes.
+ * applicable only when the controller is connected to srds25G.
+ * This reset should be performed after each operation that changes the clocks
+ *
+ * @param adapter pointer to the private structure.
+ * @param tx_reset assert and de-assert reset for tx lanes
+ * @param rx_reset assert and de-assert reset for rx lanes
+ */
+void al_eth_gearbox_reset(struct al_hw_eth_adapter *adapter, bool tx_reset, bool rx_reset);
+
+/*
+ * update link auto negotiation speed and duplex mode
+ * this function assumes the mac mode already set using the al_eth_mac_config()
+ * function.
+ *
+ * @param adapter pointer to the private structure
+ * @param force_1000_base_x set to true to force the mac to work on 1000baseX
+ *	  (not relevant to RGMII)
+ * @param an_enable set to true to enable auto negotiation
+ *	  (not relevant to RGMII)
+ * @param speed in mega bits, e.g 1000 stands for 1Gbps (relevant only in case
+ *	  an_enable is false)
+ * @param full_duplex set to true to enable full duplex mode (relevant only
+ *	  in case an_enable is false)
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_mac_link_config(struct al_hw_eth_adapter *adapter,
+			   bool force_1000_base_x,
+			   bool an_enable,
+			   u32 speed,
+			   bool full_duplex);
+
+/*
+ * configure minimum and maximum rx packet length
+ *
+ * @param adapter pointer to the private structure
+ * @param min_rx_len minimum rx packet length
+ * @param max_rx_len maximum rx packet length
+ * both length limits in bytes and it includes the MAC Layer header and FCS.
+ * @return 0 on success, otherwise on failure.
+ */
+int al_eth_rx_pkt_limit_config(struct al_hw_eth_adapter *adapter, u32 min_rx_len, u32 max_rx_len);
+
+/* Reference clock frequency (platform specific) */
+enum al_eth_ref_clk_freq {
+	AL_ETH_REF_FREQ_375_MHZ		= 0,
+	AL_ETH_REF_FREQ_187_5_MHZ	= 1,
+	AL_ETH_REF_FREQ_250_MHZ		= 2,
+	AL_ETH_REF_FREQ_500_MHZ		= 3,
+	AL_ETH_REF_FREQ_428_MHZ         = 4,
+};
+
+/*
+ * configure the MDIO hardware interface
+ * @param adapter pointer to the private structure
+ * @param mdio_type clause type
+ * @param shared_mdio_if set to true if multiple controllers using the same
+ * @param ref_clk_freq reference clock frequency
+ * @param mdio_clk_freq_khz the required MDC/MDIO clock frequency [Khz]
+ * MDIO pins of the chip.
+ *
+ * @return 0 on success, otherwise on failure.
+ */
+int al_eth_mdio_config(struct al_hw_eth_adapter *adapter,
+		       enum al_eth_mdio_type mdio_type,
+		       bool shared_mdio_if,
+		       enum al_eth_ref_clk_freq ref_clk_freq,
+		       unsigned int mdio_clk_freq_khz);
+
+/*
+ * read mdio register
+ * this function uses polling mode, and as the mdio is slow interface, it might
+ * block the cpu for long time (milliseconds).
+ * @param adapter pointer to the private structure
+ * @param phy_addr address of mdio phy
+ * @param device address of mdio device (used only in CLAUSE 45)
+ * @param reg index of the register
+ * @param val pointer for read value of the register
+ *
+ * @return 0 on success, negative errno on failure
+ */
+int al_eth_mdio_read(struct al_hw_eth_adapter *adapter, u32 phy_addr,
+		     u32 device, u32 reg, u16 *val);
+
+/*
+ * write mdio register
+ * this function uses polling mode, and as the mdio is slow interface, it might
+ * block the cpu for long time (milliseconds).
+ * @param adapter pointer to the private structure
+ * @param phy_addr address of mdio phy
+ * @param device address of mdio device (used only in CLAUSE 45)
+ * @param reg index of the register
+ * @param val value to write
+ *
+ * @return 0 on success, negative errno on failure
+ */
+int al_eth_mdio_write(struct al_hw_eth_adapter *adapter, u32 phy_addr,
+		      u32 device, u32 reg, u16 val);
+
+/*
+ * prepare packet descriptors in tx queue.
+ *
+ * This functions prepares the descriptors for the given packet in the tx
+ * submission ring. the caller must call al_eth_tx_pkt_action() below
+ * in order to notify the hardware about the new descriptors.
+ *
+ * @param tx_dma_q pointer to UDMA tx queue
+ * @param pkt the packet to transmit
+ *
+ * @return number of descriptors used for this packet, 0 if no free
+ * room in the descriptors ring
+ */
+int al_eth_tx_pkt_prepare(struct al_hw_eth_adapter *adapter,
+			  struct al_udma_q *tx_dma_q, struct al_eth_pkt *pkt);
+
+/*
+ * Trigger the DMA about previously added tx descriptors.
+ *
+ * @param tx_dma_q pointer to UDMA tx queue
+ * @param tx_descs number of descriptors to notify the DMA about.
+ * the tx_descs can be sum of descriptor numbers of multiple prepared packets,
+ * this way the caller can use this function to notify the DMA about multiple
+ * packets.
+ */
+void al_eth_tx_dma_action(struct al_udma_q *tx_dma_q, u32 tx_descs);
+
+/*
+ * get number of completed tx descriptors, upper layer should derive from
+ * this information which packets were completed.
+ *
+ * @param tx_dma_q pointer to UDMA tx queue
+ *
+ * @return number of completed tx descriptors.
+ */
+int al_eth_comp_tx_get(struct al_hw_eth_adapter *adapter,
+		       struct al_udma_q *tx_dma_q);
+
+/*
+ * add buffer to receive queue
+ *
+ * @param rx_dma_q pointer to UDMA rx queue
+ * @param buf pointer to data buffer
+ * @param flags bitwise of AL_ETH_RX_FLAGS
+ * @param header_buf this is not used for far and header_buf should be set to
+ * NULL.
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_rx_buffer_add(struct al_hw_eth_adapter *adapter,
+			 struct al_udma_q *rx_dma_q, struct al_buf *buf,
+			 u32 flags, struct al_buf *header_buf);
+
+/*
+ * notify the hw engine about rx descriptors that were added to the receive queue
+ *
+ * @param rx_dma_q pointer to UDMA rx queue
+ * @param descs_num number of rx descriptors
+ */
+void al_eth_rx_buffer_action(struct al_hw_eth_adapter *adapter,
+			     struct al_udma_q *rx_dma_q, u32 descs_num);
+
+/*
+ * get packet from RX completion ring
+ *
+ * @param rx_dma_q pointer to UDMA rx queue
+ * @param pkt pointer to a packet data structure, this function fills this
+ * structure with the information about the received packet. the buffers
+ * structures filled only with the length of the data written into the buffer,
+ * the address fields are not updated as the upper layer can retrieve this
+ * information by itself because the hardware uses the buffers in the same order
+ * were those buffers inserted into the ring of the receive queue.
+ * this structure should be allocated by the caller function.
+ *
+ * @return return number of descriptors or 0 if no completed packet found.
+ */
+u32 al_eth_pkt_rx(struct al_hw_eth_adapter *adapter, struct al_udma_q *rx_dma_q,
+		  struct al_eth_pkt *pkt);
+
+/* RX parser table */
+struct al_eth_epe_p_reg_entry {
+	u32 data;
+	u32 mask;
+	u32 ctrl;
+};
+
+struct al_eth_epe_control_entry {
+	u32 data[6];
+};
+
+/* Flow Steering and filtering */
+int al_eth_thash_table_set(struct al_hw_eth_adapter *adapter, u32 idx, u8 udma, u32 queue);
+
+/*
+ * FSM table has 7 bits input address:
+ *  bits[2:0] are the outer packet's type (IPv4, TCP...)
+ *  bits[5:3] are the inner packet's type
+ *  bit[6] is set when packet is tunneled.
+ *
+ * The output of each entry:
+ *  bits[1:0] - input selection: selects the input for the thash (2/4 tuple, inner/outer)
+ *  bit[2] - selects whether to use thash output, or default values for the queue and udma
+ *  bits[6:3] default UDMA mask: the UDMAs to select when bit 2 above was unset
+ *  bits[9:5] defualt queue: the queue index to select when bit 2 above was unset
+ */
+
+#define AL_ETH_FSM_ENTRY_IPV4_TCP	   0
+#define AL_ETH_FSM_ENTRY_IPV4_UDP	   1
+#define AL_ETH_FSM_ENTRY_IPV6_TCP	   2
+#define AL_ETH_FSM_ENTRY_IPV6_UDP	   3
+#define AL_ETH_FSM_ENTRY_IPV6_NO_UDP_TCP   4
+#define AL_ETH_FSM_ENTRY_IPV4_NO_UDP_TCP   5
+
+#define AL_ETH_FSM_ENTRY_OUTER(idx)	   ((idx) & 7)
+
+/* FSM DATA format */
+#define AL_ETH_FSM_DATA_OUTER_2_TUPLE	0
+#define AL_ETH_FSM_DATA_OUTER_4_TUPLE	1
+
+#define AL_ETH_FSM_DATA_HASH_SEL	BIT(2)
+
+#define AL_ETH_FSM_DATA_DEFAULT_Q_SHIFT		5
+#define AL_ETH_FSM_DATA_DEFAULT_UDMA_SHIFT	3
+
+/* set fsm table entry */
+int al_eth_fsm_table_set(struct al_hw_eth_adapter *adapter, u32 idx, u32 entry);
+
+enum AL_ETH_FWD_CTRL_IDX_VLAN_TABLE_OUT {
+	AL_ETH_FWD_CTRL_IDX_VLAN_TABLE_OUT_0 = 0,
+	AL_ETH_FWD_CTRL_IDX_VLAN_TABLE_OUT_1 = 1,
+	AL_ETH_FWD_CTRL_IDX_VLAN_TABLE_OUT_ANY = 2,
+};
+
+enum AL_ETH_FWD_CTRL_IDX_TUNNEL {
+	AL_ETH_FWD_CTRL_IDX_TUNNEL_NOT_EXIST = 0,
+	AL_ETH_FWD_CTRL_IDX_TUNNEL_EXIST = 1,
+	AL_ETH_FWD_CTRL_IDX_TUNNEL_ANY = 2,
+};
+
+enum AL_ETH_FWD_CTRL_IDX_VLAN {
+	AL_ETH_FWD_CTRL_IDX_VLAN_NOT_EXIST = 0,
+	AL_ETH_FWD_CTRL_IDX_VLAN_EXIST = 1,
+	AL_ETH_FWD_CTRL_IDX_VLAN_ANY = 2,
+};
+
+enum AL_ETH_FWD_CTRL_IDX_MAC_TABLE {
+	AL_ETH_FWD_CTRL_IDX_MAC_TABLE_NO_MATCH = 0,
+	AL_ETH_FWD_CTRL_IDX_MAC_TABLE_MATCH = 1,
+	AL_ETH_FWD_CTRL_IDX_MAC_TABLE_ANY = 2,
+};
+
+enum AL_ETH_FWD_CTRL_IDX_MAC_DA_TYPE {
+	AL_ETH_FWD_CTRL_IDX_MAC_DA_TYPE_UC = 0, /* unicast */
+	AL_ETH_FWD_CTRL_IDX_MAC_DA_TYPE_MC = 1, /* multicast */
+	AL_ETH_FWD_CTRL_IDX_MAC_DA_TYPE_BC = 2, /* broadcast */
+	AL_ETH_FWD_CTRL_IDX_MAC_DA_TYPE_ANY = 4, /* for sw usage */
+};
+
+enum AL_ETH_CTRL_TABLE_PRIO_SEL {
+	AL_ETH_CTRL_TABLE_PRIO_SEL_PBITS_TABLE	= 0,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_DSCP_TABLE	= 1,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_TC_TABLE	= 2,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_REG1		= 3,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_REG2		= 4,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_REG3		= 5,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_REG4		= 6,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_REG5		= 7,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_REG6		= 7,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_REG7		= 9,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_REG8		= 10,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_VAL_3	= 11,
+	AL_ETH_CTRL_TABLE_PRIO_SEL_VAL_0	= 12,
+};
+
+/* where to select the initial queue from */
+enum AL_ETH_CTRL_TABLE_QUEUE_SEL_1 {
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_PRIO_TABLE	= 0,
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_THASH_TABLE	= 1,
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_MAC_TABLE		= 2,
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_MHASH_TABLE	= 3,
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_REG1		= 4,
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_REG2		= 5,
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_REG3		= 6,
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_REG4		= 7,
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_VAL_3		= 12,
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_1_VAL_0		= 13,
+};
+
+/* target queue will be built up from the priority and initial queue */
+enum AL_ETH_CTRL_TABLE_QUEUE_SEL_2 {
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_2_PRIO_TABLE	= 0, /* target queue is the output of priority table */
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_2_PRIO		= 1, /* target queue is the priority */
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_2_PRIO_QUEUE	= 2, /* target queue is initial queue[0], priority[1] */
+	AL_ETH_CTRL_TABLE_QUEUE_SEL_2_NO_PRIO		= 3, /* target queue is the initial */
+};
+
+enum AL_ETH_CTRL_TABLE_UDMA_SEL {
+	AL_ETH_CTRL_TABLE_UDMA_SEL_THASH_TABLE		= 0,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_THASH_AND_VLAN	= 1,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_VLAN_TABLE		= 2,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_VLAN_AND_MAC		= 3,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_MAC_TABLE		= 4,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_MAC_AND_MHASH	= 5,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_MHASH_TABLE		= 6,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_REG1			= 7,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_REG2			= 8,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_REG3			= 9,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_REG4			= 10,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_REG5			= 11,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_REG6			= 12,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_REG7			= 13,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_REG8			= 14,
+	AL_ETH_CTRL_TABLE_UDMA_SEL_VAL_0		= 15,
+};
+
+struct al_eth_fwd_ctrl_table_entry {
+	enum AL_ETH_CTRL_TABLE_PRIO_SEL prio_sel;
+	enum AL_ETH_CTRL_TABLE_QUEUE_SEL_1 queue_sel_1; /* queue id source */
+	enum AL_ETH_CTRL_TABLE_QUEUE_SEL_2 queue_sel_2; /* mix queue id with priority */
+	enum AL_ETH_CTRL_TABLE_UDMA_SEL udma_sel;
+	bool filter; /* set to true to enable filtering */
+};
+
+/*
+ * Configure default control table entry
+ *
+ * @param adapter pointer to the private structure
+ * @param use_table set to true if control table is used, when set to false
+ * then control table will be bypassed and the entry value will be used.
+ * @param entry defines the value to be used when bypassing control table.
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+void al_eth_ctrl_table_def_set(struct al_hw_eth_adapter *adapter,
+			       bool use_table,
+			       struct al_eth_fwd_ctrl_table_entry *entry);
+
+/*
+ * Configure hash key initial registers
+ * Those registers define the initial key values, those values used for
+ * the THASH and MHASH hash functions.
+ *
+ * @param adapter pointer to the private structure
+ * @param idx the register index
+ * @param val the register value
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+void al_eth_hash_key_set(struct al_hw_eth_adapter *adapter, u32 idx, u32 val);
+
+struct al_eth_fwd_mac_table_entry {
+	u8		addr[6]; /* byte 0 is the first byte seen on the wire */
+	u8		mask[6];
+	bool		tx_valid;
+	u8		tx_target;
+	bool		rx_valid;
+	u8		udma_mask; /* target udma */
+	u8		qid; /* target queue */
+	bool		filter; /* set to true to enable filtering */
+};
+
+/*
+ * Configure mac table entry
+ * The HW traverse this table and looks for match from lowest index,
+ * when the packets MAC DA & mask == addr, and the valid bit is set, then match occurs.
+ *
+ * @param adapter pointer to the private structure
+ * @param idx the entry index within the mac table.
+ * @param entry the contents of the MAC table entry
+ */
+void al_eth_fwd_mac_table_set(struct al_hw_eth_adapter *adapter, u32 idx,
+			      struct al_eth_fwd_mac_table_entry *entry);
+
+void al_eth_mac_addr_store(void * __iomem ec_base, u32 idx, u8 *addr);
+void al_eth_mac_addr_read(void * __iomem ec_base, u32 idx, u8 *addr);
+
+/*
+ * Configure pbits table entry
+ * The HW uses this table to translate between vlan pbits field to priority.
+ * The vlan pbits is used as the index of this table.
+ *
+ * @param adapter pointer to the private structure
+ * @param idx the entry index within the table.
+ * @param prio the priority to set for this entry
+ */
+void al_eth_fwd_pbits_table_set(struct al_hw_eth_adapter *adapter, u32 idx, u8 prio);
+
+/*
+ * Configure priority table entry
+ * The HW uses this table to translate between priority to queue index.
+ * The priority is used as the index of this table.
+ *
+ * @param adapter pointer to the private structure
+ * @param prio the entry index within the table.
+ * @param qid the queue index to set for this entry (priority).
+ */
+void al_eth_fwd_priority_table_set(struct al_hw_eth_adapter *adapter, u8 prio, u8 qid);
+
+/*
+ * Configure MAC HASH table entry
+ * The HW uses 8 bits from the hash result on the MAC DA as index to this table.
+ *
+ * @param adapter pointer to the private structure
+ * @param idx the entry index within the table.
+ * @param udma_mask the target udma to set for this entry.
+ * @param qid the target queue index to set for this entry.
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_fwd_mhash_table_set(struct al_hw_eth_adapter *adapter, u32 idx, u8 udma_mask, u8 qid);
+
+/* filter undetected MAC DA */
+#define AL_ETH_RFW_FILTER_UNDET_MAC          BIT(0)
+/* filter specific MAC DA based on MAC table output */
+#define AL_ETH_RFW_FILTER_DET_MAC            BIT(1)
+/* filter all tagged */
+#define AL_ETH_RFW_FILTER_TAGGED             BIT(2)
+/* filter all untagged */
+#define AL_ETH_RFW_FILTER_UNTAGGED           BIT(3)
+/* filter all broadcast */
+#define AL_ETH_RFW_FILTER_BC                 BIT(4)
+/* filter all multicast */
+#define AL_ETH_RFW_FILTER_MC                 BIT(5)
+/* filter packet based on parser drop */
+#define AL_ETH_RFW_FILTER_PARSE              BIT(6)
+/* filter packet based on VLAN table output */
+#define AL_ETH_RFW_FILTER_VLAN_VID           BIT(7)
+/* filter packet based on control table output */
+#define AL_ETH_RFW_FILTER_CTRL_TABLE         BIT(8)
+/* filter packet based on protocol index */
+#define AL_ETH_RFW_FILTER_PROT_INDEX         BIT(9)
+/* filter packet based on WoL decision */
+#define AL_ETH_RFW_FILTER_WOL		     BIT(10)
+
+struct al_eth_filter_params {
+	bool		enable;
+	u32	filters; /* bitmask of AL_ETH_RFW_FILTER.. for filters to enable */
+	bool		filter_proto[AL_ETH_PROTOCOLS_NUM]; /* set true for protocols to filter */
+};
+
+/*
+ * Configure the receive filters
+ * this function enables/disables filtering packets and which filtering
+ * types to apply.
+ * filters that indicated in tables (MAC table, VLAN and Control tables)
+ * are not configured by this function. This functions only enables/disables
+ * respecting the filter indication from those tables.
+ *
+ * @param adapter pointer to the private structure
+ * @param params the parameters passed from upper layer
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_filter_config(struct al_hw_eth_adapter *adapter, struct al_eth_filter_params *params);
+
+int al_eth_flow_control_config(struct al_hw_eth_adapter *adapter, struct al_eth_flow_control_params *params);
+
+/* enum for methods when updating systime using triggers */
+enum al_eth_pth_update_method {
+	AL_ETH_PTH_UPDATE_METHOD_SET = 0, /* Set the time in int/ext update time */
+	AL_ETH_PTH_UPDATE_METHOD_INC = 1, /* increment */
+	AL_ETH_PTH_UPDATE_METHOD_DEC = 2, /* decrement */
+	AL_ETH_PTH_UPDATE_METHOD_ADD_TO_LAST = 3, /* Set to last time + int/ext update time.*/
+};
+
+/* systime internal update trigger types */
+enum al_eth_pth_int_trig {
+	/* use output pulse as trigger */
+	AL_ETH_PTH_INT_TRIG_OUT_PULSE_0 = 0,
+	/* use the int update register write as a trigger */
+	AL_ETH_PTH_INT_TRIG_REG_WRITE = 1,
+};
+
+/* get statistics */
+struct al_eth_mac_stats {
+	/* sum the data and padding octets (i.e. without header and FCS) received with a valid frame. */
+	u64 aOctetsReceivedOK;
+	/* sum of Payload and padding octets of frames transmitted without error*/
+	u64 aOctetsTransmittedOK;
+	/* total number of packets received. Good and bad packets */
+	u32 etherStatsPkts;
+	/* number of received unicast packets */
+	u32 ifInUcastPkts;
+	/* number of received multicast packets */
+	u32 ifInMulticastPkts;
+	/* number of received broadcast packets */
+	u32 ifInBroadcastPkts;
+	/* Number of frames received with FIFO Overflow, CRC, Payload Length, Jabber and Oversized, Alignment or PHY/PCS error indication */
+	u32 ifInErrors;
+
+	/* number of transmitted unicast packets */
+	u32 ifOutUcastPkts;
+	/* number of transmitted multicast packets */
+	u32 ifOutMulticastPkts;
+	/* number of transmitted broadcast packets */
+	u32 ifOutBroadcastPkts;
+	/* number of frames transmitted with FIFO Overflow, FIFO Underflow or Controller indicated error */
+	u32 ifOutErrors;
+
+	/* number of Frame received without error (Including Pause Frames). */
+	u32 aFramesReceivedOK;
+	/* number of Frames transmitter without error (Including Pause Frames) */
+	u32 aFramesTransmittedOK;
+	/* number of packets received with less than 64 octets */
+	u32 etherStatsUndersizePkts;
+	/* Too short frames with CRC error, available only for RGMII and 1G Serial modes */
+	u32 etherStatsFragments;
+	/* Too long frames with CRC error */
+	u32 etherStatsJabbers;
+	/* packet that exceeds the valid maximum programmed frame length */
+	u32 etherStatsOversizePkts;
+	/* number of frames received with a CRC error */
+	u32 aFrameCheckSequenceErrors;
+	/* number of frames received with alignment error */
+	u32 aAlignmentErrors;
+	/* number of dropped packets due to FIFO overflow */
+	u32 etherStatsDropEvents;
+	/* number of transmitted pause frames. */
+	u32 aPAUSEMACCtrlFramesTransmitted;
+	/* number of received pause frames. */
+	u32 aPAUSEMACCtrlFramesReceived;
+	/* frame received exceeded the maximum length programmed with register FRM_LGTH, available only for 10G modes */
+	u32 aFrameTooLongErrors;
+	/*
+	 * Received frame with bad length/type (between 46 and 0x600 or less
+	 * than 46 for packets longer than 64), available only for 10G modes
+	 */
+	u32 aInRangeLengthErrors;
+	/* Valid VLAN tagged frames transmitted */
+	u32 VLANTransmittedOK;
+	/* Valid VLAN tagged frames received */
+	u32 VLANReceivedOK;
+	/* Total number of octets received. Good and bad packets */
+	u32 etherStatsOctets;
+
+	/* packets of 64 octets length is received (good and bad frames are counted) */
+	u32 etherStatsPkts64Octets;
+	/* Frames (good and bad) with 65 to 127 octets */
+	u32 etherStatsPkts65to127Octets;
+	/* Frames (good and bad) with 128 to 255 octets */
+	u32 etherStatsPkts128to255Octets;
+	/* Frames (good and bad) with 256 to 511 octets */
+	u32 etherStatsPkts256to511Octets;
+	/* Frames (good and bad) with 512 to 1023 octets */
+	u32 etherStatsPkts512to1023Octets;
+	/* Frames (good and bad) with 1024 to 1518 octets */
+	u32 etherStatsPkts1024to1518Octets;
+	/* frames with 1519 bytes to the maximum length programmed in the register FRAME_LENGTH. */
+	u32 etherStatsPkts1519toX;
+
+	u32 eee_in;
+	u32 eee_out;
+};
+
+/*
+ * perform Function Level Reset RMN
+ *
+ * Addressing RMN: 714
+ *
+ * @param pci_read_config_u32 pointer to function that reads register from pci header
+ * @param pci_write_config_u32 pointer to function that writes register from pci header
+ * @param handle pointer passes to the above functions as first parameter
+ * @param mac_base base address of the MAC registers
+ *
+ * @return 0.
+ */
+int al_eth_flr_rmn(int (*pci_read_config_u32)(void *handle, int where, u32 *val),
+		   int (*pci_write_config_u32)(void *handle, int where, u32 val),
+		   void *handle, void __iomem	*mac_base);
+
+enum al_eth_board_media_type {
+	AL_ETH_BOARD_MEDIA_TYPE_AUTO_DETECT		= 0,
+	AL_ETH_BOARD_MEDIA_TYPE_RGMII			= 1,
+	AL_ETH_BOARD_MEDIA_TYPE_10GBASE_SR		= 2,
+	AL_ETH_BOARD_MEDIA_TYPE_SGMII			= 3,
+	AL_ETH_BOARD_MEDIA_TYPE_1000BASE_X		= 4,
+	AL_ETH_BOARD_MEDIA_TYPE_AUTO_DETECT_AUTO_SPEED	= 5,
+	AL_ETH_BOARD_MEDIA_TYPE_SGMII_2_5G		= 6,
+	AL_ETH_BOARD_MEDIA_TYPE_NBASE_T			= 7,
+	AL_ETH_BOARD_MEDIA_TYPE_25G			= 8,
+};
+
+enum al_eth_board_mdio_freq {
+	AL_ETH_BOARD_MDIO_FREQ_2_5_MHZ	= 0,
+	AL_ETH_BOARD_MDIO_FREQ_1_MHZ	= 1,
+};
+
+enum al_eth_board_ext_phy_if {
+	AL_ETH_BOARD_PHY_IF_MDIO	= 0,
+	AL_ETH_BOARD_PHY_IF_XMDIO	= 1,
+	AL_ETH_BOARD_PHY_IF_I2C		= 2,
+
+};
+
+enum al_eth_board_auto_neg_mode {
+	AL_ETH_BOARD_AUTONEG_OUT_OF_BAND	= 0,
+	AL_ETH_BOARD_AUTONEG_IN_BAND		= 1,
+
+};
+
+/* declare the 1G mac active speed when auto negotiation disabled */
+enum al_eth_board_1g_speed {
+	AL_ETH_BOARD_1G_SPEED_1000M		= 0,
+	AL_ETH_BOARD_1G_SPEED_100M		= 1,
+	AL_ETH_BOARD_1G_SPEED_10M		= 2,
+};
+
+enum al_eth_retimer_channel {
+	AL_ETH_RETIMER_CHANNEL_A		= 0,
+	AL_ETH_RETIMER_CHANNEL_B		= 1,
+	AL_ETH_RETIMER_CHANNEL_C		= 2,
+	AL_ETH_RETIMER_CHANNEL_D		= 3,
+	AL_ETH_RETIMER_CHANNEL_E		= 4,
+	AL_ETH_RETIMER_CHANNEL_F		= 5,
+	AL_ETH_RETIMER_CHANNEL_G		= 6,
+	AL_ETH_RETIMER_CHANNEL_H		= 7,
+	AL_ETH_RETIMER_CHANNEL_MAX		= 8
+};
+
+/* list of supported retimers */
+enum al_eth_retimer_type {
+	AL_ETH_RETIMER_BR_210			= 0,
+	AL_ETH_RETIMER_BR_410			= 1,
+	AL_ETH_RETIMER_DS_25			= 2,
+	AL_ETH_RETIMER_TYPE_MAX			= 4,
+};
+
+/*
+ * Structure represents the board information. this info set by boot loader
+ * and read by OS driver.
+ */
+struct al_eth_board_params {
+	enum al_eth_board_media_type	media_type;
+	bool		phy_exist; /* external phy exist */
+	u8		phy_mdio_addr; /* mdio address of external phy */
+	bool		sfp_plus_module_exist; /* SFP+ module connected */
+	bool		autoneg_enable; /* enable Auto-Negotiation */
+	bool		kr_lt_enable; /* enable KR Link-Training */
+	bool		kr_fec_enable; /* enable KR FEC */
+	enum al_eth_board_mdio_freq	mdio_freq; /* MDIO frequency */
+	u8		i2c_adapter_id; /* identifier for the i2c adapter to use to access SFP+ module */
+	enum al_eth_board_ext_phy_if	phy_if; /* phy interface */
+	enum al_eth_board_auto_neg_mode	an_mode; /* auto-negotiation mode (in-band / out-of-band) */
+	enum al_eth_ref_clk_freq	ref_clk_freq; /* reference clock frequency */
+	bool		force_1000_base_x; /* set mac to 1000 base-x mode (instead sgmii) */
+	bool		an_disable; /* disable auto negotiation */
+	enum al_eth_board_1g_speed	speed; /* port speed if AN disabled */
+	bool		half_duplex; /* force half duplex if AN disabled */
+	bool		fc_disable; /* disable flow control */
+	bool		retimer_exist; /* retimer is exist on the board */
+	u8		retimer_bus_id; /* in what i2c bus the retimer is on */
+	u8		retimer_i2c_addr; /* i2c address of the retimer */
+	enum al_eth_retimer_channel retimer_channel; /* what channel connected to this port (Rx) */
+	bool		dac; /* assume direct attached cable is connected if auto detect is off or failed */
+	u8		dac_len; /* assume this cable length if auto detect is off or failed  */
+	enum al_eth_retimer_type retimer_type; /* the type of the specific retimer */
+	enum al_eth_retimer_channel retimer_tx_channel; /* what channel connected to this port (Tx) */
+	u8		gpio_sfp_present; /* gpio number of sfp present for this port. 0 if not exist */
+};
+
+/*
+ * set board parameter of the eth port
+ * this function used to set the board parameters into scratchpad
+ * registers. those parameters can be read later by OS driver.
+ *
+ * @param mac_base the virtual address of the mac registers (PCI BAR 2)
+ * @param params pointer to structure the includes the parameters
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_board_params_set(void * __iomem mac_base, struct al_eth_board_params *params);
+
+/*
+ * get board parameter of the eth port
+ * this function used to get the board parameters from scratchpad
+ * registers.
+ *
+ * @param mac_base the virtual address of the mac registers (PCI BAR 2)
+ * @param params pointer to structure where the parameters will be stored.
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_board_params_get(void * __iomem mac_base, struct al_eth_board_params *params);
+
+/*
+ * Wake-On-Lan (WoL)
+ *
+ * The following few functions configure the Wake-On-Lan packet detection
+ * inside the Integrated Ethernet MAC.
+ *
+ * There are other alternative ways to set WoL, such using the
+ * external 1000Base-T transceiver to set WoL mode.
+ *
+ * These APIs do not set the system-wide power-state, nor responsible on the
+ * transition from Sleep to Normal power state.
+ *
+ * For system level considerations, please refer to Annapurna Labs Alpine Wiki.
+ */
+/* Interrupt enable WoL MAC DA Unicast detected  packet */
+#define AL_ETH_WOL_INT_UNICAST		BIT(0)
+/* Interrupt enable WoL L2 Multicast detected  packet */
+#define AL_ETH_WOL_INT_MULTICAST	BIT(1)
+/* Interrupt enable WoL L2 Broadcast detected  packet */
+#define AL_ETH_WOL_INT_BROADCAST	BIT(2)
+/* Interrupt enable WoL IPv4 detected  packet */
+#define AL_ETH_WOL_INT_IPV4		BIT(3)
+/* Interrupt enable WoL IPv6 detected  packet */
+#define AL_ETH_WOL_INT_IPV6		BIT(4)
+/* Interrupt enable WoL EtherType+MAC DA detected  packet */
+#define AL_ETH_WOL_INT_ETHERTYPE_DA	BIT(5)
+/* Interrupt enable WoL EtherType+L2 Broadcast detected  packet */
+#define AL_ETH_WOL_INT_ETHERTYPE_BC	BIT(6)
+/* Interrupt enable WoL parser detected  packet */
+/* Interrupt enable WoL magic detected  packet */
+#define AL_ETH_WOL_INT_MAGIC		BIT(8)
+/* Interrupt enable WoL magic+password detected  packet */
+#define AL_ETH_WOL_INT_MAGIC_PSWD	BIT(9)
+
+/* Forward enable WoL MAC DA Unicast detected  packet */
+#define AL_ETH_WOL_FWRD_UNICAST		BIT(0)
+/* Forward enable WoL L2 Multicast detected  packet */
+#define AL_ETH_WOL_FWRD_MULTICAST	BIT(1)
+/* Forward enable WoL L2 Broadcast detected  packet */
+#define AL_ETH_WOL_FWRD_BROADCAST	BIT(2)
+/* Forward enable WoL IPv4 detected  packet */
+/* Forward enable WoL IPv6 detected  packet */
+/* Forward enable WoL EtherType+MAC DA detected  packet */
+/* Forward enable WoL EtherType+L2 Broadcast detected  packet */
+/* Forward enable WoL parser detected  packet */
+
+struct al_eth_wol_params {
+	 /* 6 bytes array of destanation address for magic packet detection */
+	u8 *dest_addr;
+	u8 *pswd;	/* 6 bytes array of the password to use */
+	u8 *ipv4;
+	u8 *ipv6;
+	u16 ethr_type1; /* first ethertype to use */
+	u16 ethr_type2; /* secound ethertype to use */
+	/*
+	 * Bitmask of AL_ETH_WOL_FWRD_* of the packet types needed to be
+	 * forwarded.
+	 */
+	u16 forward_mask;
+	/*
+	 * Bitmask of AL_ETH_WOL_INT_* of the packet types that will send
+	 * interrupt to wake the system.
+	 */
+	u16 int_mask;
+};
+
+/*
+ * enable the wol mechanism
+ * set what type of packets will wake up the system and what type of packets
+ * neet to forward after the system is up
+ *
+ * beside this function wol filter also need to be set by
+ * calling al_eth_filter_config with AL_ETH_RFW_FILTER_WOL
+ *
+ * @param adapter pointer to the private structure
+ * @param wol the parameters needed to configure the wol
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_wol_enable(
+		struct al_hw_eth_adapter *adapter,
+		struct al_eth_wol_params *wol);
+
+/*
+ * Disable the WoL mechnism.
+ *
+ * @param adapter pointer to the private structure
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+int al_eth_wol_disable(
+		struct al_hw_eth_adapter *adapter);
+
+enum AL_ETH_TX_GCP_ALU_OPSEL {
+	AL_ETH_TX_GCP_ALU_L3_OFFSET			= 0,
+	AL_ETH_TX_GCP_ALU_OUTER_L3_OFFSET		= 1,
+	AL_ETH_TX_GCP_ALU_L3_LEN			= 2,
+	AL_ETH_TX_GCP_ALU_OUTER_L3_LEN			= 3,
+	AL_ETH_TX_GCP_ALU_L4_OFFSET			= 4,
+	AL_ETH_TX_GCP_ALU_L4_LEN			= 5,
+	AL_ETH_TX_GCP_ALU_TABLE_VAL			= 10
+};
+
+enum AL_ETH_RX_GCP_ALU_OPSEL {
+	AL_ETH_RX_GCP_ALU_OUTER_L3_OFFSET		= 0,
+	AL_ETH_RX_GCP_ALU_INNER_L3_OFFSET		= 1,
+	AL_ETH_RX_GCP_ALU_OUTER_L4_OFFSET		= 2,
+	AL_ETH_RX_GCP_ALU_INNER_L4_OFFSET		= 3,
+	AL_ETH_RX_GCP_ALU_OUTER_L3_HDR_LEN_LAT		= 4,
+	AL_ETH_RX_GCP_ALU_INNER_L3_HDR_LEN_LAT		= 5,
+	AL_ETH_RX_GCP_ALU_OUTER_L3_HDR_LEN_SEL		= 6,
+	AL_ETH_RX_GCP_ALU_INNER_L3_HDR_LEN_SEL		= 7,
+	AL_ETH_RX_GCP_ALU_PARSE_RESULT_VECTOR_OFFSET_1	= 8,
+	AL_ETH_RX_GCP_ALU_PARSE_RESULT_VECTOR_OFFSET_2	= 9,
+	AL_ETH_RX_GCP_ALU_TABLE_VAL			= 10
+};
+
+enum AL_ETH_ALU_OPCODE {
+	AL_ALU_FWD_A				= 0,
+	AL_ALU_ARITHMETIC_ADD			= 1,
+	AL_ALU_ARITHMETIC_SUBTRACT		= 2,
+	AL_ALU_BITWISE_AND			= 3,
+	AL_ALU_BITWISE_OR			= 4,
+	AL_ALU_SHIFT_RIGHT_A_BY_B		= 5,
+	AL_ALU_SHIFT_LEFT_A_BY_B		= 6,
+	AL_ALU_BITWISE_XOR			= 7,
+	AL_ALU_FWD_INV_A			= 16,
+	AL_ALU_ARITHMETIC_ADD_INV_A_AND_B	= 17,
+	AL_ALU_ARITHMETIC_SUBTRACT_INV_A_AND_B	= 18,
+	AL_ALU_BITWISE_AND_INV_A_AND_B		= 19,
+	AL_ALU_BITWISE_OR_INV_A_AND_B		= 20,
+	AL_ALU_SHIFT_RIGHT_INV_A_BY_B		= 21,
+	AL_ALU_SHIFT_LEFT_INV_A_BY_B		= 22,
+	AL_ALU_BITWISE_XOR_INV_A_AND_B		= 23,
+	AL_ALU_ARITHMETIC_ADD_A_AND_INV_B	= 33,
+	AL_ALU_ARITHMETIC_SUBTRACT_A_AND_INV_B	= 34,
+	AL_ALU_BITWISE_AND_A_AND_INV_B		= 35,
+	AL_ALU_BITWISE_OR_A_AND_INV_B		= 36,
+	AL_ALU_SHIFT_RIGHT_A_BY_INV_B		= 37,
+	AL_ALU_SHIFT_LEFT_A_BY_INV_B		= 38,
+	AL_ALU_BITWISE_XOR_A_AND_INV_B		= 39,
+	AL_ALU_ARITHMETIC_ADD_INV_A_AND_INV_B	= 49,
+	AL_ALU_ARITHMETIC_SUBTRACT_INV_A_AND	= 50,
+	AL_ALU_BITWISE_AND_INV_A_AND_INV_B	= 51,
+	AL_ALU_BITWISE_OR_INV_A_AND_INV_B	= 52,
+	AL_ALU_SHIFT_RIGHT_INV_A_BY_INV_B	= 53,
+	AL_ALU_SHIFT_LEFT_INV_A_BY_INV_B	= 54,
+	AL_ALU_BITWISE_XOR_INV_A_AND_INV_B	= 55,
+};
+
+#endif		/* __AL_HW_ETH_H__ */
diff --git a/drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h b/drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h
new file mode 100644
index 000000000000..c239ac1e8b6c
--- /dev/null
+++ b/drivers/net/ethernet/annapurna/al_hw_eth_ec_regs.h
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (C) 2017, Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __AL_HW_EC_REG_H
+#define __AL_HW_EC_REG_H
+
+struct al_ec_gen {
+	/*  Ethernet controller Version */
+	u32 version;
+	/*  Enable modules operation. */
+	u32 en;
+	/*  Enable FIFO operation on the EC side. */
+	u32 fifo_en;
+	/*  General L2 configuration for the Ethernet controlle */
+	u32 l2;
+	/*  Configure protocol index values */
+	u32 cfg_i;
+	/*  Configure protocol index values (extended protocols */
+	u32 cfg_i_ext;
+	/*  Enable modules operation (extended operations). */
+	u32 en_ext;
+	u32 rsrvd[9];
+};
+
+struct al_ec_mac {
+	/*  General configuration of the MAC side of the Ethern */
+	u32 gen;
+	/*  Minimum packet size  */
+	u32 min_pkt;
+	/*  Maximum packet size  */
+	u32 max_pkt;
+	u32 rsrvd[13];
+};
+
+struct al_ec_rxf {
+	/*  Rx FIFO input controller configuration 1 */
+	u32 cfg_1;
+	/*  Rx FIFO input controller configuration 2 */
+	u32 cfg_2;
+	/*  Threshold to start reading packet from the Rx FIFO */
+	u32 rd_fifo;
+	/*  Threshold to stop writing packet to the Rx FIFO */
+	u32 wr_fifo;
+	/*  Threshold to stop writing packet to the loopback FI */
+	u32 lb_fifo;
+	/*  Rx FIFO input controller loopback FIFO configuratio */
+	u32 cfg_lb;
+	/*  Configuration for dropping packet at the FIFO outpu */
+	u32 out_drop;
+	u32 rsrvd[25];
+};
+
+struct al_ec_epe {
+	/*  Ethernet parsing engine configuration 1 */
+	u32 parse_cfg;
+	/*  Protocol index action table address */
+	u32 act_table_addr;
+	/*  Protocol index action table data */
+	u32 act_table_data_1;
+	/*  Protocol index action table data */
+	u32 act_table_data_2;
+	/*  Protocol index action table data */
+	u32 act_table_data_3;
+	/*  Protocol index action table data */
+	u32 act_table_data_4;
+	/*  Protocol index action table data */
+	u32 act_table_data_5;
+	/*  Protocol index action table data */
+	u32 act_table_data_6;
+	/*  Input result vector, default values for parser inpu */
+	u32 res_def;
+	/*  Result input vector selection */
+	u32 res_in;
+	u32 rsrvd[6];
+};
+
+struct al_ec_epe_res {
+	/*  Parser result vector pointer */
+	u32 p1;
+	/*  Parser result vector pointer */
+	u32 p2;
+	/*  Parser result vector pointer */
+	u32 p3;
+	/*  Parser result vector pointer */
+	u32 p4;
+	/*  Parser result vector pointer */
+	u32 p5;
+	/*  Parser result vector pointer */
+	u32 p6;
+	/*  Parser result vector pointer */
+	u32 p7;
+	/*  Parser result vector pointer */
+	u32 p8;
+	/*  Parser result vector pointer */
+	u32 p9;
+	/*  Parser result vector pointer */
+	u32 p10;
+	/*  Parser result vector pointer */
+	u32 p11;
+	/*  Parser result vector pointer */
+	u32 p12;
+	/*  Parser result vector pointer */
+	u32 p13;
+	/*  Parser result vector pointer */
+	u32 p14;
+	/*  Parser result vector pointer */
+	u32 p15;
+	/*  Parser result vector pointer */
+	u32 p16;
+	/*  Parser result vector pointer */
+	u32 p17;
+	/*  Parser result vector pointer */
+	u32 p18;
+	/*  Parser result vector pointer */
+	u32 p19;
+	/*  Parser result vector pointer */
+	u32 p20;
+	u32 rsrvd[12];
+};
+
+struct al_ec_epe_h {
+	/*  Header length, support for header length table for  */
+	u32 hdr_len;
+};
+
+struct al_ec_epe_p {
+	/*  Data  for comparison */
+	u32 comp_data;
+	/*  Mask for comparison */
+	u32 comp_mask;
+	/*  Compare control */
+	u32 comp_ctrl;
+	u32 rsrvd[4];
+};
+
+struct al_ec_epe_a {
+	/*  Protocol index action register */
+	u32 prot_act;
+};
+
+struct al_ec_rfw {
+	/*  Tuple (4/2) Hash configuration */
+	u32 thash_cfg_1;
+	/*  Tuple (4/2) Hash configuration */
+	u32 thash_cfg_2;
+	/*  MAC Hash configuration */
+	u32 mhash_cfg_1;
+	/*  MAC Hash configuration */
+	u32 mhash_cfg_2;
+	/*  MAC Hash configuration */
+	u32 hdr_split;
+	/*  Masking the errors described in  register rxf_drop  */
+	u32 meta_err;
+	/*  Configuration for generating the MetaData for the R */
+	u32 meta;
+	/*  Configuration for generating the MetaData for the R */
+	u32 filter;
+	/*  4 tupple hash table address */
+	u32 thash_table_addr;
+	/*  4 tupple hash table data */
+	u32 thash_table_data;
+	/*  MAC hash table address */
+	u32 mhash_table_addr;
+	/*  MAC hash table data */
+	u32 mhash_table_data;
+	/*  VLAN table address */
+	u32 vid_table_addr;
+	/*  VLAN table data */
+	u32 vid_table_data;
+	/*  VLAN p-bits table address */
+	u32 pbits_table_addr;
+	/*  VLAN p-bits table data */
+	u32 pbits_table_data;
+	/*  DSCP table address */
+	u32 dscp_table_addr;
+	/*  DSCP table data */
+	u32 dscp_table_data;
+	/*  TC table address */
+	u32 tc_table_addr;
+	/*  TC table data */
+	u32 tc_table_data;
+	/*  Control table address */
+	u32 ctrl_table_addr;
+	/*  Control table data */
+	u32 ctrl_table_data;
+	/*  Forwarding output configuration */
+	u32 out_cfg;
+	/*  Flow steering mechanism, Table address */
+	u32 fsm_table_addr;
+	/*  Flow steering mechanism, Table data */
+	u32 fsm_table_data;
+	/*  Selection of data to be used in packet forwarding0  */
+	u32 ctrl_sel;
+	/*  Default VLAN data, used for untagged packets */
+	u32 default_vlan;
+	/*  Default HASH output values */
+	u32 default_hash;
+	/*  Default override values, if a packet was filtered b */
+	u32 default_or;
+	/*  Latched information when a drop condition occurred */
+	u32 drop_latch;
+	/*  Check sum calculation configuration */
+	u32 checksum;
+	/*  LRO offload engine configuration register */
+	u32 lro_cfg_1;
+	/*  LRO offload engine Check rules configurations for I */
+	u32 lro_check_ipv4;
+	/*  LRO offload engine IPv4 values configuration */
+	u32 lro_ipv4;
+	/*  LRO offload engine Check rules configurations for I */
+	u32 lro_check_ipv6;
+	/*  LRO offload engine IPv6 values configuration */
+	u32 lro_ipv6;
+	/*  LRO offload engine Check rules configurations for T */
+	u32 lro_check_tcp;
+	/*  LRO offload engine IPv6 values configuration */
+	u32 lro_tcp;
+	/*  LRO offload engine Check rules configurations for U */
+	u32 lro_check_udp;
+	/*  LRO offload engine Check rules configurations for U */
+	u32 lro_check_l2;
+	/*  LRO offload engine Check rules configurations for U */
+	u32 lro_check_gen;
+	/*  Rules for storing packet information into the cache */
+	u32 lro_store;
+	/*  VLAN table default */
+	u32 vid_table_def;
+	/*  Control table default */
+	u32 ctrl_table_def;
+	/*  Additional configuration 0 */
+	u32 cfg_a_0;
+	/*  Tuple (4/2) Hash configuration (extended for RoCE a */
+	u32 thash_cfg_3;
+	/*  Tuple (4/2) Hash configuration , mask for the input */
+	u32 thash_mask_outer_ipv6;
+	/*  Tuple (4/2) Hash configuration , mask for the input */
+	u32 thash_mask_outer;
+	/*  Tuple (4/2) Hash configuration , mask for the input */
+	u32 thash_mask_inner_ipv6;
+	/*  Tuple (4/2) Hash configuration , mask for the input */
+	u32 thash_mask_inner;
+	u32 rsrvd[10];
+};
+
+struct al_ec_rfw_udma {
+	/*  Per UDMA default configuration */
+	u32 def_cfg;
+};
+
+struct al_ec_rfw_hash {
+	/*  key configuration (320 bits) */
+	u32 key;
+};
+
+struct al_ec_rfw_priority {
+	/*  Priority to queue mapping configuration */
+	u32 queue;
+};
+
+struct al_ec_rfw_default {
+	/*  Default forwarding configuration options */
+	u32 opt_1;
+};
+
+struct al_ec_fwd_mac {
+	/*  MAC address data [31:0] */
+	u32 data_l;
+	/*  MAC address data [15:0] */
+	u32 data_h;
+	/*  MAC address mask [31:0] */
+	u32 mask_l;
+	/*  MAC address mask [15:0] */
+	u32 mask_h;
+	/*  MAC compare control */
+	u32 ctrl;
+};
+
+struct al_ec_msw {
+	/*  Configuration for unicast packets */
+	u32 uc;
+	/*  Configuration for multicast packets */
+	u32 mc;
+	/*  Configuration for broadcast packets */
+	u32 bc;
+	u32 rsrvd[3];
+};
+
+struct al_ec_tso {
+	/*  Input configuration */
+	u32 in_cfg;
+	/*  MetaData default cache table address */
+	u32 cache_table_addr;
+	/*  MetaData default cache table data */
+	u32 cache_table_data_1;
+	/*  MetaData default cache table data */
+	u32 cache_table_data_2;
+	/*  MetaData default cache table data */
+	u32 cache_table_data_3;
+	/*  MetaData default cache table data */
+	u32 cache_table_data_4;
+	/*  TCP control bit operation for first segment */
+	u32 ctrl_first;
+	/*  TCP control bit operation for middle segments  */
+	u32 ctrl_middle;
+	/*  TCP control bit operation for last segment */
+	u32 ctrl_last;
+	/*  Additional TSO configurations */
+	u32 cfg_add_0;
+	/*  TSO configuration for tunnelled packets */
+	u32 cfg_tunnel;
+	u32 rsrvd[13];
+};
+
+struct al_ec_tso_sel {
+	/*  MSS value */
+	u32 mss;
+};
+
+struct al_ec_tpe {
+	/*  Parsing configuration */
+	u32 parse;
+	u32 rsrvd[15];
+};
+
+struct al_ec_tpm_udma {
+	/*  Default VLAN data */
+	u32 vlan_data;
+	/*  UDMA MAC SA information for spoofing */
+	u32 mac_sa_1;
+	/*  UDMA MAC SA information for spoofing */
+	u32 mac_sa_2;
+};
+
+struct al_ec_tpm_sel {
+	/*  Ethertype values for VLAN modification */
+	u32 etype;
+};
+
+struct al_ec_tfw {
+	/*  Tx FIFO Wr configuration */
+	u32 tx_wr_fifo;
+	/*  VLAN table address */
+	u32 tx_vid_table_addr;
+	/*  VLAN table data */
+	u32 tx_vid_table_data;
+	/*  Tx FIFO Rd configuration */
+	u32 tx_rd_fifo;
+	/*  Tx FIFO Rd configuration, checksum insertion */
+	u32 tx_checksum;
+	/*  Tx forwarding general configuration register */
+	u32 tx_gen;
+	/*  Tx spoofing configuration */
+	u32 tx_spf;
+	/*  TX data FIFO status */
+	u32 data_fifo;
+	/*  Tx control FIFO status */
+	u32 ctrl_fifo;
+	/*  Tx header FIFO status */
+	u32 hdr_fifo;
+	u32 rsrvd[14];
+};
+
+struct al_ec_tfw_udma {
+	/*  Default GMDA output bitmap for unicast packet */
+	u32 uc_udma;
+	/*  Default GMDA output bitmap for multicast packet */
+	u32 mc_udma;
+	/*  Default GMDA output bitmap for broadcast packet */
+	u32 bc_udma;
+	/*  Tx spoofing configuration */
+	u32 spf_cmd;
+	/*  Forwarding decision control */
+	u32 fwd_dec;
+	u32 rsrvd;
+};
+
+struct al_ec_tmi {
+	/*  Forward packets back to the Rx data path for local  */
+	u32 tx_cfg;
+	u32 rsrvd[3];
+};
+
+struct al_ec_efc {
+	/*  Mask of pause_on  [7:0] for the Ethernet controller */
+	u32 ec_pause;
+	/*  Mask of Ethernet controller Almost Full indication  */
+	u32 ec_xoff;
+	/*  Mask for generating XON indication pulse */
+	u32 xon;
+	/*  Mask for generating GPIO output XOFF indication fro */
+	u32 gpio;
+	/*  Rx FIFO threshold for generating the Almost Full in */
+	u32 rx_fifo_af;
+	/*  Rx FIFO threshold for generating the Almost Full in */
+	u32 rx_fifo_hyst;
+	/*  Rx FIFO threshold for generating the Almost Full in */
+	u32 stat;
+	/*  XOFF timer for the 1G MACSets the interval (in SB_C */
+	u32 xoff_timer_1g;
+	/*  PFC force flow control generation */
+	u32 ec_pfc;
+	u32 rsrvd[3];
+};
+
+struct al_ec_fc_udma {
+	/*  Mask of "pause_on"  [0] for all queues */
+	u32 q_pause_0;
+	/*  Mask of "pause_on"  [1] for all queues */
+	u32 q_pause_1;
+	/*  Mask of "pause_on"  [2] for all queues */
+	u32 q_pause_2;
+	/*  Mask of "pause_on"  [3] for all queues */
+	u32 q_pause_3;
+	/*  Mask of "pause_on"  [4] for all queues */
+	u32 q_pause_4;
+	/*  Mask of "pause_on"  [5] for all queues */
+	u32 q_pause_5;
+	/*  Mask of "pause_on"  [6] for all queues */
+	u32 q_pause_6;
+	/*  Mask of "pause_on"  [7] for all queues */
+	u32 q_pause_7;
+	/*  Mask of external GPIO input pause [0] for all queue */
+	u32 q_gpio_0;
+	/*  Mask of external GPIO input pause [1] for all queue */
+	u32 q_gpio_1;
+	/*  Mask of external GPIO input pause [2] for all queue */
+	u32 q_gpio_2;
+	/*  Mask of external GPIO input pause [3] for all queue */
+	u32 q_gpio_3;
+	/*  Mask of external GPIO input [4] for all queues */
+	u32 q_gpio_4;
+	/*  Mask of external GPIO input [5] for all queues */
+	u32 q_gpio_5;
+	/*  Mask of external GPIO input [6] for all queues */
+	u32 q_gpio_6;
+	/*  Mask of external GPIO input [7] for all queues */
+	u32 q_gpio_7;
+	/*  Mask of "pause_on"  [7:0] for the UDMA stream inter */
+	u32 s_pause;
+	/*  Mask of Rx Almost Full indication for generating XO */
+	u32 q_xoff_0;
+	/*  Mask of Rx Almost Full indication for generating XO */
+	u32 q_xoff_1;
+	/*  Mask of Rx Almost Full indication for generating XO */
+	u32 q_xoff_2;
+	/*  Mask of Rx Almost Full indication for generating XO */
+	u32 q_xoff_3;
+	/*  Mask of Rx Almost Full indication for generating XO */
+	u32 q_xoff_4;
+	/*  Mask of Rx Almost Full indication for generating XO */
+	u32 q_xoff_5;
+	/*  Mask of Rx Almost Full indication for generating XO */
+	u32 q_xoff_6;
+	/*  Mask of Rx Almost Full indication for generating XO */
+	u32 q_xoff_7;
+	u32 rsrvd[7];
+};
+
+struct al_ec_tpg_rpa_res {
+	/*  NOT used */
+	u32 not_used;
+	u32 rsrvd[63];
+};
+
+struct al_ec_eee {
+	/*  EEE configuration */
+	u32 cfg_e;
+	/*  Number of clocks to get into EEE mode. */
+	u32 pre_cnt;
+	/*  Number of clocks to stop MAC EEE mode after getting */
+	u32 post_cnt;
+	/*  Number of clocks to stop the Tx MAC interface after */
+	u32 stop_cnt;
+	/*  EEE status */
+	u32 stat_eee;
+	u32 rsrvd[59];
+};
+
+struct al_ec_stat {
+	/*  Rx Frequency adjust FIFO input  packets */
+	u32 faf_in_rx_pkt;
+	/*  Rx Frequency adjust FIFO input short error packets */
+	u32 faf_in_rx_short;
+	/*  Rx Frequency adjust FIFO input  long error packets */
+	u32 faf_in_rx_long;
+	/*  Rx Frequency adjust FIFO output  packets */
+	u32 faf_out_rx_pkt;
+	/*  Rx Frequency adjust FIFO output short error packets */
+	u32 faf_out_rx_short;
+	/*  Rx Frequency adjust FIFO output long error packets */
+	u32 faf_out_rx_long;
+	/*  Rx Frequency adjust FIFO output  drop packets */
+	u32 faf_out_drop;
+	/*  Number of packets written into the Rx FIFO (without */
+	u32 rxf_in_rx_pkt;
+	/*  Number of error packets written into the Rx FIFO (w */
+	u32 rxf_in_fifo_err;
+	/*  Number of packets written into the loopback FIFO (w */
+	u32 lbf_in_rx_pkt;
+	/*  Number of error packets written into the loopback F */
+	u32 lbf_in_fifo_err;
+	/*  Number of packets read from Rx FIFO 1 */
+	u32 rxf_out_rx_1_pkt;
+	/*  Number of packets read from Rx FIFO 2 (loopback FIF */
+	u32 rxf_out_rx_2_pkt;
+	/*  Rx FIFO output drop packets from FIFO 1 */
+	u32 rxf_out_drop_1_pkt;
+	/*  Rx FIFO output drop packets from FIFO 2 (loopback) */
+	u32 rxf_out_drop_2_pkt;
+	/*  Rx Parser 1, input packet counter */
+	u32 rpe_1_in_rx_pkt;
+	/*  Rx Parser 1, output packet counter */
+	u32 rpe_1_out_rx_pkt;
+	/*  Rx Parser 2, input packet counter */
+	u32 rpe_2_in_rx_pkt;
+	/*  Rx Parser 2, output packet counter */
+	u32 rpe_2_out_rx_pkt;
+	/*  Rx Parser 3 (MACsec), input packet counter */
+	u32 rpe_3_in_rx_pkt;
+	/*  Rx Parser 3 (MACsec), output packet counter */
+	u32 rpe_3_out_rx_pkt;
+	/*  Tx parser, input packet counter */
+	u32 tpe_in_tx_pkt;
+	/*  Tx parser, output packet counter */
+	u32 tpe_out_tx_pkt;
+	/*  Tx packet modification, input packet counter */
+	u32 tpm_tx_pkt;
+	/*  Tx forwarding input packet counter */
+	u32 tfw_in_tx_pkt;
+	/*  Tx forwarding input packet counter */
+	u32 tfw_out_tx_pkt;
+	/*  Rx forwarding input packet counter */
+	u32 rfw_in_rx_pkt;
+	/*  Rx Forwarding, packet with VLAN command drop indica */
+	u32 rfw_in_vlan_drop;
+	/*  Rx Forwarding, packets with parse drop indication */
+	u32 rfw_in_parse_drop;
+	/*  Rx Forwarding, multicast packets */
+	u32 rfw_in_mc;
+	/*  Rx Forwarding, broadcast packets */
+	u32 rfw_in_bc;
+	/*  Rx Forwarding, tagged packets */
+	u32 rfw_in_vlan_exist;
+	/*  Rx Forwarding, untagged packets */
+	u32 rfw_in_vlan_nexist;
+	/*  Rx Forwarding, packets with MAC address drop indica */
+	u32 rfw_in_mac_drop;
+	/*  Rx Forwarding, packets with undetected MAC address */
+	u32 rfw_in_mac_ndet_drop;
+	/*  Rx Forwarding, packets with drop indication from th */
+	u32 rfw_in_ctrl_drop;
+	/*  Rx Forwarding, packets with L3_protocol_index drop  */
+	u32 rfw_in_prot_i_drop;
+	/*  EEE, number of times the system went into EEE state */
+	u32 eee_in;
+	u32 rsrvd[90];
+};
+
+struct al_ec_stat_udma {
+	/*  Rx forwarding output packet counter */
+	u32 rfw_out_rx_pkt;
+	/*  Rx forwarding output drop packet counter */
+	u32 rfw_out_drop;
+	/*  Multi-stream write, number of Rx packets */
+	u32 msw_in_rx_pkt;
+	/*  Multi-stream write, number of dropped packets at SO */
+	u32 msw_drop_q_full;
+	/*  Multi-stream write, number of dropped packets at SO */
+	u32 msw_drop_sop;
+	/*  Multi-stream write, number of dropped packets at EO */
+	u32 msw_drop_eop;
+	/*  Multi-stream write, number of packets written to th */
+	u32 msw_wr_eop;
+	/*  Multi-stream write, number of packets read from the */
+	u32 msw_out_rx_pkt;
+	/*  Number of transmitted packets without TSO enabled */
+	u32 tso_no_tso_pkt;
+	/*  Number of transmitted packets with TSO enabled */
+	u32 tso_tso_pkt;
+	/*  Number of TSO segments that were generated */
+	u32 tso_seg_pkt;
+	/*  Number of TSO segments that required padding */
+	u32 tso_pad_pkt;
+	/*  Tx Packet modification, MAC SA spoof error  */
+	u32 tpm_tx_spoof;
+	/*  Tx MAC interface, input packet counter */
+	u32 tmi_in_tx_pkt;
+	/*  Tx MAC interface, number of packets forwarded to th */
+	u32 tmi_out_to_mac;
+	/*  Tx MAC interface, number of packets forwarded to th */
+	u32 tmi_out_to_rx;
+	/*  Tx MAC interface, number of transmitted bytes */
+	u32 tx_q0_bytes;
+	/*  Tx MAC interface, number of transmitted bytes */
+	u32 tx_q1_bytes;
+	/*  Tx MAC interface, number of transmitted bytes */
+	u32 tx_q2_bytes;
+	/*  Tx MAC interface, number of transmitted bytes */
+	u32 tx_q3_bytes;
+	/*  Tx MAC interface, number of transmitted packets */
+	u32 tx_q0_pkts;
+	/*  Tx MAC interface, number of transmitted packets */
+	u32 tx_q1_pkts;
+	/*  Tx MAC interface, number of transmitted packets */
+	u32 tx_q2_pkts;
+	/*  Tx MAC interface, number of transmitted packets */
+	u32 tx_q3_pkts;
+	u32 rsrvd[40];
+};
+
+struct al_ec_msp {
+	/*  Ethernet parsing engine configuration 1 */
+	u32 p_parse_cfg;
+	/*  Protocol index action table address */
+	u32 p_act_table_addr;
+	/*  Protocol index action table data */
+	u32 p_act_table_data_1;
+	/*  Protocol index action table data */
+	u32 p_act_table_data_2;
+	/*  Protocol index action table data */
+	u32 p_act_table_data_3;
+	/*  Protocol index action table data */
+	u32 p_act_table_data_4;
+	/*  Protocol index action table data */
+	u32 p_act_table_data_5;
+	/*  Protocol index action table data */
+	u32 p_act_table_data_6;
+	/*  Input result vector, default values for parser inpu */
+	u32 p_res_def;
+	/*  Result input vector selection */
+	u32 p_res_in;
+	u32 rsrvd[6];
+};
+
+struct al_ec_msp_p {
+	/*  Header length, support for header length table for  */
+	u32 h_hdr_len;
+};
+
+struct al_ec_msp_c {
+	/*  Data  for comparison */
+	u32 p_comp_data;
+	/*  Mask for comparison */
+	u32 p_comp_mask;
+	/*  Compare control */
+	u32 p_comp_ctrl;
+	u32 rsrvd[4];
+};
+
+struct al_ec_wol {
+	/*  WoL enable configuration,Packet forwarding and inte */
+	u32 wol_en;
+	/*  Password for magic_password packet detection - bits */
+	u32 magic_pswd_l;
+	/*  Password for magic+password packet detection -  47: */
+	u32 magic_pswd_h;
+	/*  Configured L3 Destination IP address for WoL IPv6 p */
+	u32 ipv6_dip_word0;
+	/*  Configured L3 Destination IP address for WoL IPv6 p */
+	u32 ipv6_dip_word1;
+	/*  Configured L3 Destination IP address for WoL IPv6 p */
+	u32 ipv6_dip_word2;
+	/*  Configured L3 Destination IP address for WoL IPv6 p */
+	u32 ipv6_dip_word3;
+	/*  Configured L3 Destination IP address for WoL IPv4 p */
+	u32 ipv4_dip;
+	/*  Configured EtherType for WoL EtherType_da/EtherType */
+	u32 ethertype;
+	u32 rsrvd[7];
+};
+
+struct al_ec_pth {
+	/*  System time counter (Time of Day) */
+	u32 system_time_seconds;
+	/*  System time subseconds in a second (MSBs) */
+	u32 system_time_subseconds_msb;
+	/*  System time subseconds in a second (LSBs) */
+	u32 system_time_subseconds_lsb;
+	/*  Clock period in femtoseconds (MSB) */
+	u32 clock_period_msb;
+	/*  Clock period in femtoseconds (LSB) */
+	u32 clock_period_lsb;
+	/*  Control register for internal updates to the system */
+	u32 int_update_ctrl;
+	/*  Value to update system_time_seconds with */
+	u32 int_update_seconds;
+	/*  Value to update system_time_subseconds_msb with */
+	u32 int_update_subseconds_msb;
+	/*  Value to update system_time_subseconds_lsb with */
+	u32 int_update_subseconds_lsb;
+	/*  Control register for external updates to the system */
+	u32 ext_update_ctrl;
+	/*  Value to update system_time_seconds with */
+	u32 ext_update_seconds;
+	/*  Value to update system_time_subseconds_msb with */
+	u32 ext_update_subseconds_msb;
+	/*  Value to update system_time_subseconds_lsb with */
+	u32 ext_update_subseconds_lsb;
+	/*  This value represents the APB transaction delay fro */
+	u32 read_compensation_subseconds_msb;
+	/*  This value represents the APB transaction delay fro */
+	u32 read_compensation_subseconds_lsb;
+	/*  This value is used for two purposes:1 */
+	u32 int_write_compensation_subseconds_msb;
+	/*  This value is used for two purposes:1 */
+	u32 int_write_compensation_subseconds_lsb;
+	/*  This value represents the number of cycles it for a */
+	u32 ext_write_compensation_subseconds_msb;
+	/*  This value represents the number of cycles it for a */
+	u32 ext_write_compensation_subseconds_lsb;
+	/*  Value to be added to system_time before transferrin */
+	u32 sync_compensation_subseconds_msb;
+	/*  Value to be added to system_time before transferrin */
+	u32 sync_compensation_subseconds_lsb;
+	u32 rsrvd[11];
+};
+
+struct al_ec_pth_egress {
+	/*  Control register for egress trigger #k */
+	u32 trigger_ctrl;
+	/*  threshold for next egress trigger (#k) - secondsWri */
+	u32 trigger_seconds;
+	/*  Threshold for next egress trigger (#k) - subseconds */
+	u32 trigger_subseconds_msb;
+	/*  threshold for next egress trigger (#k) - subseconds */
+	u32 trigger_subseconds_lsb;
+	/*  External output pulse width (subseconds_msb)(Atomic */
+	u32 pulse_width_subseconds_msb;
+	/*  External output pulse width (subseconds_lsb)(Atomic */
+	u32 pulse_width_subseconds_lsb;
+	u32 rsrvd[2];
+};
+
+struct al_ec_pth_db {
+	/*  timestamp[k], in resolution of 2^18 femtosec =~ 0 */
+	u32 ts;
+	/*  Timestamp entry is valid */
+	u32 qual;
+	u32 rsrvd[4];
+};
+
+struct al_ec_gen_v3 {
+	/*  Bypass enable */
+	u32 bypass;
+	/*  Rx Completion descriptor */
+	u32 rx_comp_desc;
+	/*  general configuration */
+	u32 conf;
+	u32 rsrvd[13];
+};
+
+struct al_ec_tfw_v3 {
+	/*  Generic protocol detect Cam compare table address */
+	u32 tx_gpd_cam_addr;
+	/*  Tx Generic protocol detect Cam compare data_1 (low) */
+	u32 tx_gpd_cam_data_1;
+	/*  Tx Generic protocol detect Cam compare data_2 (high */
+	u32 tx_gpd_cam_data_2;
+	/*  Tx Generic protocol detect Cam compare mask_1 (low) */
+	u32 tx_gpd_cam_mask_1;
+	/*  Tx Generic protocol detect Cam compare mask_1 (high */
+	u32 tx_gpd_cam_mask_2;
+	/*  Tx Generic protocol detect Cam compare control */
+	u32 tx_gpd_cam_ctrl;
+	/*  Tx Generic crc parameters legacy */
+	u32 tx_gcp_legacy;
+	/*  Tx Generic crc prameters table address */
+	u32 tx_gcp_table_addr;
+	/*  Tx Generic crc prameters table general */
+	u32 tx_gcp_table_gen;
+	/*  Tx Generic crc parametrs tabel mask word 1 */
+	u32 tx_gcp_table_mask_1;
+	/*  Tx Generic crc parametrs tabel mask word 2 */
+	u32 tx_gcp_table_mask_2;
+	/*  Tx Generic crc parametrs tabel mask word 3 */
+	u32 tx_gcp_table_mask_3;
+	/*  Tx Generic crc parametrs tabel mask word 4 */
+	u32 tx_gcp_table_mask_4;
+	/*  Tx Generic crc parametrs tabel mask word 5 */
+	u32 tx_gcp_table_mask_5;
+	/*  Tx Generic crc parametrs tabel mask word 6 */
+	u32 tx_gcp_table_mask_6;
+	/*  Tx Generic crc parametrs tabel crc init */
+	u32 tx_gcp_table_crc_init;
+	/*  Tx Generic crc parametrs tabel result configuration */
+	u32 tx_gcp_table_res;
+	/*  Tx Generic crc parameters table alu opcode */
+	u32 tx_gcp_table_alu_opcode;
+	/*  Tx Generic crc parameters table alu opsel */
+	u32 tx_gcp_table_alu_opsel;
+	/*  Tx Generic crc parameters table alu constant value */
+	u32 tx_gcp_table_alu_val;
+	/*  Tx CRC/Checksum replace */
+	u32 crc_csum_replace;
+	/*  CRC/Checksum replace table address */
+	u32 crc_csum_replace_table_addr;
+	/*  CRC/Checksum replace table */
+	u32 crc_csum_replace_table;
+	u32 rsrvd[9];
+};
+
+struct al_ec_rfw_v3 {
+	/*  Rx Generic protocol detect Cam compare table address */
+	u32 rx_gpd_cam_addr;
+	/*  Rx Generic protocol detect Cam compare data_1 (low) */
+	u32 rx_gpd_cam_data_1;
+	/*  Rx Generic protocol detect Cam compare data_2 (high */
+	u32 rx_gpd_cam_data_2;
+	/*  Rx Generic protocol detect Cam compare mask_1 (low) */
+	u32 rx_gpd_cam_mask_1;
+	/*  Rx Generic protocol detect Cam compare mask_1 (high */
+	u32 rx_gpd_cam_mask_2;
+	/*  Rx Generic protocol detect Cam compare control */
+	u32 rx_gpd_cam_ctrl;
+	/*  Generic protocol detect Parser result vector pointe */
+	u32 gpd_p1;
+	/*  Generic protocol detect Parser result vector pointe */
+	u32 gpd_p2;
+	/*  Generic protocol detect Parser result vector pointe */
+	u32 gpd_p3;
+	/*  Generic protocol detect Parser result vector pointe */
+	u32 gpd_p4;
+	/*  Generic protocol detect Parser result vector pointe */
+	u32 gpd_p5;
+	/*  Generic protocol detect Parser result vector pointe */
+	u32 gpd_p6;
+	/*  Generic protocol detect Parser result vector pointe */
+	u32 gpd_p7;
+	/*  Generic protocol detect Parser result vector pointe */
+	u32 gpd_p8;
+	/*  Rx Generic crc parameters legacy */
+	u32 rx_gcp_legacy;
+	/*  Rx Generic crc prameters table address */
+	u32 rx_gcp_table_addr;
+	/*  Rx Generic crc prameters table general */
+	u32 rx_gcp_table_gen;
+	/*  Rx Generic crc parametrs tabel mask word 1 */
+	u32 rx_gcp_table_mask_1;
+	/*  Rx Generic crc parametrs tabel mask word 2 */
+	u32 rx_gcp_table_mask_2;
+	/*  Rx Generic crc parametrs tabel mask word 3 */
+	u32 rx_gcp_table_mask_3;
+	/*  Rx Generic crc parametrs tabel mask word 4 */
+	u32 rx_gcp_table_mask_4;
+	/*  Rx Generic crc parametrs tabel mask word 5 */
+	u32 rx_gcp_table_mask_5;
+	/*  Rx Generic crc parametrs tabel mask word 6 */
+	u32 rx_gcp_table_mask_6;
+	/*  Rx Generic crc parametrs tabel crc init */
+	u32 rx_gcp_table_crc_init;
+	/*  Rx Generic crc parametrs tabel result configuration */
+	u32 rx_gcp_table_res;
+	/*  Rx Generic crc  parameters table alu opcode */
+	u32 rx_gcp_table_alu_opcode;
+	/*  Rx Generic crc  parameters table alu opsel */
+	u32 rx_gcp_table_alu_opsel;
+	/*  Rx Generic crc  parameters table alu constant value */
+	u32 rx_gcp_table_alu_val;
+	/*  Generic crc engin parameters alu Parser result vect */
+	u32 rx_gcp_alu_p1;
+	/*  Generic crc engine parameters alu Parser result vec */
+	u32 rx_gcp_alu_p2;
+	/*  Header split control table address */
+	u32 hs_ctrl_table_addr;
+	/*  Header split control table */
+	u32 hs_ctrl_table;
+	/*  Header split control alu opcode */
+	u32 hs_ctrl_table_alu_opcode;
+	/*  Header split control alu opsel */
+	u32 hs_ctrl_table_alu_opsel;
+	/*  Header split control alu constant value */
+	u32 hs_ctrl_table_alu_val;
+	/*  Header split control configuration */
+	u32 hs_ctrl_cfg;
+	/*  Header split control alu Parser result vector point */
+	u32 hs_ctrl_alu_p1;
+	/*  Header split control alu Parser result vector point */
+	u32 hs_ctrl_alu_p2;
+	u32 rsrvd[26];
+};
+
+struct al_ec_crypto {
+	/*  Tx inline crypto configuration */
+	u32 tx_config;
+	/*  Rx inline crypto configuration */
+	u32 rx_config;
+	/*  reserved FFU */
+	u32 tx_override;
+	/*  reserved FFU */
+	u32 rx_override;
+	/*  inline XTS alpha [31:0] */
+	u32 xts_alpha_1;
+	/*  inline XTS alpha [63:32] */
+	u32 xts_alpha_2;
+	/*  inline XTS alpha [95:64] */
+	u32 xts_alpha_3;
+	/*  inline XTS alpha [127:96] */
+	u32 xts_alpha_4;
+	/*  inline XTS sector ID increment [31:0] */
+	u32 xts_sector_id_1;
+	/*  inline XTS sector ID increment [63:32] */
+	u32 xts_sector_id_2;
+	/*  inline XTS sector ID increment [95:64] */
+	u32 xts_sector_id_3;
+	/*  inline XTS sector ID increment [127:96] */
+	u32 xts_sector_id_4;
+	/*  IV formation configuration */
+	u32 tx_enc_iv_construction;
+	/*  IV formation configuration */
+	u32 rx_enc_iv_construction;
+	/*  IV formation configuration */
+	u32 rx_enc_iv_map;
+	/*
+	 * effectively shorten shift-registers used for eop-pkt-trim, in order
+	 * to improve performance.  Each value must be built of consecutive 1's
+	 * (bypassed regs), and then consecutive 0's (non-bypassed regs)
+	 */
+	u32 tx_pkt_trim_len;
+	/*
+	 * effectively shorten shift-registers used for eop-pkt-trim, in order
+	 * to improve performance.  Each value must be built of consecutive 1's
+	 * (bypassed regs), and then consecutive 0's (non-bypassed regs)
+	 */
+	u32 rx_pkt_trim_len;
+	/*  reserved FFU */
+	u32 tx_reserved;
+	/*  reserved FFU */
+	u32 rx_reserved;
+	u32 rsrvd[13];
+};
+
+struct al_ec_crypto_perf_cntr {
+	u32 total_tx_pkts;
+	u32 total_rx_pkts;
+	u32 total_tx_secured_pkts;
+	u32 total_rx_secured_pkts;
+	u32 total_tx_secured_pkts_cipher_mode;
+	u32 total_tx_secured_pkts_cipher_mode_cmpr;
+	u32 total_rx_secured_pkts_cipher_mode;
+	u32 total_rx_secured_pkts_cipher_mode_cmpr;
+	u32 total_tx_secured_bytes_low;
+	u32 total_tx_secured_bytes_high;
+	u32 total_rx_secured_bytes_low;
+	u32 total_rx_secured_bytes_high;
+	u32 total_tx_sign_calcs;
+	u32 total_rx_sign_calcs;
+	u32 total_tx_sign_errs;
+	u32 total_rx_sign_errs;
+};
+
+struct al_ec_crypto_tx_tid {
+	/*  tid_default_entry */
+	u32 def_val;
+};
+
+struct al_ec_regs {
+	u32 rsrvd_0[32];
+	struct al_ec_gen gen;
+	struct al_ec_mac mac;
+	struct al_ec_rxf rxf;
+	struct al_ec_epe epe[2];
+	struct al_ec_epe_res epe_res;
+	struct al_ec_epe_h epe_h[32];
+	struct al_ec_epe_p epe_p[32];
+	struct al_ec_epe_a epe_a[32];
+	struct al_ec_rfw rfw;
+	struct al_ec_rfw_udma rfw_udma[4];
+	struct al_ec_rfw_hash rfw_hash[10];
+	struct al_ec_rfw_priority rfw_priority[8];
+	struct al_ec_rfw_default rfw_default[8];
+	struct al_ec_fwd_mac fwd_mac[32];
+	struct al_ec_msw msw;
+	struct al_ec_tso tso;
+	struct al_ec_tso_sel tso_sel[8];
+	struct al_ec_tpe tpe;
+	struct al_ec_tpm_udma tpm_udma[4];
+	struct al_ec_tpm_sel tpm_sel[4];
+	struct al_ec_tfw tfw;
+	struct al_ec_tfw_udma tfw_udma[4];
+	struct al_ec_tmi tmi;
+	struct al_ec_efc efc;
+	struct al_ec_fc_udma fc_udma[4];
+	struct al_ec_tpg_rpa_res tpg_rpa_res;
+	struct al_ec_eee eee;
+	struct al_ec_stat stat;
+	struct al_ec_stat_udma stat_udma[4];
+	struct al_ec_msp msp;
+	struct al_ec_msp_p msp_p[32];
+	struct al_ec_msp_c msp_c[32];
+	u32 rsrvd_1[16];
+	struct al_ec_wol wol;
+	u32 rsrvd_2[80];
+	struct al_ec_pth pth;
+	struct al_ec_pth_egress pth_egress[8];
+	struct al_ec_pth_db pth_db[16];
+	u32 rsrvd_3[416];
+	struct al_ec_gen_v3 gen_v3;
+	struct al_ec_tfw_v3 tfw_v3;
+	struct al_ec_rfw_v3 rfw_v3;
+	struct al_ec_crypto crypto;
+	struct al_ec_crypto_perf_cntr crypto_perf_cntr[2];
+	u32 rsrvd_4[48];
+	struct al_ec_crypto_tx_tid crypto_tx_tid[8];
+};
+
+/* Selection between descriptor caching options (WORD selection) */
+#define EC_GEN_EN_EXT_CACHE_WORD_SPLIT   BIT(20)
+
+/* Drop indication for the selected protocol index */
+#define EC_EPE_A_PROT_ACT_DROP           BIT(0)
+
+/* Enable SIP/DIP swap if SIP<DIP */
+#define EC_RFW_THASH_CFG_1_ENABLE_IP_SWAP BIT(16)
+/* Enable PORT swap if SPORT<DPORT */
+#define EC_RFW_THASH_CFG_1_ENABLE_PORT_SWAP BIT(17)
+
+/* Selects how to calculate the L3 header length when L3 is IpPv */
+#define EC_RFW_META_L3_LEN_CALC          BIT(4)
+
+/* Number of MetaData at the end of the packet1 - One MetaData b */
+#define EC_RFW_OUT_CFG_META_CNT_MASK     0x00000003
+/* Enable packet drop */
+#define EC_RFW_OUT_CFG_DROP_EN           BIT(2)
+
+/* Select the header that will be used for the checksum when a t */
+#define EC_RFW_CHECKSUM_HDR_SEL          BIT(1)
+
+/* Default data selection 0 - Default value 1 - Table data out */
+#define EC_RFW_CTRL_TABLE_DEF_SEL        BIT(20)
+
+/* Drop indication */
+#define EC_FWD_MAC_CTRL_RX_VAL_DROP		BIT(0)
+
+/* UDMA selection */
+#define EC_FWD_MAC_CTRL_RX_VAL_UDMA_MASK	0x000000078
+#define EC_FWD_MAC_CTRL_RX_VAL_UDMA_SHIFT	3
+
+/* queue number */
+#define EC_FWD_MAC_CTRL_RX_VAL_QID_MASK		0x00000180
+#define EC_FWD_MAC_CTRL_RX_VAL_QID_SHIFT	7
+
+/* Entry is valid for Rx forwarding engine. */
+#define EC_FWD_MAC_CTRL_RX_VALID         BIT(15)
+/* Control value for Tx forwarding engine */
+#define EC_FWD_MAC_CTRL_TX_VAL_MASK      0x001F0000
+#define EC_FWD_MAC_CTRL_TX_VAL_SHIFT     16
+/* Entry is valid for Tx forwarding engine. */
+#define EC_FWD_MAC_CTRL_TX_VALID         BIT(31)
+
+/* MSS selection option:0 - MSS value is selected using MSS_sel  */
+#define EC_TSO_CFG_ADD_0_MSS_SEL         BIT(0)
+
+/* Enable TSO with tunnelling */
+#define EC_TSO_CFG_TUNNEL_EN_TUNNEL_TSO  BIT(0)
+/* Enable outer UDP checksum update */
+#define EC_TSO_CFG_TUNNEL_EN_UDP_CHKSUM  BIT(8)
+/* Enable outer UDP length update */
+#define EC_TSO_CFG_TUNNEL_EN_UDP_LEN     BIT(9)
+/* Enable outer Ip6  length update */
+#define EC_TSO_CFG_TUNNEL_EN_IPV6_PLEN   BIT(10)
+/* Enable outer IPv4 checksum update */
+#define EC_TSO_CFG_TUNNEL_EN_IPV4_CHKSUM BIT(11)
+/* Enable outer IPv4 Identification update */
+#define EC_TSO_CFG_TUNNEL_EN_IPV4_IDEN   BIT(12)
+/* Enable outer IPv4 length update */
+#define EC_TSO_CFG_TUNNEL_EN_IPV4_TLEN   BIT(13)
+
+/* Swap output byte order */
+#define EC_TMI_TX_CFG_SWAP_BYTES         BIT(0)
+/* Enable forwarding to the Rx data path. */
+#define EC_TMI_TX_CFG_EN_FWD_TO_RX       BIT(1)
+/* Mask 2 for XOFF [7:0] Mask 2 for sampled Almost Full indicati */
+#define EC_EFC_EC_XOFF_MASK_2_SHIFT      8
+
+/* Mask 1 for generating XON pulse, masking XOFF [0] */
+#define EC_EFC_XON_MASK_1                BIT(0)
+/* Mask 2 for generating XON pulse, masking Almost Full indicati */
+#define EC_EFC_XON_MASK_2                BIT(1)
+
+/* Threshold high */
+#define EC_EFC_RX_FIFO_HYST_TH_HIGH_SHIFT 16
+
+#endif /* __AL_HW_EC_REG_H */
diff --git a/drivers/net/ethernet/annapurna/al_hw_eth_mac_regs.h b/drivers/net/ethernet/annapurna/al_hw_eth_mac_regs.h
new file mode 100644
index 000000000000..b2b956b7e28f
--- /dev/null
+++ b/drivers/net/ethernet/annapurna/al_hw_eth_mac_regs.h
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 2017, Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __AL_HW_ETH_MAC_REGS_H__
+#define __AL_HW_ETH_MAC_REGS_H__
+
+/*
+* Unit Registers
+*/
+
+struct al_eth_mac_1g_stats {
+	u32 reserved1[2];
+	u32 aFramesTransmittedOK;
+	u32 aFramesReceivedOK;
+	u32 aFrameCheckSequenceErrors;
+	u32 aAlignmentErrors;
+	u32 aOctetsTransmittedOK;
+	u32 aOctetsReceivedOK;
+	u32 aPAUSEMACCtrlFramesTransmitted;
+	u32 aPAUSEMACCtrlFramesReceived;
+	u32 ifInErrors;
+	u32 ifOutErrors;
+	u32 ifInUcastPkts;
+	u32 ifInMulticastPkts;
+	u32 ifInBroadcastPkts;
+	u32 reserved2;
+	u32 ifOutUcastPkts;
+	u32 ifOutMulticastPkts;
+	u32 ifOutBroadcastPkts;
+	u32 etherStatsDropEvents;
+	u32 etherStatsOctets;
+	u32 etherStatsPkts;
+	u32 etherStatsUndersizePkts;
+	u32 etherStatsOversizePkts;
+	u32 etherStatsPkts64Octets;
+	u32 etherStatsPkts65to127Octets;
+	u32 etherStatsPkts128to255Octets;
+	u32 etherStatsPkts256to511Octets;
+	u32 etherStatsPkts512to1023Octets;
+	u32 etherStatsPkts1024to1518Octets;
+	u32 etherStatsPkts1519toX;
+	u32 etherStatsJabbers;
+	u32 etherStatsFragments;
+	u32 reserved3[71];
+};
+
+struct al_eth_mac_1g {
+	u32 rev;
+	u32 scratch;
+	u32 cmd_cfg;
+	u32 mac_0;
+
+	u32 mac_1;
+	u32 frm_len;
+	u32 pause_quant;
+	u32 rx_section_empty;
+
+	u32 rx_section_full;
+	u32 tx_section_empty;
+	u32 tx_section_full;
+	u32 rx_almost_empty;
+
+	u32 rx_almost_full;
+	u32 tx_almost_empty;
+	u32 tx_almost_full;
+	u32 mdio_addr0;
+
+	u32 mdio_addr1;
+	u32 Reserved[5];
+
+	u32 reg_stat;
+	u32 tx_ipg_len;
+
+	struct al_eth_mac_1g_stats stats;
+
+	u32 phy_regs_base;
+	u32 Reserved2[127];
+};
+
+struct al_eth_mac_10g_stats_v2 {
+	u32 aFramesTransmittedOK;
+	u32 reserved1;
+	u32 aFramesReceivedOK;
+	u32 reserved2;
+	u32 aFrameCheckSequenceErrors;
+	u32 reserved3;
+	u32 aAlignmentErrors;
+	u32 reserved4;
+	u32 aPAUSEMACCtrlFramesTransmitted;
+	u32 reserved5;
+	u32 aPAUSEMACCtrlFramesReceived;
+	u32 reserved6;
+	u32 aFrameTooLongErrors;
+	u32 reserved7;
+	u32 aInRangeLengthErrors;
+	u32 reserved8;
+	u32 VLANTransmittedOK;
+	u32 reserved9;
+	u32 VLANReceivedOK;
+	u32 reserved10;
+	u32 ifOutOctetsL;
+	u32 ifOutOctetsH;
+	u32 ifInOctetsL;
+	u32 ifInOctetsH;
+	u32 ifInUcastPkts;
+	u32 reserved11;
+	u32 ifInMulticastPkts;
+	u32 reserved12;
+	u32 ifInBroadcastPkts;
+	u32 reserved13;
+	u32 ifOutErrors;
+	u32 reserved14[3];
+	u32 ifOutUcastPkts;
+	u32 reserved15;
+	u32 ifOutMulticastPkts;
+	u32 reserved16;
+	u32 ifOutBroadcastPkts;
+	u32 reserved17;
+	u32 etherStatsDropEvents;
+	u32 reserved18;
+	u32 etherStatsOctets;
+	u32 reserved19;
+	u32 etherStatsPkts;
+	u32 reserved20;
+	u32 etherStatsUndersizePkts;
+	u32 reserved21;
+	u32 etherStatsPkts64Octets;
+	u32 reserved22;
+	u32 etherStatsPkts65to127Octets;
+	u32 reserved23;
+	u32 etherStatsPkts128to255Octets;
+	u32 reserved24;
+	u32 etherStatsPkts256to511Octets;
+	u32 reserved25;
+	u32 etherStatsPkts512to1023Octets;
+	u32 reserved26;
+	u32 etherStatsPkts1024to1518Octets;
+	u32 reserved27;
+	u32 etherStatsPkts1519toX;
+	u32 reserved28;
+	u32 etherStatsOversizePkts;
+	u32 reserved29;
+	u32 etherStatsJabbers;
+	u32 reserved30;
+	u32 etherStatsFragments;
+	u32 reserved31;
+	u32 ifInErrors;
+	u32 reserved32[91];
+};
+
+struct al_eth_mac_10g_stats_v3_rx {
+	u32 etherStatsOctets;
+	u32 reserved2;
+	u32 ifOctetsL;
+	u32 ifOctetsH;
+	u32 aAlignmentErrors;
+	u32 reserved4;
+	u32 aPAUSEMACCtrlFrames;
+	u32 reserved5;
+	u32 FramesOK;
+	u32 reserved6;
+	u32 CRCErrors;
+	u32 reserved7;
+	u32 VLANOK;
+	u32 reserved8;
+	u32 ifInErrors;
+	u32 reserved9;
+	u32 ifInUcastPkts;
+	u32 reserved10;
+	u32 ifInMulticastPkts;
+	u32 reserved11;
+	u32 ifInBroadcastPkts;
+	u32 reserved12;
+	u32 etherStatsDropEvents;
+	u32 reserved13;
+	u32 etherStatsPkts;
+	u32 reserved14;
+	u32 etherStatsUndersizePkts;
+	u32 reserved15;
+	u32 etherStatsPkts64Octets;
+	u32 reserved16;
+	u32 etherStatsPkts65to127Octets;
+	u32 reserved17;
+	u32 etherStatsPkts128to255Octets;
+	u32 reserved18;
+	u32 etherStatsPkts256to511Octets;
+	u32 reserved19;
+	u32 etherStatsPkts512to1023Octets;
+	u32 reserved20;
+	u32 etherStatsPkts1024to1518Octets;
+	u32 reserved21;
+	u32 etherStatsPkts1519toMax;
+	u32 reserved22;
+	u32 etherStatsOversizePkts;
+	u32 reserved23;
+	u32 etherStatsJabbers;
+	u32 reserved24;
+	u32 etherStatsFragments;
+	u32 reserved25;
+	u32 aMACControlFramesReceived;
+	u32 reserved26;
+	u32 aFrameTooLong;
+	u32 reserved27;
+	u32 aInRangeLengthErrors;
+	u32 reserved28;
+	u32 reserved29[10];
+};
+
+struct al_eth_mac_10g_stats_v3_tx {
+	u32 etherStatsOctets;
+	u32 reserved30;
+	u32 ifOctetsL;
+	u32 ifOctetsH;
+	u32 aAlignmentErrors;
+	u32 reserved32;
+	u32 aPAUSEMACCtrlFrames;
+	u32 reserved33;
+	u32 FramesOK;
+	u32 reserved34;
+	u32 CRCErrors;
+	u32 reserved35;
+	u32 VLANOK;
+	u32 reserved36;
+	u32 ifOutErrors;
+	u32 reserved37;
+	u32 ifUcastPkts;
+	u32 reserved38;
+	u32 ifMulticastPkts;
+	u32 reserved39;
+	u32 ifBroadcastPkts;
+	u32 reserved40;
+	u32 etherStatsDropEvents;
+	u32 reserved41;
+	u32 etherStatsPkts;
+	u32 reserved42;
+	u32 etherStatsUndersizePkts;
+	u32 reserved43;
+	u32 etherStatsPkts64Octets;
+	u32 reserved44;
+	u32 etherStatsPkts65to127Octets;
+	u32 reserved45;
+	u32 etherStatsPkts128to255Octets;
+	u32 reserved46;
+	u32 etherStatsPkts256to511Octets;
+	u32 reserved47;
+	u32 etherStatsPkts512to1023Octets;
+	u32 reserved48;
+	u32 etherStatsPkts1024to1518Octets;
+	u32 reserved49;
+	u32 etherStatsPkts1519toTX_MTU;
+	u32 reserved50;
+	u32 reserved51[4];
+	u32 aMACControlFrames;
+	u32 reserved52[15];
+};
+
+struct al_eth_mac_10g_stats_v3 {
+	u32 reserved1[32];
+
+	struct al_eth_mac_10g_stats_v3_rx rx;
+	struct al_eth_mac_10g_stats_v3_tx tx;
+};
+
+union al_eth_mac_10g_stats {
+	struct al_eth_mac_10g_stats_v2	v2;
+	struct al_eth_mac_10g_stats_v3	v3;
+};
+
+struct al_eth_mac_10g {
+	u32 rev;
+	u32 scratch;
+	u32 cmd_cfg;
+	u32 mac_0;
+
+	u32 mac_1;
+	u32 frm_len;
+	u32 Reserved;
+	u32 rx_fifo_sections;
+
+	u32 tx_fifo_sections;
+	u32 rx_fifo_almost_f_e;
+	u32 tx_fifo_almost_f_e;
+	u32 hashtable_load;
+
+	u32 mdio_cfg_status;
+	u16 mdio_cmd;
+	u16 reserved1;
+	u16 mdio_data;
+	u16 reserved2;
+	u16 mdio_regaddr;
+	u16 reserved3;
+
+	u32 status;
+	u32 tx_ipg_len;
+	u32 Reserved1[3];
+
+	u32 cl01_pause_quanta;
+	u32 cl23_pause_quanta;
+	u32 cl45_pause_quanta;
+
+	u32 cl67_pause_quanta;
+	u32 cl01_quanta_thresh;
+	u32 cl23_quanta_thresh;
+	u32 cl45_quanta_thresh;
+
+	u32 cl67_quanta_thresh;
+	u32 rx_pause_status;
+	u32 Reserved2;
+	u32 ts_timestamp;
+
+	union al_eth_mac_10g_stats stats;
+
+	u32 control;
+	u32 status_reg;
+	u32 phy_id[2];
+
+	u32 dev_ability;
+	u32 partner_ability;
+	u32 an_expansion;
+	u32 device_np;
+
+	u32 partner_np;
+	u32 Reserved4[9];
+
+	u32 link_timer_lo;
+	u32 link_timer_hi;
+
+	u32 if_mode;
+
+	u32 Reserved5[43];
+};
+
+struct al_eth_mac_gen {
+	/*  Ethernet Controller Version */
+	u32 version;
+	u32 rsrvd_0[2];
+	/* MAC selection configuration */
+	u32 cfg;
+	/* 10/100/1000 MAC external configuration */
+	u32 mac_1g_cfg;
+	/* 10/100/1000 MAC status */
+	u32 mac_1g_stat;
+	/* RGMII external configuration */
+	u32 rgmii_cfg;
+	/* RGMII status */
+	u32 rgmii_stat;
+	/* 1/2.5/10G MAC external configuration */
+	u32 mac_10g_cfg;
+	/* 1/2.5/10G MAC status */
+	u32 mac_10g_stat;
+	/* XAUI PCS configuration */
+	u32 xaui_cfg;
+	/* XAUI PCS status */
+	u32 xaui_stat;
+	/* RXAUI PCS configuration */
+	u32 rxaui_cfg;
+	/* RXAUI PCS status */
+	u32 rxaui_stat;
+	/* Signal detect configuration */
+	u32 sd_cfg;
+	/* MDIO control register for MDIO interface 1 */
+	u32 mdio_ctrl_1;
+	/* MDIO information register for MDIO interface 1 */
+	u32 mdio_1;
+	/* MDIO control register for MDIO interface 2 */
+	u32 mdio_ctrl_2;
+	/* MDIO information register for MDIO interface 2 */
+	u32 mdio_2;
+	/* XGMII 32 to 64 data FIFO control */
+	u32 xgmii_dfifo_32_64;
+	/* Reserved 1 out */
+	u32 mac_res_1_out;
+	/* XGMII 64 to 32 data FIFO control */
+	u32 xgmii_dfifo_64_32;
+	/* Reserved 1 in */
+	u32 mac_res_1_in;
+	/* SerDes TX FIFO control */
+	u32 sd_fifo_ctrl;
+	/* SerDes TX FIFO status */
+	u32 sd_fifo_stat;
+	/* SerDes in/out selection */
+	u32 mux_sel;
+	/* Clock configuration */
+	u32 clk_cfg;
+	u32 rsrvd_1;
+	/* LOS and SD selection */
+	u32 los_sel;
+	/* RGMII selection configuration */
+	u32 rgmii_sel;
+	/* Ethernet LED configuration */
+	u32 led_cfg;
+	u32 rsrvd[33];
+};
+
+struct al_eth_mac_kr {
+	/* PCS register file address */
+	u32 pcs_addr;
+	/* PCS register file data */
+	u32 pcs_data;
+	/* AN register file address */
+	u32 an_addr;
+	/* AN register file data */
+	u32 an_data;
+	/* PMA register file address */
+	u32 pma_addr;
+	/* PMA register file data */
+	u32 pma_data;
+	/* MTIP register file address */
+	u32 mtip_addr;
+	/* MTIP register file data */
+	u32 mtip_data;
+	/* KR PCS config  */
+	u32 pcs_cfg;
+	/* KR PCS status  */
+	u32 pcs_stat;
+	u32 rsrvd[54];
+};
+
+struct al_eth_mac_sgmii {
+	/* PCS register file address */
+	u32 reg_addr;
+	/* PCS register file data */
+	u32 reg_data;
+	/* PCS clock divider configuration */
+	u32 clk_div;
+	/* PCS Status */
+	u32 link_stat;
+	u32 rsrvd[60];
+};
+
+struct al_eth_mac_stat {
+	/* Receive rate matching error */
+	u32 match_fault;
+	/* EEE, number of times the MAC went into low power mode */
+	u32 eee_in;
+	/* EEE, number of times the MAC went out of low power mode */
+	u32 eee_out;
+	/*
+	 * 40G PCS,
+	 * FEC corrected error indication
+	 */
+	u32 v3_pcs_40g_ll_cerr_0;
+	/*
+	 * 40G PCS,
+	 * FEC corrected error indication
+	 */
+	u32 v3_pcs_40g_ll_cerr_1;
+	/*
+	 * 40G PCS,
+	 * FEC corrected error indication
+	 */
+	u32 v3_pcs_40g_ll_cerr_2;
+	/*
+	 * 40G PCS,
+	 * FEC corrected error indication
+	 */
+	u32 v3_pcs_40g_ll_cerr_3;
+	/*
+	 * 40G PCS,
+	 * FEC uncorrectable error indication
+	 */
+	u32 v3_pcs_40g_ll_ncerr_0;
+	/*
+	 * 40G PCS,
+	 * FEC uncorrectable error indication
+	 */
+	u32 v3_pcs_40g_ll_ncerr_1;
+	/*
+	 * 40G PCS,
+	 * FEC uncorrectable error indication
+	 */
+	u32 v3_pcs_40g_ll_ncerr_2;
+	/*
+	 * 40G PCS,
+	 * FEC uncorrectable error indication
+	 */
+	u32 v3_pcs_40g_ll_ncerr_3;
+	/*
+	 * 10G_LL PCS,
+	 * FEC corrected error indication
+	 */
+	u32 v3_pcs_10g_ll_cerr;
+	/*
+	 * 10G_LL PCS,
+	 * FEC uncorrectable error indication
+	 */
+	u32 v3_pcs_10g_ll_ncerr;
+	u32 rsrvd[51];
+};
+
+struct al_eth_mac_stat_lane {
+	/* Character error */
+	u32 char_err;
+	/* Disparity error */
+	u32 disp_err;
+	/* Comma detection */
+	u32 pat;
+	u32 rsrvd[13];
+};
+
+struct al_eth_mac_gen_v3 {
+	/* ASYNC FIFOs control */
+	u32 afifo_ctrl;
+	/* TX ASYNC FIFO configuration */
+	u32 tx_afifo_cfg_1;
+	/* TX ASYNC FIFO configuration */
+	u32 tx_afifo_cfg_2;
+	/* TX ASYNC FIFO configuration */
+	u32 tx_afifo_cfg_3;
+	/* TX ASYNC FIFO configuration */
+	u32 tx_afifo_cfg_4;
+	/* TX ASYNC FIFO configuration */
+	u32 tx_afifo_cfg_5;
+	/* RX ASYNC FIFO configuration */
+	u32 rx_afifo_cfg_1;
+	/* RX ASYNC FIFO configuration */
+	u32 rx_afifo_cfg_2;
+	/* RX ASYNC FIFO configuration */
+	u32 rx_afifo_cfg_3;
+	/* RX ASYNC FIFO configuration */
+	u32 rx_afifo_cfg_4;
+	/* RX ASYNC FIFO configuration */
+	u32 rx_afifo_cfg_5;
+	/* MAC selection configuration */
+	u32 mac_sel;
+	/* 10G LL MAC configuration */
+	u32 mac_10g_ll_cfg;
+	/* 10G LL MAC control */
+	u32 mac_10g_ll_ctrl;
+	/* 10G LL PCS configuration */
+	u32 pcs_10g_ll_cfg;
+	/* 10G LL PCS status */
+	u32 pcs_10g_ll_status;
+	/* 40G LL PCS configuration */
+	u32 pcs_40g_ll_cfg;
+	/* 40G LL PCS status */
+	u32 pcs_40g_ll_status;
+	/* PCS 40G  register file address */
+	u32 pcs_40g_ll_addr;
+	/* PCS 40G register file data */
+	u32 pcs_40g_ll_data;
+	/* 40G LL MAC configuration */
+	u32 mac_40g_ll_cfg;
+	/* 40G LL MAC status */
+	u32 mac_40g_ll_status;
+	/* Preamble configuration (high [55:32]) */
+	u32 preamble_cfg_high;
+	/* Preamble configuration (low [31:0]) */
+	u32 preamble_cfg_low;
+	/* MAC 40G register file address */
+	u32 mac_40g_ll_addr;
+	/* MAC 40G register file data */
+	u32 mac_40g_ll_data;
+	/* 40G LL MAC control */
+	u32 mac_40g_ll_ctrl;
+	/* PCS 40G  register file address */
+	u32 pcs_40g_fec_91_ll_addr;
+	/* PCS 40G register file data */
+	u32 pcs_40g_fec_91_ll_data;
+	/* 40G LL PCS EEE configuration */
+	u32 pcs_40g_ll_eee_cfg;
+	/* 40G LL PCS EEE status */
+	u32 pcs_40g_ll_eee_status;
+	/*
+	 * SERDES 32-bit interface shift configuration (when swap is
+	 * enabled)
+	 */
+	u32 serdes_32_tx_shift;
+	/*
+	 * SERDES 32-bit interface shift configuration (when swap is
+	 * enabled)
+	 */
+	u32 serdes_32_rx_shift;
+	/*
+	 * SERDES 32-bit interface bit selection
+	 */
+	u32 serdes_32_tx_sel;
+	/*
+	 * SERDES 32-bit interface bit selection
+	 */
+	u32 serdes_32_rx_sel;
+	/* AN/LT wrapper  control */
+	u32 an_lt_ctrl;
+	/* AN/LT wrapper  register file address */
+	u32 an_lt_0_addr;
+	/* AN/LT wrapper register file data */
+	u32 an_lt_0_data;
+	/* AN/LT wrapper  register file address */
+	u32 an_lt_1_addr;
+	/* AN/LT wrapper register file data */
+	u32 an_lt_1_data;
+	/* AN/LT wrapper  register file address */
+	u32 an_lt_2_addr;
+	/* AN/LT wrapper register file data */
+	u32 an_lt_2_data;
+	/* AN/LT wrapper  register file address */
+	u32 an_lt_3_addr;
+	/* AN/LT wrapper register file data */
+	u32 an_lt_3_data;
+	/* External SERDES control */
+	u32 ext_serdes_ctrl;
+	/* spare bits */
+	u32 spare;
+	u32 rsrvd[18];
+};
+
+struct al_eth_mac_regs {
+	struct al_eth_mac_1g mac_1g;
+	struct al_eth_mac_10g mac_10g;
+	u32 rsrvd_0[64];
+	struct al_eth_mac_gen gen;
+	struct al_eth_mac_kr kr;
+	struct al_eth_mac_sgmii sgmii;
+	struct al_eth_mac_stat stat;
+	struct al_eth_mac_stat_lane stat_lane[4];
+	struct al_eth_mac_gen_v3 gen_v3;
+};
+
+/* cmd_cfg */
+#define ETH_1G_MAC_CMD_CFG_TX_ENA	BIT(0)
+#define ETH_1G_MAC_CMD_CFG_RX_ENA	BIT(1)
+/* enable Half Duplex */
+#define ETH_1G_MAC_CMD_CFG_HD_EN	BIT(10)
+/* enable 1G speed */
+#define ETH_1G_MAC_CMD_CFG_1G_SPD	BIT(3)
+/* enable 10M speed */
+#define ETH_1G_MAC_CMD_CFG_10M_SPD	BIT(25)
+
+/* cmd_cfg */
+#define ETH_10G_MAC_CMD_CFG_TX_ENA				BIT(0)
+#define ETH_10G_MAC_CMD_CFG_RX_ENA				BIT(1)
+
+/* mdio_cfg_status */
+#define ETH_10G_MAC_MDIO_CFG_HOLD_TIME_MASK	0x0000001c
+#define ETH_10G_MAC_MDIO_CFG_HOLD_TIME_SHIFT	2
+
+#define ETH_10G_MAC_MDIO_CFG_HOLD_TIME_7_CLK	3
+
+/* control */
+#define ETH_10G_MAC_CONTROL_AN_EN_MASK	0x00001000
+
+/* if_mode */
+#define ETH_10G_MAC_IF_MODE_SGMII_EN_MASK	0x00000001
+#define ETH_10G_MAC_IF_MODE_SGMII_AN_MASK	0x00000002
+#define ETH_10G_MAC_IF_MODE_SGMII_SPEED_MASK	0x0000000c
+#define ETH_10G_MAC_IF_MODE_SGMII_SPEED_SHIFT	2
+#define ETH_10G_MAC_IF_MODE_SGMII_DUPLEX_MASK	0x00000010
+#define ETH_10G_MAC_IF_MODE_SGMII_DUPLEX_SHIFT	4
+
+#define ETH_10G_MAC_IF_MODE_SGMII_SPEED_10M	0
+#define ETH_10G_MAC_IF_MODE_SGMII_SPEED_100M	1
+#define ETH_10G_MAC_IF_MODE_SGMII_SPEED_1G	2
+
+#define ETH_10G_MAC_IF_MODE_SGMII_DUPLEX_FULL	0
+#define ETH_10G_MAC_IF_MODE_SGMII_DUPLEX_HALF	1
+
+/*
+ * Selection of the input for the "set_1000" input of the RGMII converter
+ * 0 - From MAC
+ * 1 - From register set_1000_def (automatic speed selection)
+ */
+#define ETH_MAC_GEN_RGMII_CFG_SET_1000_SEL BIT(0)
+/*
+ * Selection of the input for the "set_10" input of the RGMII converter:
+ * 0 - From MAC
+ * 1 - From register set_10_def (automatic speed selection)
+ */
+#define ETH_MAC_GEN_RGMII_CFG_SET_10_SEL BIT(4)
+/* Enable automatic speed selection (based on PHY in-band status information) */
+#define ETH_MAC_GEN_RGMII_CFG_ENA_AUTO   BIT(8)
+
+#define ETH_MAC_GEN_MUX_SEL_KR_IN_MASK   0x0000C000
+
+/*
+ * LED source selection:
+ * 0 – Default reg
+ * 1 – Rx activity
+ * 2 – Tx activity
+ * 3 – Rx | Tx activity
+ * 4-9 – SGMII LEDs
+ */
+#define ETH_MAC_GEN_LED_CFG_SEL_MASK     0x0000000F
+
+/* turn the led on/off based on default value field (ETH_MAC_GEN_LED_CFG_DEF) */
+#define ETH_MAC_GEN_LED_CFG_SEL_DEFAULT_REG	0
+
+/* LED default value */
+#define ETH_MAC_GEN_LED_CFG_DEF          BIT(4)
+
+#define ETH_MAC_SGMII_REG_ADDR_CTRL_REG	0x0
+#define ETH_MAC_SGMII_REG_ADDR_IF_MODE_REG 0x14
+
+#define ETH_MAC_SGMII_REG_DATA_CTRL_AN_ENABLE			BIT(12)
+#define ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_EN			BIT(0)
+#define ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_AN			BIT(1)
+#define ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_SPEED_10		0x0
+#define ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_SPEED_100		0x1
+#define ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_SPEED_1000		0x2
+#define ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_DUPLEX		BIT(4)
+
+/* command config */
+#define ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_ADDR	0x00000008
+#define ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_TX_ENA	BIT(0)
+#define ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_RX_ENA	BIT(1)
+#define ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_PFC_MODE	BIT(19)
+
+/* frame length */
+#define ETH_MAC_GEN_V3_MAC_40G_FRM_LENGTH_ADDR		0x00000014
+
+#define ETH_MAC_GEN_V3_MAC_40G_CL01_PAUSE_QUANTA_ADDR	0x00000054
+#define ETH_MAC_GEN_V3_MAC_40G_CL23_PAUSE_QUANTA_ADDR	0x00000058
+#define ETH_MAC_GEN_V3_MAC_40G_CL45_PAUSE_QUANTA_ADDR	0x0000005C
+#define ETH_MAC_GEN_V3_MAC_40G_CL67_PAUSE_QUANTA_ADDR	0x00000060
+#define ETH_MAC_GEN_V3_MAC_40G_CL01_QUANTA_THRESH_ADDR	0x00000064
+#define ETH_MAC_GEN_V3_MAC_40G_CL23_QUANTA_THRESH_ADDR	0x00000068
+#define ETH_MAC_GEN_V3_MAC_40G_CL45_QUANTA_THRESH_ADDR	0x0000006C
+#define ETH_MAC_GEN_V3_MAC_40G_CL67_QUANTA_THRESH_ADDR	0x00000070
+
+/* spare */
+#define ETH_MAC_GEN_V3_SPARE_CHICKEN_DISABLE_TIMESTAMP_STRETCH BIT(0)
+
+#endif /* __AL_HW_ETH_MAC_REGS_H__ */
diff --git a/drivers/net/ethernet/annapurna/al_hw_eth_main.c b/drivers/net/ethernet/annapurna/al_hw_eth_main.c
new file mode 100644
index 000000000000..abb9ffd09fbf
--- /dev/null
+++ b/drivers/net/ethernet/annapurna/al_hw_eth_main.c
@@ -0,0 +1,3050 @@
+/*
+ * Copyright (C) 2017, Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/soc/alpine/iofic.h>
+#include <linux/soc/alpine/al_hw_udma_iofic.h>
+#include <linux/soc/alpine/al_hw_udma_config.h>
+
+#include "al_hw_eth.h"
+#include "al_hw_eth_ec_regs.h"
+#include "al_hw_eth_mac_regs.h"
+#include "al_hw_unit_adapter_regs.h"
+
+#define AL_ADDR_LOW(x)	((u32)((dma_addr_t)(x)))
+#define AL_ADDR_HIGH(x)	((u32)((((dma_addr_t)(x)) >> 16) >> 16))
+
+#define AL_ETH_TX_PKT_UDMA_FLAGS	(AL_ETH_TX_FLAGS_NO_SNOOP | \
+					 AL_ETH_TX_FLAGS_INT)
+
+#define AL_ETH_TX_PKT_META_FLAGS	(AL_ETH_TX_FLAGS_IPV4_L3_CSUM | \
+					 AL_ETH_TX_FLAGS_L4_CSUM |	\
+					 AL_ETH_TX_FLAGS_L4_PARTIAL_CSUM |	\
+					 AL_ETH_TX_FLAGS_L2_MACSEC_PKT | \
+					 AL_ETH_TX_FLAGS_L2_DIS_FCS |\
+					 AL_ETH_TX_FLAGS_TSO |\
+					 AL_ETH_TX_FLAGS_TS)
+
+#define AL_ETH_TX_SRC_VLAN_CNT_SHIFT		5
+#define AL_ETH_TX_L4_PROTO_IDX_SHIFT		8
+#define AL_ETH_TX_TUNNEL_MODE_SHIFT		18
+#define AL_ETH_TX_OUTER_L3_PROTO_SHIFT		20
+#define AL_ETH_TX_VLAN_MOD_ADD_SHIFT		22
+#define AL_ETH_TX_VLAN_MOD_DEL_SHIFT		24
+#define AL_ETH_TX_VLAN_MOD_E_SEL_SHIFT		26
+#define AL_ETH_TX_VLAN_MOD_VID_SEL_SHIFT	28
+#define AL_ETH_TX_VLAN_MOD_PBIT_SEL_SHIFT	30
+
+/* tx Meta Descriptor defines */
+#define AL_ETH_TX_META_STORE			BIT(21)
+#define AL_ETH_TX_META_L3_LEN_MASK		0xff
+#define AL_ETH_TX_META_L3_OFF_MASK		0xff
+#define AL_ETH_TX_META_L3_OFF_SHIFT		8
+#define AL_ETH_TX_META_MSS_LSB_VAL_SHIFT	22
+#define AL_ETH_TX_META_MSS_MSB_TS_VAL_SHIFT	16
+#define AL_ETH_TX_META_OUTER_L3_LEN_MASK	0x1f
+#define AL_ETH_TX_META_OUTER_L3_LEN_SHIFT	24
+#define AL_ETH_TX_META_OUTER_L3_OFF_HIGH_MASK	0x18
+#define AL_ETH_TX_META_OUTER_L3_OFF_HIGH_SHIFT	10
+#define AL_ETH_TX_META_OUTER_L3_OFF_LOW_MASK	0x07
+#define AL_ETH_TX_META_OUTER_L3_OFF_LOW_SHIFT	29
+
+/* Rx Descriptor defines */
+#define AL_ETH_RX_L3_PROTO_IDX_MASK	0x1F
+#define AL_ETH_RX_L4_PROTO_IDX_MASK	0x1F
+#define AL_ETH_RX_L4_PROTO_IDX_SHIFT	8
+
+#define AL_ETH_RX_L3_OFFSET_SHIFT	9
+#define AL_ETH_RX_L3_OFFSET_MASK	(0x7f << AL_ETH_RX_L3_OFFSET_SHIFT)
+#define AL_ETH_RX_HASH_SHIFT		16
+#define AL_ETH_RX_HASH_MASK		(0xffff		<< AL_ETH_RX_HASH_SHIFT)
+
+#define AL_ETH_MDIO_DELAY_PERIOD	1 /* micro seconds to wait when polling mdio status */
+#define AL_ETH_MDIO_DELAY_COUNT		150 /* number of times to poll */
+#define AL_ETH_S2M_UDMA_COMP_COAL_TIMEOUT	200 /* Rx descriptors coalescing timeout in SB clocks */
+
+#define AL_ETH_EPE_ENTRIES_NUM 26
+static struct al_eth_epe_p_reg_entry al_eth_epe_p_regs[AL_ETH_EPE_ENTRIES_NUM] = {
+	{ 0x0, 0x0, 0x0 },
+	{ 0x0, 0x0, 0x1 },
+	{ 0x0, 0x0, 0x2 },
+	{ 0x0, 0x0, 0x3 },
+	{ 0x18100, 0xFFFFF, 0x80000004 },
+	{ 0x188A8, 0xFFFFF, 0x80000005 },
+	{ 0x99100, 0xFFFFF, 0x80000006 },
+	{ 0x98100, 0xFFFFF, 0x80000007 },
+	{ 0x10800, 0x7FFFF, 0x80000008 },
+	{ 0x20000, 0x73FFF, 0x80000009 },
+	{ 0x20000, 0x70000, 0x8000000A },
+	{ 0x186DD, 0x7FFFF, 0x8000000B },
+	{ 0x30600, 0x7FF00, 0x8000000C },
+	{ 0x31100, 0x7FF00, 0x8000000D },
+	{ 0x32F00, 0x7FF00, 0x8000000E },
+	{ 0x32900, 0x7FF00, 0x8000000F },
+	{ 0x105DC, 0x7FFFF, 0x80010010 },
+	{ 0x188E5, 0x7FFFF, 0x80000011 },
+	{ 0x72000, 0x72000, 0x80000012 },
+	{ 0x70000, 0x72000, 0x80000013 },
+	{ 0x46558, 0x7FFFF, 0x80000001 },
+	{ 0x18906, 0x7FFFF, 0x80000015 },
+	{ 0x18915, 0x7FFFF, 0x80000016 },
+	{ 0x31B00, 0x7FF00, 0x80000017 },
+	{ 0x30400, 0x7FF00, 0x80000018 },
+	{ 0x0, 0x0, 0x8000001F }
+};
+
+static struct al_eth_epe_control_entry al_eth_epe_control_table[AL_ETH_EPE_ENTRIES_NUM] = {
+	{ { 0x2800000, 0x0, 0x0, 0x0, 0x1, 0x400000 } },
+	{ { 0x280004C, 0x746000, 0xA46030, 0xE00000, 0x2, 0x400000 } },
+	{ { 0x2800054, 0x746000, 0xA46030, 0x1600000, 0x2, 0x400000 } },
+	{ { 0x280005C, 0x746000, 0xA46030, 0x1E00000, 0x2, 0x400000 } },
+	{ { 0x2800042, 0xD42000, 0x0, 0x400000, 0x1010412, 0x400000 } },
+	{ { 0x2800042, 0xD42000, 0x0, 0x400000, 0x1010412, 0x400000 } },
+	{ { 0x2800042, 0xE42000, 0x0, 0x400000, 0x2020002, 0x400000 } },
+	{ { 0x2800042, 0xE42000, 0x0, 0x400000, 0x2020002, 0x400000 } },
+	{ { 0x280B046, 0x0, 0x6C1008, 0x0, 0x4, 0x406800 } },
+	{ { 0x2800049, 0xF44060, 0x1744080, 0x14404, 0x6, 0x400011 } },
+	{ { 0x2015049, 0xF44060, 0x1744080, 0x14404, 0x8080007, 0x400011 } },
+	{ { 0x280B046, 0xF60040, 0x6C1004, 0x2800000, 0x6, 0x406811 } },
+	{ { 0x2815042, 0x1F42000, 0x2042010, 0x1414460, 0x10100009, 0x40B800 } },
+	{ { 0x2815042, 0x1F42000, 0x2042010, 0x800000, 0x10100009, 0x40B800 } },
+	{ { 0x280B042, 0x0, 0x0, 0x430400, 0x4040009, 0x0 } },
+	{ { 0x2815580, 0x0, 0x0, 0x0, 0x4040005, 0x0 } },
+	{ { 0x280B000, 0x0, 0x0, 0x0, 0x1, 0x400000 } },
+	{ { 0x2800040, 0x174E000, 0x0, 0x0, 0xE, 0x406800 } },
+	{ { 0x280B000, 0x0, 0x0, 0x600000, 0x1, 0x406800 } },
+	{ { 0x280B000, 0x0, 0x0, 0xE00000, 0x1, 0x406800 } },
+	{ { 0x2800000, 0x0, 0x0, 0x0, 0x1, 0x400000 } },
+	{ { 0x280B046, 0x0, 0x0, 0x2800000, 0x7, 0x400000 } },
+	{ { 0x280B046, 0xF60040, 0x6C1004, 0x2800000, 0x6, 0x406811 } },
+	{ { 0x2815042, 0x1F43028, 0x2000000, 0xC00000, 0x10100009, 0x40B800 } },
+	{ { 0x2815400, 0x0, 0x0, 0x0, 0x4040005, 0x0 } },
+	{ { 0x2800000, 0x0, 0x0, 0x0, 0x1, 0x400000 } }
+};
+
+#define AL_ETH_IS_1G_MAC(mac_mode) (((mac_mode) == AL_ETH_MAC_MODE_RGMII) || ((mac_mode) == AL_ETH_MAC_MODE_SGMII))
+#define AL_ETH_IS_10G_MAC(mac_mode)	(((mac_mode) == AL_ETH_MAC_MODE_10GbE_Serial) ||	\
+					((mac_mode) == AL_ETH_MAC_MODE_10G_SGMII) ||		\
+					((mac_mode) == AL_ETH_MAC_MODE_SGMII_2_5G))
+#define AL_ETH_IS_25G_MAC(mac_mode) ((mac_mode) == AL_ETH_MAC_MODE_KR_LL_25G)
+
+static const char *al_eth_mac_mode_str(enum al_eth_mac_mode mode)
+{
+	switch (mode) {
+	case AL_ETH_MAC_MODE_RGMII:
+		return "RGMII";
+	case AL_ETH_MAC_MODE_SGMII:
+		return "SGMII";
+	case AL_ETH_MAC_MODE_SGMII_2_5G:
+		return "SGMII_2_5G";
+	case AL_ETH_MAC_MODE_10GbE_Serial:
+		return "KR";
+	case AL_ETH_MAC_MODE_KR_LL_25G:
+		return "KR_LL_25G";
+	case AL_ETH_MAC_MODE_10G_SGMII:
+		return "10G_SGMII";
+	case AL_ETH_MAC_MODE_XLG_LL_40G:
+		return "40G_LL";
+	case AL_ETH_MAC_MODE_XLG_LL_50G:
+		return "50G_LL";
+	case AL_ETH_MAC_MODE_XLG_LL_25G:
+		return "25G_LL";
+	default:
+		return "N/A";
+	}
+}
+
+/*
+ * change and wait udma state
+ *
+ * @param dma the udma to change its state
+ * @param new_state
+ *
+ * @return 0 on success. otherwise on failure.
+ */
+static int al_udma_state_set_wait(struct al_hw_eth_adapter *adapter,
+				  struct al_udma *dma,
+				  enum al_udma_state new_state)
+{
+	enum al_udma_state state;
+	enum al_udma_state expected_state = new_state;
+	int count = 1000;
+
+	al_udma_state_set(dma, new_state);
+
+	if ((new_state == UDMA_NORMAL) || (new_state == UDMA_DISABLE))
+		expected_state = UDMA_IDLE;
+
+	do {
+		state = al_udma_state_get(dma);
+		if (state == expected_state)
+			break;
+		udelay(1);
+		if (count-- == 0) {
+			netdev_warn(adapter->netdev,
+				    "[%s] warn: dma state didn't change to %s\n",
+				    dma->name, al_udma_states_name[new_state]);
+			return -ETIMEDOUT;
+		}
+	} while (1);
+	return 0;
+}
+
+static void al_eth_epe_entry_set(struct al_hw_eth_adapter *adapter, u32 idx,
+				 struct al_eth_epe_p_reg_entry *reg_entry,
+				 struct al_eth_epe_control_entry *control_entry)
+{
+	writel(reg_entry->data, &adapter->ec_regs_base->epe_p[idx].comp_data);
+	writel(reg_entry->mask, &adapter->ec_regs_base->epe_p[idx].comp_mask);
+	writel(reg_entry->ctrl, &adapter->ec_regs_base->epe_p[idx].comp_ctrl);
+
+	writel(reg_entry->data,
+	       &adapter->ec_regs_base->msp_c[idx].p_comp_data);
+	writel(reg_entry->mask,
+	       &adapter->ec_regs_base->msp_c[idx].p_comp_mask);
+	writel(reg_entry->ctrl,
+	       &adapter->ec_regs_base->msp_c[idx].p_comp_ctrl);
+
+	/*control table  0*/
+	writel(idx, &adapter->ec_regs_base->epe[0].act_table_addr);
+	writel(control_entry->data[5],
+	       &adapter->ec_regs_base->epe[0].act_table_data_6);
+	writel(control_entry->data[1],
+	       &adapter->ec_regs_base->epe[0].act_table_data_2);
+	writel(control_entry->data[2],
+	       &adapter->ec_regs_base->epe[0].act_table_data_3);
+	writel(control_entry->data[3],
+	       &adapter->ec_regs_base->epe[0].act_table_data_4);
+	writel(control_entry->data[4],
+	       &adapter->ec_regs_base->epe[0].act_table_data_5);
+	writel(control_entry->data[0],
+	       &adapter->ec_regs_base->epe[0].act_table_data_1);
+
+	/*control table 1*/
+	writel(idx, &adapter->ec_regs_base->epe[1].act_table_addr);
+	writel(control_entry->data[5],
+	       &adapter->ec_regs_base->epe[1].act_table_data_6);
+	writel(control_entry->data[1],
+	       &adapter->ec_regs_base->epe[1].act_table_data_2);
+	writel(control_entry->data[2],
+	       &adapter->ec_regs_base->epe[1].act_table_data_3);
+	writel(control_entry->data[3],
+	       &adapter->ec_regs_base->epe[1].act_table_data_4);
+	writel(control_entry->data[4],
+	       &adapter->ec_regs_base->epe[1].act_table_data_5);
+	writel(control_entry->data[0],
+	       &adapter->ec_regs_base->epe[1].act_table_data_1);
+}
+
+static void al_eth_epe_init(struct al_hw_eth_adapter *adapter)
+{
+	int idx;
+
+	if (adapter->enable_rx_parser == 0) {
+		netdev_dbg(adapter->netdev, "eth [%s]: disable rx parser\n",
+			   adapter->name);
+
+		writel(0x08000000, &adapter->ec_regs_base->epe[0].res_def);
+		writel(0x7, &adapter->ec_regs_base->epe[0].res_in);
+
+		writel(0x08000000, &adapter->ec_regs_base->epe[1].res_def);
+		writel(0x7, &adapter->ec_regs_base->epe[1].res_in);
+
+		return;
+	}
+
+	for (idx = 0; idx < AL_ETH_EPE_ENTRIES_NUM; idx++)
+		al_eth_epe_entry_set(adapter, idx, &al_eth_epe_p_regs[idx],
+				     &al_eth_epe_control_table[idx]);
+
+	writel(0x08000080, &adapter->ec_regs_base->epe[0].res_def);
+	writel(0x7, &adapter->ec_regs_base->epe[0].res_in);
+
+	writel(0x08000080, &adapter->ec_regs_base->epe[1].res_def);
+	writel(0, &adapter->ec_regs_base->epe[1].res_in);
+
+	/*
+	 * header length as function of 4 bits value, for GRE, when C bit
+	 * is set, the header len should be increase by 4
+	 */
+	writel((4 << 16) | 4, &adapter->ec_regs_base->epe_h[8].hdr_len);
+
+	/*
+	 * select the outer information when writing the rx descriptor
+	 * (l3 protocol index etc)
+	 */
+	writel(EC_RFW_META_L3_LEN_CALC, &adapter->ec_regs_base->rfw.meta);
+
+	writel(EC_RFW_CHECKSUM_HDR_SEL, &adapter->ec_regs_base->rfw.checksum);
+}
+
+/*
+ * read 40G MAC registers (indirect access)
+ *
+ * @param adapter pointer to the private structure
+ * @param reg_addr address in the an registers
+ *
+ * @return the register value
+ */
+static u32 al_eth_40g_mac_reg_read(struct al_hw_eth_adapter *adapter,
+				   u32 reg_addr)
+{
+	u32 val;
+
+	/* indirect access */
+	writel(reg_addr, &adapter->mac_regs_base->gen_v3.mac_40g_ll_addr);
+	val = readl(&adapter->mac_regs_base->gen_v3.mac_40g_ll_data);
+
+	return val;
+}
+
+/*
+ * write 40G MAC registers (indirect access)
+ *
+ * @param adapter pointer to the private structure
+ * @param reg_addr address in the an registers
+ * @param reg_data value to write to the register
+ *
+ */
+static void al_eth_40g_mac_reg_write(struct al_hw_eth_adapter *adapter,
+				     u32 reg_addr, u32 reg_data)
+{
+	/* indirect access */
+	writel(reg_addr, &adapter->mac_regs_base->gen_v3.mac_40g_ll_addr);
+	writel(reg_data, &adapter->mac_regs_base->gen_v3.mac_40g_ll_data);
+}
+
+/*
+ * write 40G PCS registers (indirect access)
+ *
+ * @param adapter pointer to the private structure
+ * @param reg_addr address in the an registers
+ * @param reg_data value to write to the register
+ *
+ */
+static void al_eth_40g_pcs_reg_write(struct al_hw_eth_adapter *adapter,
+				     u32 reg_addr, u32 reg_data)
+{
+	/* indirect access */
+	writel(reg_addr, &adapter->mac_regs_base->gen_v3.pcs_40g_ll_addr);
+	writel(reg_data, &adapter->mac_regs_base->gen_v3.pcs_40g_ll_data);
+}
+
+/*
+ * initialize the ethernet adapter's DMA
+ */
+int al_eth_adapter_init(struct al_hw_eth_adapter *adapter,
+			struct al_eth_adapter_params *params)
+{
+	struct al_udma_params udma_params;
+	struct al_udma_m2s_pkt_len_conf conf;
+	int i;
+	u32 reg;
+	int rc;
+
+	netdev_dbg(adapter->netdev,
+		   "eth [%s]: initialize controller's UDMA. id = %d\n",
+		   params->name, params->udma_id);
+	netdev_dbg(adapter->netdev, "eth [%s]: enable_rx_parser: %x\n",
+		   params->name, params->enable_rx_parser);
+
+	adapter->name = params->name;
+	adapter->rev_id = params->rev_id;
+	adapter->netdev = params->netdev;
+	adapter->udma_id = params->udma_id;
+	adapter->udma_regs_base = params->udma_regs_base;
+	adapter->ec_regs_base =
+		(struct al_ec_regs __iomem *)params->ec_regs_base;
+	adapter->mac_regs_base =
+		(struct al_eth_mac_regs __iomem *)params->mac_regs_base;
+	adapter->unit_regs = (struct unit_regs __iomem *)params->udma_regs_base;
+	adapter->enable_rx_parser = params->enable_rx_parser;
+	adapter->ec_ints_base = (u8 __iomem *)adapter->ec_regs_base + 0x1c00;
+	adapter->mac_ints_base = (struct interrupt_controller_ctrl __iomem *)
+				 ((u8 __iomem *)adapter->mac_regs_base + 0x800);
+
+	/* initialize Tx udma */
+	udma_params.dev = adapter->netdev->dev.parent;
+	udma_params.udma_regs_base = adapter->unit_regs;
+	udma_params.type = UDMA_TX;
+	udma_params.cdesc_size = AL_ETH_UDMA_TX_CDESC_SZ;
+	udma_params.num_of_queues = AL_ETH_UDMA_TX_QUEUES;
+	udma_params.name = "eth tx";
+	rc = al_udma_init(&adapter->tx_udma, &udma_params);
+
+	if (rc != 0) {
+		netdev_err(adapter->netdev,
+			   "failed to initialize %s, error %d\n",
+			   udma_params.name, rc);
+		return rc;
+	}
+	rc = al_udma_state_set_wait(adapter, &adapter->tx_udma, UDMA_NORMAL);
+	if (rc != 0) {
+		netdev_err(adapter->netdev,
+			   "[%s]: failed to change state, error %d\n",
+			   udma_params.name, rc);
+		return rc;
+	}
+	/* initialize Rx udma */
+	udma_params.dev = adapter->netdev->dev.parent;
+	udma_params.udma_regs_base = adapter->unit_regs;
+	udma_params.type = UDMA_RX;
+	udma_params.cdesc_size = AL_ETH_UDMA_RX_CDESC_SZ;
+	udma_params.num_of_queues = AL_ETH_UDMA_RX_QUEUES;
+	udma_params.name = "eth rx";
+	rc = al_udma_init(&adapter->rx_udma, &udma_params);
+
+	if (rc != 0) {
+		netdev_err(adapter->netdev,
+			   "failed to initialize %s, error %d\n",
+			   udma_params.name, rc);
+		return rc;
+	}
+
+	rc = al_udma_state_set_wait(adapter, &adapter->rx_udma, UDMA_NORMAL);
+	if (rc != 0) {
+		netdev_err(adapter->netdev,
+			   "[%s]: failed to change state, error %d\n",
+			   udma_params.name, rc);
+		return rc;
+	}
+
+	netdev_dbg(adapter->netdev,
+		   "eth [%s]: controller's UDMA successfully initialized\n",
+		   params->name);
+
+	/* set max packet size to 1M (for TSO) */
+	conf.encode_64k_as_zero = true;
+	conf.max_pkt_size = 0xfffff;
+	al_udma_m2s_packet_size_cfg_set(&adapter->tx_udma, &conf);
+
+	/*
+	 * Set m2s (tx) max descriptors to max data buffers number and one for
+	 * meta descriptor
+	 */
+	al_udma_m2s_max_descs_set(&adapter->tx_udma, AL_ETH_PKT_MAX_BUFS + 1);
+
+	/* set s2m (rx) max descriptors to max data buffers */
+	al_udma_s2m_max_descs_set(&adapter->rx_udma, AL_ETH_PKT_MAX_BUFS);
+
+	/*
+	 * set s2m burst length when writing completion descriptors to
+	 * 64 bytes
+	 */
+	al_udma_s2m_compl_desc_burst_config(&adapter->rx_udma, 64);
+
+	/* if pointer to ec regs provided, then init the tx meta cache of this udma*/
+	if (adapter->ec_regs_base) {
+		/* INIT TX CACHE TABLE: */
+		for (i = 0; i < 4; i++) {
+			writel(i + (adapter->udma_id * 4),
+			       &adapter->ec_regs_base->tso.cache_table_addr);
+			writel(0x00000000,
+			       &adapter->ec_regs_base->tso.cache_table_data_1);
+			writel(0x00000000,
+			       &adapter->ec_regs_base->tso.cache_table_data_2);
+			writel(0x00000000,
+			       &adapter->ec_regs_base->tso.cache_table_data_3);
+			writel(0x00000000,
+			       &adapter->ec_regs_base->tso.cache_table_data_4);
+		}
+	}
+	/* only udma 0 allowed to init ec */
+	if (adapter->udma_id != 0)
+		return 0;
+
+	/* enable internal machines*/
+	writel(0xffffffff, &adapter->ec_regs_base->gen.en);
+	writel(0xffffffff, &adapter->ec_regs_base->gen.fifo_en);
+
+	/* enable A0 descriptor structure */
+	writel(readl(&adapter->ec_regs_base->gen.en_ext) | EC_GEN_EN_EXT_CACHE_WORD_SPLIT,
+	       &adapter->ec_regs_base->gen.en_ext);
+
+	/* use mss value in the descriptor */
+	writel(EC_TSO_CFG_ADD_0_MSS_SEL,
+	       &adapter->ec_regs_base->tso.cfg_add_0);
+
+	/* enable tunnel TSO */
+	reg = EC_TSO_CFG_TUNNEL_EN_TUNNEL_TSO | EC_TSO_CFG_TUNNEL_EN_UDP_CHKSUM |
+		EC_TSO_CFG_TUNNEL_EN_UDP_LEN | EC_TSO_CFG_TUNNEL_EN_IPV6_PLEN |
+		EC_TSO_CFG_TUNNEL_EN_IPV4_CHKSUM | EC_TSO_CFG_TUNNEL_EN_IPV4_IDEN |
+		EC_TSO_CFG_TUNNEL_EN_IPV4_TLEN;
+	writel(reg, &adapter->ec_regs_base->tso.cfg_tunnel);
+
+	/* swap input byts from MAC RX */
+	writel(0x1, &adapter->ec_regs_base->mac.gen);
+	/* swap output bytes to MAC TX*/
+	writel(EC_TMI_TX_CFG_EN_FWD_TO_RX | EC_TMI_TX_CFG_SWAP_BYTES,
+	       &adapter->ec_regs_base->tmi.tx_cfg);
+
+	writel(0x3fb, &adapter->ec_regs_base->tfw_udma[0].fwd_dec);
+
+	/* RFW configuration: default 0 */
+	writel(0x1, &adapter->ec_regs_base->rfw_default[0].opt_1);
+
+	/* VLAN table address */
+	writel(0x0, &adapter->ec_regs_base->rfw.vid_table_addr);
+	/* VLAN table data */
+	writel(0x0, &adapter->ec_regs_base->rfw.vid_table_data);
+	/*
+	 * HASH config (select toeplitz and bits 7:0 of the thash result, enable
+	 * symmetric hash)
+	 */
+	reg = EC_RFW_THASH_CFG_1_ENABLE_IP_SWAP | EC_RFW_THASH_CFG_1_ENABLE_PORT_SWAP;
+	writel(reg, &adapter->ec_regs_base->rfw.thash_cfg_1);
+
+	al_eth_epe_init(adapter);
+
+	/* disable TSO padding and use mac padding instead */
+	reg = readl(&adapter->ec_regs_base->tso.in_cfg);
+	reg &= ~0x7F00; /*clear bits 14:8 */
+	writel(reg, &adapter->ec_regs_base->tso.in_cfg);
+
+	return 0;
+}
+
+/*
+ * stop the DMA of the ethernet adapter
+ */
+int al_eth_adapter_stop(struct al_hw_eth_adapter *adapter)
+{
+	int rc;
+
+	netdev_dbg(adapter->netdev, "eth [%s]: stop controller's UDMA\n",
+		   adapter->name);
+
+	/* disable Tx dma*/
+	rc = al_udma_state_set_wait(adapter, &adapter->tx_udma, UDMA_DISABLE);
+	if (rc != 0) {
+		netdev_warn(adapter->netdev,
+			    "[%s] warn: failed to change state, error %d\n",
+			    adapter->tx_udma.name, rc);
+		return rc;
+	}
+
+	netdev_dbg(adapter->netdev, "eth [%s]: controller's TX UDMA stopped\n",
+		   adapter->name);
+
+	/* disable Rx dma*/
+	rc = al_udma_state_set_wait(adapter, &adapter->rx_udma, UDMA_DISABLE);
+	if (rc != 0) {
+		netdev_warn(adapter->netdev,
+			    "[%s] warn: failed to change state, error %d\n",
+			    adapter->rx_udma.name, rc);
+		return rc;
+	}
+
+	netdev_dbg(adapter->netdev, "eth [%s]: controller's RX UDMA stopped\n",
+		   adapter->name);
+	return 0;
+}
+
+/* Q management */
+/*
+ * Configure and enable a queue ring
+ */
+int al_eth_queue_config(struct al_hw_eth_adapter *adapter,
+			enum al_udma_type type, u32 qid,
+			struct al_udma_q_params *q_params)
+{
+	struct al_udma *udma;
+	int rc;
+
+	netdev_dbg(adapter->netdev, "eth [%s]: config UDMA %s queue %d\n",
+		   adapter->name, type == UDMA_TX ? "Tx" : "Rx", qid);
+
+	udma = (type == UDMA_TX) ? &adapter->tx_udma : &adapter->rx_udma;
+	q_params->adapter_rev_id = adapter->rev_id;
+
+	rc = al_udma_q_init(udma, qid, q_params);
+	if (rc)
+		return rc;
+
+	if (type == UDMA_RX)
+		al_udma_s2m_q_compl_coal_config(&udma->udma_q[qid], true,
+						AL_ETH_S2M_UDMA_COMP_COAL_TIMEOUT);
+
+	return rc;
+}
+
+/* MAC layer */
+int al_eth_rx_pkt_limit_config(struct al_hw_eth_adapter *adapter,
+			       u32 min_rx_len, u32 max_rx_len)
+{
+	WARN_ON(AL_ETH_MAX_FRAME_LEN < max_rx_len);
+
+	/* EC minimum packet length [bytes] in RX */
+	writel(min_rx_len, &adapter->ec_regs_base->mac.min_pkt);
+	/* EC maximum packet length [bytes] in RX */
+	writel(max_rx_len, &adapter->ec_regs_base->mac.max_pkt);
+
+	if (adapter->rev_id > AL_ETH_REV_ID_2) {
+		writel(min_rx_len,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_1);
+		writel(max_rx_len,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_2);
+	}
+
+	/*
+	 * configure the MAC's max rx length, add 16 bytes so the packet get
+	 * trimmed by the EC/Async_fifo rather by the MAC
+	 */
+	if (AL_ETH_IS_1G_MAC(adapter->mac_mode))
+		writel(max_rx_len + 16,
+		       &adapter->mac_regs_base->mac_1g.frm_len);
+	else if (AL_ETH_IS_10G_MAC(adapter->mac_mode) ||
+		 AL_ETH_IS_25G_MAC(adapter->mac_mode))
+		/* 10G MAC control register  */
+		writel((max_rx_len + 16),
+		       &adapter->mac_regs_base->mac_10g.frm_len);
+	else
+		al_eth_40g_mac_reg_write(adapter,
+					 ETH_MAC_GEN_V3_MAC_40G_FRM_LENGTH_ADDR,
+					 (max_rx_len + 16));
+
+	return 0;
+}
+
+/* configure the mac media type. */
+int al_eth_mac_config(struct al_hw_eth_adapter *adapter, enum al_eth_mac_mode mode)
+{
+	u32 tmp;
+
+	switch (mode) {
+	case AL_ETH_MAC_MODE_RGMII:
+		writel(0x40003210, &adapter->mac_regs_base->gen.clk_cfg);
+
+		/*
+		 * 1G MAC control register
+		 *
+		 * bit[0]  - TX_ENA - zeroed by default. Should be asserted by al_eth_mac_start
+		 * bit[1]  - RX_ENA - zeroed by default. Should be asserted by al_eth_mac_start
+		 * bit[3]  - ETH_SPEED - zeroed to enable 10/100 Mbps Ethernet
+		 * bit[4]  - PROMIS_EN - asserted to enable MAC promiscuous mode
+		 * bit[23] - CNTL_FRM-ENA - asserted to enable control frames
+		 * bit[24] - NO_LGTH_CHECK - asserted to disable length checks, which is done in the controller
+		 */
+		writel(0x01800010, &adapter->mac_regs_base->mac_1g.cmd_cfg);
+
+		writel(0x00000000,
+		       &adapter->mac_regs_base->mac_1g.rx_section_empty);
+		writel(0x0000000c,
+		       &adapter->mac_regs_base->mac_1g.rx_section_full);
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.rx_almost_empty);
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.rx_almost_full);
+
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.tx_section_empty);
+		writel(0x0000000c,
+		       &adapter->mac_regs_base->mac_1g.tx_section_full);
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.tx_almost_empty);
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.tx_almost_full);
+
+		writel(0x00000000, &adapter->mac_regs_base->gen.cfg);
+
+		/*
+		 * 1G MACSET 1G
+		 * taking sel_1000/sel_10 inputs from rgmii PHY, and not from register.
+		 * disabling magic_packets detection in mac
+		 */
+		writel(0x00000002, &adapter->mac_regs_base->gen.mac_1g_cfg);
+		/* RGMII set 1G */
+		tmp = readl(&adapter->mac_regs_base->gen.mux_sel);
+		tmp &= ETH_MAC_GEN_MUX_SEL_KR_IN_MASK;
+		tmp |= 0x63910;
+		writel(tmp, &adapter->mac_regs_base->gen.mux_sel);
+		writel(0xf, &adapter->mac_regs_base->gen.rgmii_sel);
+		break;
+	case AL_ETH_MAC_MODE_SGMII:
+		if (adapter->rev_id > AL_ETH_REV_ID_2) {
+			/*
+			 * Configure and enable the ASYNC FIFO between the MACs
+			 * and the EC
+			 */
+			/* TX min packet size */
+			writel(0x00000010,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_1);
+			/* TX max packet size */
+			writel(0x00002800,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_2);
+			/* TX input bus configuration */
+			writel(0x00000080,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_3);
+			/* TX output bus configuration */
+			writel(0x00030020,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_4);
+			/* TX Valid/ready configuration */
+			writel(0x00000121,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_5);
+			/* RX input bus configuration */
+			writel(0x00030020,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_3);
+			/* RX output bus configuration */
+			writel(0x00000080,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_4);
+			/* RX Valid/ready configuration */
+			writel(0x00000212,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_5);
+			/* V3 additional MAC selection */
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_sel);
+			writel(0x00000001,
+			       &adapter->mac_regs_base->gen_v3.mac_10g_ll_cfg);
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_10g_ll_ctrl);
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.pcs_10g_ll_cfg);
+			/* ASYNC FIFO ENABLE */
+			writel(0x00003333,
+			       &adapter->mac_regs_base->gen_v3.afifo_ctrl);
+			/* Timestamp_configuration */
+			writel(ETH_MAC_GEN_V3_SPARE_CHICKEN_DISABLE_TIMESTAMP_STRETCH,
+			       &adapter->mac_regs_base->gen_v3.spare);
+		}
+
+		writel(0x40053210, &adapter->mac_regs_base->gen.clk_cfg);
+
+		/*
+		 * 1G MAC control register
+		 *
+		 * bit[0]  - TX_ENA - zeroed by default. Should be asserted by al_eth_mac_start
+		 * bit[1]  - RX_ENA - zeroed by default. Should be asserted by al_eth_mac_start
+		 * bit[3]  - ETH_SPEED - zeroed to enable 10/100 Mbps Ethernet
+		 * bit[4]  - PROMIS_EN - asserted to enable MAC promiscuous mode
+		 * bit[23] - CNTL_FRM-ENA - asserted to enable control frames
+		 * bit[24] - NO_LGTH_CHECK - asserted to disable length checks, which is done in the controller
+		 */
+		writel(0x01800010, &adapter->mac_regs_base->mac_1g.cmd_cfg);
+
+		writel(0x00000000,
+		       &adapter->mac_regs_base->mac_1g.rx_section_empty);
+		writel(0x0000000c,
+		       &adapter->mac_regs_base->mac_1g.rx_section_full); /* must be larger than almost empty */
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.rx_almost_empty);
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.rx_almost_full);
+
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.tx_section_empty); /* 8 ? */
+		writel(0x0000000c,
+		       &adapter->mac_regs_base->mac_1g.tx_section_full);
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.tx_almost_empty);
+		writel(0x00000008,
+		       &adapter->mac_regs_base->mac_1g.tx_almost_full);
+
+		/* XAUI MAC control register */
+		writel(0x000000c0, &adapter->mac_regs_base->gen.cfg);
+
+		/*
+		 * 1G MACSET 1G
+		 * taking sel_1000/sel_10 inputs from rgmii_converter, and not from register.
+		 * disabling magic_packets detection in mac
+		 */
+		writel(0x00000002, &adapter->mac_regs_base->gen.mac_1g_cfg);
+
+		/* Setting PCS i/f mode to SGMII (instead of default 1000Base-X) */
+		writel(0x00000014, &adapter->mac_regs_base->sgmii.reg_addr);
+		writel(0x0000000b, &adapter->mac_regs_base->sgmii.reg_data);
+		/* setting dev_ability to have speed of 1000Mb, [11:10] = 2'b10 */
+		writel(0x00000004, &adapter->mac_regs_base->sgmii.reg_addr);
+		writel(0x000009A0, &adapter->mac_regs_base->sgmii.reg_data);
+
+		tmp = readl(&adapter->mac_regs_base->gen.led_cfg);
+		tmp &= ~ETH_MAC_GEN_LED_CFG_SEL_MASK;
+		tmp |= ETH_MAC_GEN_LED_CFG_SEL_DEFAULT_REG;
+		writel(tmp, &adapter->mac_regs_base->gen.led_cfg);
+		break;
+
+	case AL_ETH_MAC_MODE_SGMII_2_5G:
+		if (adapter->rev_id > AL_ETH_REV_ID_2) {
+			/* configure and enable the ASYNC FIFO between the MACs and the EC */
+			/* TX min packet size */
+			writel(0x00000010,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_1);
+			/* TX max packet size */
+			writel(0x00002800,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_2);
+			/* TX input bus configuration */
+			writel(0x00000080,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_3);
+			/* TX output bus configuration */
+			writel(0x00030020,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_4);
+			/* TX Valid/ready configuration */
+			writel(0x00000023,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_5);
+			/* RX input bus configuration */
+			writel(0x00030020,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_3);
+			/* RX output bus configuration */
+			writel(0x00000080,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_4);
+			/* RX Valid/ready configuration */
+			writel(0x00000012,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_5);
+			/* V3 additional MAC selection */
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_sel);
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_10g_ll_cfg);
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_10g_ll_ctrl);
+			writel(0x00000050,
+			       &adapter->mac_regs_base->gen_v3.pcs_10g_ll_cfg);
+			/* ASYNC FIFO ENABLE */
+			writel(0x00003333,
+			       &adapter->mac_regs_base->gen_v3.afifo_ctrl);
+		}
+
+		/* MAC register file */
+		writel(0x01022830, &adapter->mac_regs_base->mac_10g.cmd_cfg);
+		/* XAUI MAC control register */
+		writel(0x00000001, &adapter->mac_regs_base->gen.cfg);
+		writel(0x00000028, &adapter->mac_regs_base->mac_10g.if_mode);
+		writel(0x00001140, &adapter->mac_regs_base->mac_10g.control);
+		/* RXAUI MAC control register */
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_32_64);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_64_32);
+
+		tmp = readl(&adapter->mac_regs_base->gen.mux_sel);
+		tmp &= ETH_MAC_GEN_MUX_SEL_KR_IN_MASK;
+		tmp |= 0x00063910;
+		writel(tmp, &adapter->mac_regs_base->gen.mux_sel);
+
+		writel(0x40003210, &adapter->mac_regs_base->gen.clk_cfg);
+		writel(0x000004f0, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+		writel(0x00000401, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+
+		tmp = readl(&adapter->mac_regs_base->gen.led_cfg);
+		tmp &= ~ETH_MAC_GEN_LED_CFG_SEL_MASK;
+		tmp |= ETH_MAC_GEN_LED_CFG_SEL_DEFAULT_REG;
+		writel(tmp, &adapter->mac_regs_base->gen.led_cfg);
+		break;
+
+	case AL_ETH_MAC_MODE_10GbE_Serial:
+		if (adapter->rev_id > AL_ETH_REV_ID_2) {
+			/* configure and enable the ASYNC FIFO between the MACs and the EC */
+			/* TX min packet size */
+			writel(0x00000010,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_1);
+			/* TX max packet size */
+			writel(0x00002800,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_2);
+			/* TX input bus configuration */
+			writel(0x00000080,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_3);
+			/* TX output bus configuration */
+			writel(0x00030020,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_4);
+			/* TX Valid/ready configuration */
+			writel(0x00000023,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_5);
+			/* RX input bus configuration */
+			writel(0x00030020,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_3);
+			/* RX output bus configuration */
+			writel(0x00000080,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_4);
+			/* RX Valid/ready configuration */
+			writel(0x00000012,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_5);
+			/* V3 additional MAC selection */
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_sel);
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_10g_ll_cfg);
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_10g_ll_ctrl);
+			writel(0x00000050,
+			       &adapter->mac_regs_base->gen_v3.pcs_10g_ll_cfg);
+			/* ASYNC FIFO ENABLE */
+			writel(0x00003333,
+			       &adapter->mac_regs_base->gen_v3.afifo_ctrl);
+		}
+
+		/* MAC register file */
+		writel(0x01022810, &adapter->mac_regs_base->mac_10g.cmd_cfg);
+		/* XAUI MAC control register */
+		writel(0x00000005, &adapter->mac_regs_base->gen.cfg);
+		/* RXAUI MAC control register */
+		writel(0x00000007, &adapter->mac_regs_base->gen.rxaui_cfg);
+		writel(0x000001F1, &adapter->mac_regs_base->gen.sd_cfg);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_32_64);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_64_32);
+
+		tmp = readl(&adapter->mac_regs_base->gen.mux_sel);
+		tmp &= ETH_MAC_GEN_MUX_SEL_KR_IN_MASK;
+		tmp |= 0x73910;
+		writel(tmp, &adapter->mac_regs_base->gen.mux_sel);
+
+		writel(0x10003210, &adapter->mac_regs_base->gen.clk_cfg);
+		writel(0x000004f0, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+		writel(0x00000401, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+
+		tmp = readl(&adapter->mac_regs_base->gen.led_cfg);
+		tmp &= ~ETH_MAC_GEN_LED_CFG_SEL_MASK;
+		tmp |= ETH_MAC_GEN_LED_CFG_SEL_DEFAULT_REG;
+		writel(tmp, &adapter->mac_regs_base->gen.led_cfg);
+		break;
+
+	case AL_ETH_MAC_MODE_KR_LL_25G:
+		if (adapter->rev_id > AL_ETH_REV_ID_2) {
+			/* configure and enable the ASYNC FIFO between the MACs and the EC */
+			/* TX min packet size */
+			writel(0x00000010,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_1);
+			/* TX max packet size */
+			writel(0x00002800,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_2);
+			/* TX input bus configuration */
+			writel(0x00000080,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_3);
+			/* TX output bus configuration */
+			writel(0x00030020,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_4);
+			/* TX Valid/ready configuration */
+			writel(0x00000023,
+			       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_5);
+			/* RX input bus configuration */
+			writel(0x00030020,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_3);
+			/* RX output bus configuration */
+			writel(0x00000080,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_4);
+			/* RX Valid/ready configuration */
+			writel(0x00000012,
+			       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_5);
+			/* V3 additional MAC selection */
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_sel);
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_10g_ll_cfg);
+			writel(0x00000000,
+			       &adapter->mac_regs_base->gen_v3.mac_10g_ll_ctrl);
+			writel(0x000000a0,
+			       &adapter->mac_regs_base->gen_v3.pcs_10g_ll_cfg);
+			/* ASYNC FIFO ENABLE */
+			writel(0x00003333,
+			       &adapter->mac_regs_base->gen_v3.afifo_ctrl);
+		}
+
+		/* MAC register file */
+		writel(0x01022810, &adapter->mac_regs_base->mac_10g.cmd_cfg);
+		/* XAUI MAC control register */
+		writel(0x00000005, &adapter->mac_regs_base->gen.cfg);
+		/* RXAUI MAC control register */
+		writel(0x00000007, &adapter->mac_regs_base->gen.rxaui_cfg);
+		writel(0x000001F1, &adapter->mac_regs_base->gen.sd_cfg);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_32_64);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_64_32);
+
+		writel(0x000004f0, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+		writel(0x00000401, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+
+		tmp = readl(&adapter->mac_regs_base->gen.led_cfg);
+		tmp &= ETH_MAC_GEN_LED_CFG_SEL_MASK;
+		tmp |= ETH_MAC_GEN_LED_CFG_SEL_DEFAULT_REG;
+		writel(tmp, &adapter->mac_regs_base->gen.led_cfg);
+
+		break;
+
+	case AL_ETH_MAC_MODE_10G_SGMII:
+		/* MAC register file */
+		writel(0x01022810, &adapter->mac_regs_base->mac_10g.cmd_cfg);
+
+		/* XAUI MAC control register */
+		writel(0x00000001, &adapter->mac_regs_base->gen.cfg);
+
+		writel(0x0000002b, &adapter->mac_regs_base->mac_10g.if_mode);
+		writel(0x00009140, &adapter->mac_regs_base->mac_10g.control);
+
+		/* RXAUI MAC control register */
+		writel(0x00000007, &adapter->mac_regs_base->gen.rxaui_cfg);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_32_64);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_64_32);
+
+		tmp = readl(&adapter->mac_regs_base->gen.mux_sel);
+		tmp &= ETH_MAC_GEN_MUX_SEL_KR_IN_MASK;
+		tmp |= 0x00063910;
+		writel(tmp, &adapter->mac_regs_base->gen.mux_sel);
+
+		writel(0x40003210, &adapter->mac_regs_base->gen.clk_cfg);
+		writel(0x00000401, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+
+		tmp = readl(&adapter->mac_regs_base->gen.led_cfg);
+		tmp &= ~ETH_MAC_GEN_LED_CFG_SEL_MASK;
+		tmp |= ETH_MAC_GEN_LED_CFG_SEL_DEFAULT_REG;
+		writel(tmp, &adapter->mac_regs_base->gen.led_cfg);
+		break;
+
+	case AL_ETH_MAC_MODE_XLG_LL_40G:
+		/* configure and enable the ASYNC FIFO between the MACs and the EC */
+		/* TX min packet size */
+		writel(0x00000010,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_1);
+		/* TX max packet size */
+		writel(0x00002800,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_2);
+		/* TX input bus configuration */
+		writel(0x00000080,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_3);
+		/* TX output bus configuration */
+		writel(0x00010040,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_4);
+		/* TX Valid/ready configuration */
+		writel(0x00000023,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_5);
+		/* RX input bus configuration */
+		writel(0x00010040,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_3);
+		/* RX output bus configuration */
+		writel(0x00000080,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_4);
+		/* RX Valid/ready configuration */
+		writel(0x00000112,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_5);
+		/* V3 additional MAC selection */
+		writel(0x00000010, &adapter->mac_regs_base->gen_v3.mac_sel);
+		writel(0x00000000,
+		       &adapter->mac_regs_base->gen_v3.mac_10g_ll_cfg);
+		writel(0x00000000,
+		       &adapter->mac_regs_base->gen_v3.mac_10g_ll_ctrl);
+		writel(0x00000000,
+		       &adapter->mac_regs_base->gen_v3.pcs_10g_ll_cfg);
+		/* ASYNC FIFO ENABLE */
+		writel(0x00003333, &adapter->mac_regs_base->gen_v3.afifo_ctrl);
+
+		/* cmd_cfg */
+		writel(0x00000008,
+		       &adapter->mac_regs_base->gen_v3.mac_40g_ll_addr);
+		writel(0x01022810,
+		       &adapter->mac_regs_base->gen_v3.mac_40g_ll_data);
+
+		/* XAUI MAC control register */
+		tmp = readl(&adapter->mac_regs_base->gen.mux_sel);
+		tmp &= ETH_MAC_GEN_MUX_SEL_KR_IN_MASK;
+		tmp |= 0x06883910;
+		writel(tmp, &adapter->mac_regs_base->gen.mux_sel);
+		writel(0x0000040f, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+
+		/* XAUI MAC control register */
+		writel(0x00000005, &adapter->mac_regs_base->gen.cfg);
+		/* RXAUI MAC control register */
+		writel(0x00000007, &adapter->mac_regs_base->gen.rxaui_cfg);
+		writel(0x000001F1, &adapter->mac_regs_base->gen.sd_cfg);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_32_64);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_64_32);
+		writel(0x10003210, &adapter->mac_regs_base->gen.clk_cfg);
+
+		tmp = readl(&adapter->mac_regs_base->gen.led_cfg);
+		tmp &= ~ETH_MAC_GEN_LED_CFG_SEL_MASK;
+		tmp |= ETH_MAC_GEN_LED_CFG_SEL_DEFAULT_REG;
+		writel(tmp, &adapter->mac_regs_base->gen.led_cfg);
+		break;
+
+	case AL_ETH_MAC_MODE_XLG_LL_25G:
+		/* xgmii_mode: 0=xlgmii, 1=xgmii */
+		writel(0x0080,
+		       &adapter->mac_regs_base->gen_v3.mac_40g_ll_addr);
+		writel(0x00000001,
+		       &adapter->mac_regs_base->gen_v3.mac_40g_ll_data);
+
+		/* configure and enable the ASYNC FIFO between the MACs and the EC */
+		/* TX min packet size */
+		writel(0x00000010,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_1);
+		/* TX max packet size */
+		writel(0x00002800,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_2);
+		/* TX input bus configuration */
+		writel(0x00000080,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_3);
+		/* TX output bus configuration */
+		writel(0x00010040,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_4);
+		/* TX Valid/ready configuration */
+		writel(0x00000023,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_5);
+		/* RX input bus configuration */
+		writel(0x00010040,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_3);
+		/* RX output bus configuration */
+		writel(0x00000080,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_4);
+		/* RX Valid/ready configuration */
+		writel(0x00000112,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_5);
+		/* V3 additional MAC selection */
+		writel(0x00000010, &adapter->mac_regs_base->gen_v3.mac_sel);
+		writel(0x00000000,
+		       &adapter->mac_regs_base->gen_v3.mac_10g_ll_cfg);
+		writel(0x00000000,
+		       &adapter->mac_regs_base->gen_v3.mac_10g_ll_ctrl);
+		writel(0x00000000,
+		       &adapter->mac_regs_base->gen_v3.pcs_10g_ll_cfg);
+		/* ASYNC FIFO ENABLE */
+		writel(0x00003333, &adapter->mac_regs_base->gen_v3.afifo_ctrl);
+
+		/* cmd_cfg */
+		writel(0x00000008,
+		       &adapter->mac_regs_base->gen_v3.mac_40g_ll_addr);
+		writel(0x01022810,
+		       &adapter->mac_regs_base->gen_v3.mac_40g_ll_data);
+		/* use VL 0-2 for RXLAUI lane 0, use VL 1-3 for RXLAUI lane 1 */
+		al_eth_40g_pcs_reg_write(adapter, 0x00010008, 0x0d80);
+		/* configure the PCS to work 32 bit interface */
+		writel(0x00440000,
+		       &adapter->mac_regs_base->gen_v3.pcs_40g_ll_cfg);
+
+		/* disable MLD and move to clause 49 PCS: */
+		writel(0xE, &adapter->mac_regs_base->gen_v3.pcs_40g_ll_addr);
+		writel(0, &adapter->mac_regs_base->gen_v3.pcs_40g_ll_data);
+
+		/* XAUI MAC control register */
+		writel(0x0000040f, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+
+		/* XAUI MAC control register */
+		writel(0x00000005, &adapter->mac_regs_base->gen.cfg);
+		/* RXAUI MAC control register */
+		writel(0x00000007, &adapter->mac_regs_base->gen.rxaui_cfg);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_32_64);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_64_32);
+
+		tmp = readl(&adapter->mac_regs_base->gen.led_cfg);
+		tmp &= ~ETH_MAC_GEN_LED_CFG_SEL_MASK;
+		tmp |= ETH_MAC_GEN_LED_CFG_SEL_DEFAULT_REG;
+		writel(tmp, &adapter->mac_regs_base->gen.led_cfg);
+
+		break;
+
+	case AL_ETH_MAC_MODE_XLG_LL_50G:
+
+		/* configure and enable the ASYNC FIFO between the MACs and the EC */
+		/* TX min packet size */
+		writel(0x00000010,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_1);
+		/* TX max packet size */
+		writel(0x00002800,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_2);
+		/* TX input bus configuration */
+		writel(0x00000080,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_3);
+		/* TX output bus configuration */
+		writel(0x00010040,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_4);
+		/* TX Valid/ready configuration */
+		writel(0x00000023,
+		       &adapter->mac_regs_base->gen_v3.tx_afifo_cfg_5);
+		/* RX input bus configuration */
+		writel(0x00010040,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_3);
+		/* RX output bus configuration */
+		writel(0x00000080,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_4);
+		/* RX Valid/ready configuration */
+		writel(0x00000112,
+		       &adapter->mac_regs_base->gen_v3.rx_afifo_cfg_5);
+		/* V3 additional MAC selection */
+		writel(0x00000010, &adapter->mac_regs_base->gen_v3.mac_sel);
+		writel(0x00000000,
+		       &adapter->mac_regs_base->gen_v3.mac_10g_ll_cfg);
+		writel(0x00000000,
+		       &adapter->mac_regs_base->gen_v3.mac_10g_ll_ctrl);
+		writel(0x00000000,
+		       &adapter->mac_regs_base->gen_v3.pcs_10g_ll_cfg);
+		/* ASYNC FIFO ENABLE */
+		writel(0x00003333, &adapter->mac_regs_base->gen_v3.afifo_ctrl);
+
+		/* cmd_cfg */
+		writel(0x00000008,
+		       &adapter->mac_regs_base->gen_v3.mac_40g_ll_addr);
+		writel(0x01022810,
+		       &adapter->mac_regs_base->gen_v3.mac_40g_ll_data);
+
+		/* configure which two of the 4 PCS Lanes (VL) are combined to one RXLAUI lane */
+		/* use VL 0-2 for RXLAUI lane 0, use VL 1-3 for RXLAUI lane 1 */
+		al_eth_40g_pcs_reg_write(adapter, 0x00010008, 0x0d81);
+		/* configure the PCS to work 32 bit interface */
+		writel(0x00440000,
+		       &adapter->mac_regs_base->gen_v3.pcs_40g_ll_cfg);
+
+		/* XAUI MAC control register */
+		tmp = readl(&adapter->mac_regs_base->gen.mux_sel);
+		tmp &= ETH_MAC_GEN_MUX_SEL_KR_IN_MASK;
+		tmp |= 0x06883910;
+		writel(tmp, &adapter->mac_regs_base->gen.mux_sel);
+
+		writel(0x0000040f, &adapter->mac_regs_base->gen.sd_fifo_ctrl);
+
+		/* XAUI MAC control register */
+		writel(0x00000005, &adapter->mac_regs_base->gen.cfg);
+		/* RXAUI MAC control register */
+		writel(0x00000007, &adapter->mac_regs_base->gen.rxaui_cfg);
+		writel(0x000001F1, &adapter->mac_regs_base->gen.sd_cfg);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_32_64);
+		writel(0x00000401,
+		       &adapter->mac_regs_base->gen.xgmii_dfifo_64_32);
+		writel(0x10003210, &adapter->mac_regs_base->gen.clk_cfg);
+
+		tmp = readl(&adapter->mac_regs_base->gen.led_cfg);
+		tmp &= ~ETH_MAC_GEN_LED_CFG_SEL_MASK;
+		tmp |= ETH_MAC_GEN_LED_CFG_SEL_DEFAULT_REG;
+		writel(tmp, &adapter->mac_regs_base->gen.led_cfg);
+		break;
+
+	default:
+		netdev_err(adapter->netdev, "Eth: unsupported MAC mode %d",
+			   mode);
+		return -EPERM;
+	}
+	adapter->mac_mode = mode;
+	netdev_info(adapter->netdev, "configured MAC to %s mode:\n",
+		    al_eth_mac_mode_str(mode));
+
+	return 0;
+}
+
+/* start the mac */
+int al_eth_mac_start(struct al_hw_eth_adapter *adapter)
+{
+	u32 tmp;
+
+	if (AL_ETH_IS_1G_MAC(adapter->mac_mode)) {
+		/* 1G MAC control register */
+		tmp = readl(&adapter->mac_regs_base->mac_1g.cmd_cfg);
+		tmp |= ETH_1G_MAC_CMD_CFG_TX_ENA | ETH_1G_MAC_CMD_CFG_RX_ENA;
+		writel(tmp, &adapter->mac_regs_base->mac_1g.cmd_cfg);
+	} else if (AL_ETH_IS_10G_MAC(adapter->mac_mode) || AL_ETH_IS_25G_MAC(adapter->mac_mode)) {
+		/* 10G MAC control register  */
+		tmp = readl(&adapter->mac_regs_base->mac_10g.cmd_cfg);
+		tmp |= ETH_10G_MAC_CMD_CFG_TX_ENA | ETH_10G_MAC_CMD_CFG_RX_ENA;
+		writel(tmp, &adapter->mac_regs_base->mac_10g.cmd_cfg);
+	} else {
+		u32 cmd_cfg;
+
+		cmd_cfg = al_eth_40g_mac_reg_read(adapter,
+						  ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_ADDR);
+
+		cmd_cfg |= (ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_TX_ENA |
+			    ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_RX_ENA);
+
+		al_eth_40g_mac_reg_write(adapter,
+					 ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_ADDR,
+					 cmd_cfg);
+	}
+
+	return 0;
+}
+
+/* stop the mac */
+int al_eth_mac_stop(struct al_hw_eth_adapter *adapter)
+{
+	u32 tmp;
+
+	if (AL_ETH_IS_1G_MAC(adapter->mac_mode)) {
+		/* 1G MAC control register */
+		tmp = readl(&adapter->mac_regs_base->mac_1g.cmd_cfg);
+		tmp &= ~(ETH_1G_MAC_CMD_CFG_TX_ENA | ETH_1G_MAC_CMD_CFG_RX_ENA);
+		writel(tmp, &adapter->mac_regs_base->mac_1g.cmd_cfg);
+	} else if (AL_ETH_IS_10G_MAC(adapter->mac_mode) ||
+		 AL_ETH_IS_25G_MAC(adapter->mac_mode)) {
+		/* 10G MAC control register  */
+		tmp = readl(&adapter->mac_regs_base->mac_10g.cmd_cfg);
+		tmp &= ~(ETH_10G_MAC_CMD_CFG_TX_ENA | ETH_10G_MAC_CMD_CFG_RX_ENA);
+		writel(tmp, &adapter->mac_regs_base->mac_10g.cmd_cfg);
+	} else {
+		u32 cmd_cfg;
+
+		cmd_cfg = al_eth_40g_mac_reg_read(adapter,
+						  ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_ADDR);
+
+		cmd_cfg &= ~(ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_TX_ENA |
+			    ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_RX_ENA);
+
+		al_eth_40g_mac_reg_write(adapter,
+					 ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_ADDR,
+					 cmd_cfg);
+	}
+
+	return 0;
+}
+
+static void al_eth_mac_link_config_1g_mac(struct al_hw_eth_adapter *adapter,
+					  bool force_1000_base_x,
+					  bool an_enable, u32 speed,
+					  bool full_duplex)
+{
+	u32 mac_ctrl;
+	u32 sgmii_ctrl = 0;
+	u32 sgmii_if_mode = 0;
+	u32 rgmii_ctrl = 0;
+
+	mac_ctrl = readl(&adapter->mac_regs_base->mac_1g.cmd_cfg);
+
+	if (adapter->mac_mode == AL_ETH_MAC_MODE_SGMII) {
+		writel(ETH_MAC_SGMII_REG_ADDR_CTRL_REG,
+		       &adapter->mac_regs_base->sgmii.reg_addr);
+		sgmii_ctrl = readl(&adapter->mac_regs_base->sgmii.reg_data);
+		/*
+		 * in case bit 0 is off in sgmii_if_mode register all the other
+		 * bits are ignored.
+		 */
+		if (!force_1000_base_x)
+			sgmii_if_mode = ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_EN;
+
+		if (an_enable) {
+			sgmii_if_mode |= ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_AN;
+			sgmii_ctrl |= ETH_MAC_SGMII_REG_DATA_CTRL_AN_ENABLE;
+		} else {
+			sgmii_ctrl &= ~(ETH_MAC_SGMII_REG_DATA_CTRL_AN_ENABLE);
+		}
+	}
+
+	if (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII) {
+		/*
+		 * Use the speed provided by the MAC instead of the PHY
+		 */
+		rgmii_ctrl = readl(&adapter->mac_regs_base->gen.rgmii_cfg);
+
+		rgmii_ctrl &= ~ETH_MAC_GEN_RGMII_CFG_ENA_AUTO;
+		rgmii_ctrl &= ~ETH_MAC_GEN_RGMII_CFG_SET_1000_SEL;
+		rgmii_ctrl &= ~ETH_MAC_GEN_RGMII_CFG_SET_10_SEL;
+
+		writel(rgmii_ctrl, &adapter->mac_regs_base->gen.rgmii_cfg);
+	}
+
+	if (full_duplex) {
+		mac_ctrl &= ~ETH_1G_MAC_CMD_CFG_HD_EN;
+	} else {
+		mac_ctrl |= ETH_1G_MAC_CMD_CFG_HD_EN;
+		sgmii_if_mode |= ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_DUPLEX;
+	}
+
+	if (speed == 1000) {
+		mac_ctrl |= ETH_1G_MAC_CMD_CFG_1G_SPD;
+		sgmii_if_mode |= ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_SPEED_1000;
+	} else {
+		mac_ctrl &= ~ETH_1G_MAC_CMD_CFG_1G_SPD;
+		if (speed == 10) {
+			mac_ctrl |= ETH_1G_MAC_CMD_CFG_10M_SPD;
+		} else {
+			sgmii_if_mode |= ETH_MAC_SGMII_REG_DATA_IF_MODE_SGMII_SPEED_100;
+			mac_ctrl &= ~ETH_1G_MAC_CMD_CFG_10M_SPD;
+		}
+	}
+
+	if (adapter->mac_mode == AL_ETH_MAC_MODE_SGMII) {
+		writel(ETH_MAC_SGMII_REG_ADDR_IF_MODE_REG,
+		       &adapter->mac_regs_base->sgmii.reg_addr);
+		writel(sgmii_if_mode, &adapter->mac_regs_base->sgmii.reg_data);
+
+		writel(ETH_MAC_SGMII_REG_ADDR_CTRL_REG,
+		       &adapter->mac_regs_base->sgmii.reg_addr);
+		writel(sgmii_ctrl, &adapter->mac_regs_base->sgmii.reg_data);
+	}
+
+	writel(mac_ctrl, &adapter->mac_regs_base->mac_1g.cmd_cfg);
+}
+
+static void al_eth_mac_link_config_10g_mac(struct al_hw_eth_adapter *adapter,
+					   bool force_1000_base_x,
+					   bool an_enable, u32 speed,
+					   bool full_duplex)
+{
+	u32 if_mode;
+	u32 val;
+
+	if_mode = readl(&adapter->mac_regs_base->mac_10g.if_mode);
+
+	if (force_1000_base_x) {
+		u32 control;
+
+		if_mode &= ~ETH_10G_MAC_IF_MODE_SGMII_EN_MASK;
+
+		control = readl(&adapter->mac_regs_base->mac_10g.control);
+
+		if (an_enable)
+			control |= ETH_10G_MAC_CONTROL_AN_EN_MASK;
+		else
+			control &= ~ETH_10G_MAC_CONTROL_AN_EN_MASK;
+
+		writel(control, &adapter->mac_regs_base->mac_10g.control);
+
+	} else {
+		if_mode |= ETH_10G_MAC_IF_MODE_SGMII_EN_MASK;
+		if (an_enable) {
+			if_mode |= ETH_10G_MAC_IF_MODE_SGMII_AN_MASK;
+		} else {
+			if_mode &= ~ETH_10G_MAC_IF_MODE_SGMII_AN_MASK;
+
+			if (speed == 1000)
+				val = ETH_10G_MAC_IF_MODE_SGMII_SPEED_1G;
+			else if (speed == 100)
+				val = ETH_10G_MAC_IF_MODE_SGMII_SPEED_100M;
+			else
+				val = ETH_10G_MAC_IF_MODE_SGMII_SPEED_10M;
+
+			if_mode &= ~ETH_10G_MAC_IF_MODE_SGMII_SPEED_MASK;
+			if_mode |= (val << ETH_10G_MAC_IF_MODE_SGMII_SPEED_SHIFT) &
+				ETH_10G_MAC_IF_MODE_SGMII_SPEED_MASK;
+
+			if_mode &= ~ETH_10G_MAC_IF_MODE_SGMII_DUPLEX_MASK;
+			if_mode |= (((full_duplex) ? ETH_10G_MAC_IF_MODE_SGMII_DUPLEX_FULL :
+				     ETH_10G_MAC_IF_MODE_SGMII_DUPLEX_HALF) << ETH_10G_MAC_IF_MODE_SGMII_DUPLEX_SHIFT) &
+				     ETH_10G_MAC_IF_MODE_SGMII_DUPLEX_MASK;
+		}
+	}
+
+	writel(if_mode, &adapter->mac_regs_base->mac_10g.if_mode);
+}
+
+/* update link speed and duplex mode */
+int al_eth_mac_link_config(struct al_hw_eth_adapter *adapter,
+			   bool force_1000_base_x, bool an_enable, u32 speed,
+			   bool full_duplex)
+{
+	if ((!AL_ETH_IS_1G_MAC(adapter->mac_mode)) &&
+	    (adapter->mac_mode != AL_ETH_MAC_MODE_SGMII_2_5G)) {
+		netdev_err(adapter->netdev,
+			   "eth [%s]: this function not supported in this mac mode.\n",
+			   adapter->name);
+		return -EINVAL;
+	}
+
+	if ((adapter->mac_mode != AL_ETH_MAC_MODE_RGMII) && (an_enable)) {
+		/*
+		 * an_enable is not relevant to RGMII mode.
+		 * in AN mode speed and duplex aren't relevant.
+		 */
+		netdev_info(adapter->netdev,
+			    "eth [%s]: set auto negotiation to enable\n",
+			    adapter->name);
+	} else {
+		netdev_info(adapter->netdev,
+			    "eth [%s]: set link speed to %dMbps. %s duplex.\n",
+			    adapter->name, speed,
+			    full_duplex ? "full" : "half");
+
+		if ((speed != 10) && (speed != 100) && (speed != 1000)) {
+			netdev_err(adapter->netdev,
+				   "eth [%s]: bad speed parameter (%d).\n",
+				   adapter->name, speed);
+			return -EINVAL;
+		}
+		if ((speed == 1000) && (full_duplex == false)) {
+			netdev_err(adapter->netdev,
+				   "eth [%s]: half duplex in 1Gbps is not supported.\n",
+				   adapter->name);
+			return -EINVAL;
+		}
+	}
+
+	if (AL_ETH_IS_1G_MAC(adapter->mac_mode))
+		al_eth_mac_link_config_1g_mac(adapter, force_1000_base_x,
+					      an_enable, speed, full_duplex);
+	else
+		al_eth_mac_link_config_10g_mac(adapter, force_1000_base_x,
+					       an_enable, speed, full_duplex);
+
+	return 0;
+}
+
+/* MDIO */
+int al_eth_mdio_config(struct al_hw_eth_adapter *adapter,
+		       enum al_eth_mdio_type mdio_type, bool shared_mdio_if,
+		       enum al_eth_ref_clk_freq ref_clk_freq,
+		       unsigned int mdio_clk_freq_khz)
+{
+	enum al_eth_mdio_if mdio_if = AL_ETH_MDIO_IF_10G_MAC;
+	const char *if_name = (mdio_if == AL_ETH_MDIO_IF_1G_MAC) ? "10/100/1G MAC" : "10G MAC";
+	const char *type_name = (mdio_type == AL_ETH_MDIO_TYPE_CLAUSE_22) ? "Clause 22" : "Clause 45";
+	const char *shared_name = shared_mdio_if ? "Yes" : "No";
+	unsigned int ref_clk_freq_khz;
+	u32 val;
+
+	netdev_dbg(adapter->netdev,
+		   "eth [%s]: mdio config: interface %s. type %s. shared: %s\n",
+		   adapter->name, if_name, type_name, shared_name);
+	adapter->shared_mdio_if = shared_mdio_if;
+
+	val = readl(&adapter->mac_regs_base->gen.cfg);
+	netdev_dbg(adapter->netdev, "eth [%s]: mdio config: 10G mac \n",
+		   adapter->name);
+
+	switch (mdio_if) {
+	case AL_ETH_MDIO_IF_1G_MAC:
+		val &= ~BIT(10);
+		break;
+	case AL_ETH_MDIO_IF_10G_MAC:
+		val |= BIT(10);
+		break;
+	}
+
+	writel(val, &adapter->mac_regs_base->gen.cfg);
+	adapter->mdio_if = mdio_if;
+
+	if (mdio_if == AL_ETH_MDIO_IF_10G_MAC) {
+		val = readl(&adapter->mac_regs_base->mac_10g.mdio_cfg_status);
+		switch (mdio_type) {
+		case AL_ETH_MDIO_TYPE_CLAUSE_22:
+			val &= ~BIT(6);
+			break;
+		case AL_ETH_MDIO_TYPE_CLAUSE_45:
+			val |= BIT(6);
+			break;
+		}
+
+		/* set clock div to get 'mdio_clk_freq_khz' */
+		switch (ref_clk_freq) {
+		default:
+			netdev_err(adapter->netdev,
+				   "%s: invalid reference clock frequency (%d)\n",
+				   adapter->name, ref_clk_freq);
+		case AL_ETH_REF_FREQ_375_MHZ:
+			ref_clk_freq_khz = 375000;
+			break;
+		case AL_ETH_REF_FREQ_187_5_MHZ:
+			ref_clk_freq_khz = 187500;
+			break;
+		case AL_ETH_REF_FREQ_250_MHZ:
+			ref_clk_freq_khz = 250000;
+			break;
+		case AL_ETH_REF_FREQ_500_MHZ:
+			ref_clk_freq_khz = 500000;
+			break;
+		case AL_ETH_REF_FREQ_428_MHZ:
+			ref_clk_freq_khz = 428000;
+			break;
+		}
+
+		val &= ~(0x1FF << 7);
+		val |= (ref_clk_freq_khz / (2 * mdio_clk_freq_khz)) << 7;
+		val &= ~ETH_10G_MAC_MDIO_CFG_HOLD_TIME_MASK;
+		val |= (ETH_10G_MAC_MDIO_CFG_HOLD_TIME_7_CLK << ETH_10G_MAC_MDIO_CFG_HOLD_TIME_SHIFT) &
+			ETH_10G_MAC_MDIO_CFG_HOLD_TIME_MASK;
+		writel(val, &adapter->mac_regs_base->mac_10g.mdio_cfg_status);
+	} else {
+		if (mdio_type != AL_ETH_MDIO_TYPE_CLAUSE_22) {
+			netdev_err(adapter->netdev,
+				   "eth [%s] mdio type not supported for this interface\n",
+				   adapter->name);
+			return -EINVAL;
+		}
+	}
+
+	adapter->mdio_type = mdio_type;
+	return 0;
+}
+
+static void al_eth_mdio_1g_mac_read(struct al_hw_eth_adapter *adapter,
+				    u32 phy_addr, u32 reg, u16 *val)
+{
+	*val = readl(&adapter->mac_regs_base->mac_1g.phy_regs_base + reg);
+}
+
+static void al_eth_mdio_1g_mac_write(struct al_hw_eth_adapter *adapter,
+				     u32 phy_addr, u32 reg, u16 val)
+{
+	writel(val, &adapter->mac_regs_base->mac_1g.phy_regs_base + reg);
+}
+
+static int al_eth_mdio_10g_mac_wait_busy(struct al_hw_eth_adapter *adapter)
+{
+	int count = 0;
+	u32 mdio_cfg_status;
+
+	do {
+		mdio_cfg_status = readl(&adapter->mac_regs_base->mac_10g.mdio_cfg_status);
+		if (mdio_cfg_status & BIT(0)) {
+			if (count > 0)
+				netdev_dbg(adapter->netdev,
+					   "eth [%s] mdio: still busy!\n",
+					   adapter->name);
+		} else {
+			return 0;
+		}
+		udelay(AL_ETH_MDIO_DELAY_PERIOD);
+	} while (count++ < AL_ETH_MDIO_DELAY_COUNT);
+
+	return -ETIMEDOUT;
+}
+
+static int al_eth_mdio_10g_mac_type22(struct al_hw_eth_adapter *adapter,
+				      int read, u32 phy_addr, u32 reg, u16 *val)
+{
+	int rc;
+	const char *op = (read == 1) ? "read" : "write";
+	u32 mdio_cfg_status;
+	u16 mdio_cmd;
+
+	/* wait if the HW is busy */
+	rc = al_eth_mdio_10g_mac_wait_busy(adapter);
+	if (rc) {
+		netdev_err(adapter->netdev,
+			   " eth [%s] mdio %s failed. HW is busy\n",
+			   adapter->name, op);
+		return rc;
+	}
+
+	mdio_cmd = (u16)(0x1F & reg);
+	mdio_cmd |= (0x1F & phy_addr) << 5;
+
+	if (read)
+		mdio_cmd |= BIT(15); /* READ command */
+
+	writew(mdio_cmd, &adapter->mac_regs_base->mac_10g.mdio_cmd);
+	if (!read)
+		writew(*val, &adapter->mac_regs_base->mac_10g.mdio_data);
+
+	/* wait for the busy to clear */
+	rc = al_eth_mdio_10g_mac_wait_busy(adapter);
+	if (rc != 0) {
+		netdev_err(adapter->netdev, " %s mdio %s failed on timeout\n",
+			   adapter->name, op);
+		return -ETIMEDOUT;
+	}
+
+	mdio_cfg_status = readl(&adapter->mac_regs_base->mac_10g.mdio_cfg_status);
+
+	if (mdio_cfg_status & BIT(1)) {
+		netdev_err(adapter->netdev,
+			   " %s mdio %s failed on error. phy_addr 0x%x reg 0x%x\n",
+			   adapter->name, op, phy_addr, reg);
+		return -EIO;
+	}
+	if (read)
+		*val = readw((u16 *)&adapter->mac_regs_base->mac_10g.mdio_data);
+	return 0;
+}
+
+static int al_eth_mdio_10g_mac_type45(struct al_hw_eth_adapter *adapter,
+				      int read, u32 port_addr, u32 device,
+				      u32 reg, u16 *val)
+{
+	int rc;
+	const char *op = (read == 1) ? "read" : "write";
+	u32 mdio_cfg_status;
+	u16 mdio_cmd;
+
+	/* wait if the HW is busy */
+	rc = al_eth_mdio_10g_mac_wait_busy(adapter);
+	if (rc) {
+		netdev_err(adapter->netdev, " %s mdio %s failed. HW is busy\n",
+			   adapter->name, op);
+		return rc;
+	}
+
+	/* set command register */
+	mdio_cmd = (u16)(0x1F & device);
+	mdio_cmd |= (0x1F & port_addr) << 5;
+	writew(mdio_cmd, &adapter->mac_regs_base->mac_10g.mdio_cmd);
+
+	/* send address frame */
+	writew(reg, &adapter->mac_regs_base->mac_10g.mdio_regaddr);
+
+	/* wait for the busy to clear */
+	rc = al_eth_mdio_10g_mac_wait_busy(adapter);
+	if (rc) {
+		netdev_err(adapter->netdev,
+			   " %s mdio %s (address frame) failed on timeout\n",
+			   adapter->name, op);
+		return rc;
+	}
+
+	/* if read, write again to the command register with READ bit set */
+	if (read) {
+		mdio_cmd |= BIT(15); /* READ command */
+		writew(mdio_cmd, (u16 *)&adapter->mac_regs_base->mac_10g.mdio_cmd);
+	} else {
+		writew(*val, (u16 *)&adapter->mac_regs_base->mac_10g.mdio_data);
+	}
+
+	/* wait for the busy to clear */
+	rc = al_eth_mdio_10g_mac_wait_busy(adapter);
+	if (rc) {
+		netdev_err(adapter->netdev, " %s mdio %s failed on timeout\n",
+			   adapter->name, op);
+		return rc;
+	}
+
+	mdio_cfg_status = readl(&adapter->mac_regs_base->mac_10g.mdio_cfg_status);
+
+	if (mdio_cfg_status & BIT(1)) {
+		netdev_err(adapter->netdev,
+			   " %s mdio %s failed on error. port 0x%x, device 0x%x reg 0x%x\n",
+			   adapter->name, op, port_addr, device, reg);
+		return -EIO;
+	}
+
+	if (read)
+		*val = readw((u16 *)&adapter->mac_regs_base->mac_10g.mdio_data);
+
+	return 0;
+}
+
+/*
+ * acquire mdio interface ownership
+ * when mdio interface shared between multiple eth controllers, this function waits until the ownership granted for this controller.
+ * this function does nothing when the mdio interface is used only by this controller.
+ *
+ * @param adapter
+ * @return 0 on success, -ETIMEDOUT  on timeout.
+ */
+static int al_eth_mdio_lock(struct al_hw_eth_adapter *adapter)
+{
+	int count = 0;
+	u32 mdio_ctrl_1;
+
+	if (!adapter->shared_mdio_if)
+		return 0; /* nothing to do when interface is not shared */
+
+	do {
+		mdio_ctrl_1 = readl(&adapter->mac_regs_base->gen.mdio_ctrl_1);
+		if (mdio_ctrl_1 & BIT(0)) {
+			if (count > 0)
+				netdev_dbg(adapter->netdev,
+					   "eth %s mdio interface still busy!\n",
+					   adapter->name);
+		} else {
+			return 0;
+		}
+		udelay(AL_ETH_MDIO_DELAY_PERIOD);
+	} while (count++ < (AL_ETH_MDIO_DELAY_COUNT * 4));
+
+	netdev_err(adapter->netdev,
+		   " %s mdio failed to take ownership. MDIO info reg: 0x%08x\n",
+		   adapter->name, readl(&adapter->mac_regs_base->gen.mdio_1));
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * free mdio interface ownership
+ * when mdio interface shared between multiple eth controllers, this function releases the ownership granted for this controller.
+ * this function does nothing when the mdio interface is used only by this controller.
+ *
+ * @param adapter
+ * @return 0.
+ */
+static int al_eth_mdio_free(struct al_hw_eth_adapter *adapter)
+{
+	if (!adapter->shared_mdio_if)
+		return 0; /* nothing to do when interface is not shared */
+
+	writel(0, &adapter->mac_regs_base->gen.mdio_ctrl_1);
+
+	/*
+	 * Addressing RMN: 2917
+	 *
+	 * RMN description:
+	 * The HW spin-lock is stateless and doesn't maintain any scheduling
+	 * policy.
+	 *
+	 * Software flow:
+	 * After getting the lock wait 2 times the delay period in order to give
+	 * the other port chance to take the lock and prevent starvation.
+	 * This is not scalable to more than two ports.
+	 */
+	udelay(2 * AL_ETH_MDIO_DELAY_PERIOD);
+
+	return 0;
+}
+
+int al_eth_mdio_read(struct al_hw_eth_adapter *adapter, u32 phy_addr,
+		     u32 device, u32 reg, u16 *val)
+{
+	int rc = al_eth_mdio_lock(adapter);
+
+	if (rc)
+		return rc;
+
+	if (adapter->mdio_if == AL_ETH_MDIO_IF_1G_MAC)
+		al_eth_mdio_1g_mac_read(adapter, phy_addr, reg, val);
+	else
+		if (adapter->mdio_type == AL_ETH_MDIO_TYPE_CLAUSE_22)
+			rc = al_eth_mdio_10g_mac_type22(adapter, 1, phy_addr,
+							reg, val);
+		else
+			rc = al_eth_mdio_10g_mac_type45(adapter, 1, phy_addr,
+							device, reg, val);
+
+	al_eth_mdio_free(adapter);
+
+	netdev_dbg(adapter->netdev,
+		   "eth mdio read: phy_addr %x, device %x, reg %x val %x\n",
+		   phy_addr, device, reg, *val);
+	return rc;
+}
+
+int al_eth_mdio_write(struct al_hw_eth_adapter *adapter, u32 phy_addr,
+		      u32 device, u32 reg, u16 val)
+{
+	int rc;
+
+	netdev_dbg(adapter->netdev,
+		   "eth mdio write: phy_addr %x, device %x, reg %x, val %x\n",
+		   phy_addr, device, reg, val);
+
+	rc = al_eth_mdio_lock(adapter);
+	/* interface ownership taken */
+	if (rc)
+		return rc;
+
+	if (adapter->mdio_if == AL_ETH_MDIO_IF_1G_MAC) {
+		al_eth_mdio_1g_mac_write(adapter, phy_addr, reg, val);
+	} else {
+		if (adapter->mdio_type == AL_ETH_MDIO_TYPE_CLAUSE_22)
+			rc = al_eth_mdio_10g_mac_type22(adapter, 0, phy_addr,
+							reg, &val);
+		else
+			rc = al_eth_mdio_10g_mac_type45(adapter, 0, phy_addr,
+							device, reg, &val);
+	}
+
+	al_eth_mdio_free(adapter);
+	return rc;
+}
+
+static void al_dump_tx_desc(struct al_hw_eth_adapter *adapter,
+			    union al_udma_desc *tx_desc)
+{
+	u32 *ptr = (u32 *)tx_desc;
+
+	netdev_dbg(adapter->netdev,
+		   "eth tx desc:\n0x%08x\n0x%08x\n0x%08x\n0x%08x\n",
+		   ptr[0], ptr[1], ptr[2], ptr[3]);
+}
+
+static void al_dump_tx_pkt(struct al_hw_eth_adapter *adapter,
+			   struct al_udma_q *tx_dma_q, struct al_eth_pkt *pkt)
+{
+	const char *tso = (pkt->flags & AL_ETH_TX_FLAGS_TSO) ? "TSO" : "";
+	const char *l3_csum = (pkt->flags & AL_ETH_TX_FLAGS_IPV4_L3_CSUM) ? "L3 CSUM" : "";
+	const char *l4_csum = (pkt->flags & AL_ETH_TX_FLAGS_L4_CSUM) ?
+	  ((pkt->flags & AL_ETH_TX_FLAGS_L4_PARTIAL_CSUM) ? "L4 PARTIAL CSUM" : "L4 FULL CSUM") : "";
+	const char *fcs = (pkt->flags & AL_ETH_TX_FLAGS_L2_DIS_FCS) ? "Disable FCS" : "";
+	const char *ptp = (pkt->flags & AL_ETH_TX_FLAGS_TS) ? "TX_PTP" : "";
+	const char *l3_proto_name = "unknown";
+	const char *l4_proto_name = "unknown";
+	const char *outer_l3_proto_name = "N/A";
+	const char *tunnel_mode = ((pkt->tunnel_mode) &
+				(AL_ETH_TUNNEL_WITH_UDP == AL_ETH_TUNNEL_WITH_UDP)) ?
+				"TUNNEL_WITH_UDP" :
+				((pkt->tunnel_mode) &
+				(AL_ETH_TUNNEL_NO_UDP == AL_ETH_TUNNEL_NO_UDP)) ?
+				"TUNNEL_NO_UDP" : "";
+	u32 total_len = 0;
+	int i;
+
+	netdev_dbg(adapter->netdev, "[%s %d]: flags: %s %s %s %s %s %s\n",
+		   tx_dma_q->udma->name, tx_dma_q->qid, tso, l3_csum, l4_csum,
+		   fcs, ptp, tunnel_mode);
+
+	switch (pkt->l3_proto_idx) {
+	case AL_ETH_PROTO_ID_IPv4:
+		l3_proto_name = "IPv4";
+		break;
+	case AL_ETH_PROTO_ID_IPv6:
+		l3_proto_name = "IPv6";
+		break;
+	default:
+		l3_proto_name = "unknown";
+		break;
+	}
+
+	switch (pkt->l4_proto_idx) {
+	case AL_ETH_PROTO_ID_TCP:
+		l4_proto_name = "TCP";
+		break;
+	case AL_ETH_PROTO_ID_UDP:
+		l4_proto_name = "UDP";
+		break;
+	default:
+		l4_proto_name = "unknown";
+		break;
+	}
+
+	switch (pkt->outer_l3_proto_idx) {
+	case AL_ETH_PROTO_ID_IPv4:
+		outer_l3_proto_name = "IPv4";
+		break;
+	case AL_ETH_PROTO_ID_IPv6:
+		outer_l3_proto_name = "IPv6";
+		break;
+	default:
+		outer_l3_proto_name = "N/A";
+		break;
+	}
+
+	netdev_dbg(adapter->netdev,
+		   "[%s %d]: L3 proto: %d (%s). L4 proto: %d (%s). "
+		   "Outer_L3 proto: %d (%s). vlan source count %d. mod add %d. mod del %d\n",
+		   tx_dma_q->udma->name, tx_dma_q->qid, pkt->l3_proto_idx,
+		   l3_proto_name, pkt->l4_proto_idx, l4_proto_name,
+		   pkt->outer_l3_proto_idx, outer_l3_proto_name,
+		   pkt->source_vlan_count, pkt->vlan_mod_add_count,
+		   pkt->vlan_mod_del_count);
+
+	if (pkt->meta) {
+		const char *store = pkt->meta->store ? "Yes" : "No";
+		const char *ptp_val = (pkt->flags & AL_ETH_TX_FLAGS_TS) ? "Yes" : "No";
+
+		netdev_dbg(adapter->netdev,
+			   "[%s %d]: tx pkt with meta data. words valid %x\n",
+			   tx_dma_q->udma->name, tx_dma_q->qid,
+			   pkt->meta->words_valid);
+		netdev_dbg(adapter->netdev,
+			   "[%s %d]: meta: store to cache %s. l3 hdr len %d. l3 hdr offset %d. "
+			   "l4 hdr len %d. mss val %d ts_index %d ts_val:%s\n",
+			   tx_dma_q->udma->name, tx_dma_q->qid, store,
+			   pkt->meta->l3_header_len,
+			   pkt->meta->l3_header_offset,
+			   pkt->meta->l4_header_len, pkt->meta->mss_val,
+			   pkt->meta->ts_index, ptp_val);
+		netdev_dbg(adapter->netdev,
+			   "outer_l3_hdr_offset %d. outer_l3_len %d.\n",
+			   pkt->meta->outer_l3_offset, pkt->meta->outer_l3_len);
+	}
+
+	netdev_dbg(adapter->netdev, "[%s %d]: num of bufs: %d\n",
+		   tx_dma_q->udma->name, tx_dma_q->qid, pkt->num_of_bufs);
+	for (i = 0; i < pkt->num_of_bufs; i++) {
+		netdev_dbg(adapter->netdev,
+			   "eth [%s %d]: buf[%d]: len 0x%08x. address 0x%016llx\n",
+			   tx_dma_q->udma->name, tx_dma_q->qid,
+			   i, pkt->bufs[i].len,
+			   (unsigned long long)pkt->bufs[i].addr);
+		total_len += pkt->bufs[i].len;
+	}
+
+	netdev_dbg(adapter->netdev, "[%s %d]: total len: 0x%08x\n",
+		   tx_dma_q->udma->name, tx_dma_q->qid, total_len);
+
+}
+
+/* add packet to transmission queue */
+int al_eth_tx_pkt_prepare(struct al_hw_eth_adapter *adapter,
+			  struct al_udma_q *tx_dma_q, struct al_eth_pkt *pkt)
+{
+	union al_udma_desc *tx_desc;
+	u32 tx_descs;
+	u32 flags = AL_M2S_DESC_FIRST | AL_M2S_DESC_CONCAT |
+		    (pkt->flags & AL_ETH_TX_FLAGS_INT);
+	u64 tgtid = ((u64)pkt->tgtid) << AL_UDMA_DESC_TGTID_SHIFT;
+	u32 meta_ctrl;
+	u32 ring_id;
+	int buf_idx;
+
+	netdev_dbg(adapter->netdev, "[%s %d]: new tx pkt\n",
+		   tx_dma_q->udma->name, tx_dma_q->qid);
+
+	al_dump_tx_pkt(adapter, tx_dma_q, pkt);
+
+	tx_descs = pkt->num_of_bufs;
+	if (pkt->meta)
+		tx_descs += 1;
+
+	if (unlikely(al_udma_available_get(tx_dma_q) < tx_descs)) {
+		netdev_dbg(adapter->netdev,
+			   "[%s %d]: failed to allocate (%d) descriptors",
+			   tx_dma_q->udma->name, tx_dma_q->qid, tx_descs);
+		return 0;
+	}
+
+	if (pkt->meta) {
+		u32 meta_word_0 = 0;
+		u32 meta_word_1 = 0;
+		u32 meta_word_2 = 0;
+		u32 meta_word_3 = 0;
+
+		meta_word_0 |= flags | AL_M2S_DESC_META_DATA;
+		meta_word_0 &=  ~AL_M2S_DESC_CONCAT;
+		flags &= ~(AL_M2S_DESC_FIRST | AL_ETH_TX_FLAGS_INT);
+
+		tx_desc = al_udma_desc_get(tx_dma_q);
+		/* get ring id, and clear FIRST and Int flags */
+		ring_id = al_udma_ring_id_get(tx_dma_q) <<
+			AL_M2S_DESC_RING_ID_SHIFT;
+
+		meta_word_0 |= ring_id;
+		meta_word_0 |= pkt->meta->words_valid << 12;
+
+		if (pkt->meta->store)
+			meta_word_0 |= AL_ETH_TX_META_STORE;
+
+		if (pkt->meta->words_valid & 1) {
+			meta_word_0 |= pkt->meta->vlan1_cfi_sel;
+			meta_word_0 |= pkt->meta->vlan2_vid_sel << 2;
+			meta_word_0 |= pkt->meta->vlan2_cfi_sel << 4;
+			meta_word_0 |= pkt->meta->vlan2_pbits_sel << 6;
+			meta_word_0 |= pkt->meta->vlan2_ether_sel << 8;
+		}
+
+		if (pkt->meta->words_valid & 2) {
+			meta_word_1 = pkt->meta->vlan1_new_vid;
+			meta_word_1 |= pkt->meta->vlan1_new_cfi << 12;
+			meta_word_1 |= pkt->meta->vlan1_new_pbits << 13;
+			meta_word_1 |= pkt->meta->vlan2_new_vid << 16;
+			meta_word_1 |= pkt->meta->vlan2_new_cfi << 28;
+			meta_word_1 |= pkt->meta->vlan2_new_pbits << 29;
+		}
+
+		if (pkt->meta->words_valid & 4) {
+			u32 l3_offset;
+
+			meta_word_2 = pkt->meta->l3_header_len & AL_ETH_TX_META_L3_LEN_MASK;
+			meta_word_2 |= (pkt->meta->l3_header_offset & AL_ETH_TX_META_L3_OFF_MASK) <<
+				AL_ETH_TX_META_L3_OFF_SHIFT;
+			meta_word_2 |= (pkt->meta->l4_header_len & 0x3f) << 16;
+
+			if (unlikely(pkt->flags & AL_ETH_TX_FLAGS_TS))
+				meta_word_0 |= pkt->meta->ts_index <<
+					AL_ETH_TX_META_MSS_MSB_TS_VAL_SHIFT;
+			else
+				meta_word_0 |= (((pkt->meta->mss_val & 0x3c00) >> 10)
+						<< AL_ETH_TX_META_MSS_MSB_TS_VAL_SHIFT);
+			meta_word_2 |= ((pkt->meta->mss_val & 0x03ff)
+					<< AL_ETH_TX_META_MSS_LSB_VAL_SHIFT);
+
+			/*
+			 * move from bytes to multiplication of 2 as the HW
+			 * expect to get it
+			 */
+			l3_offset = (pkt->meta->outer_l3_offset >> 1);
+
+			meta_word_0 |=
+				(((l3_offset &
+				   AL_ETH_TX_META_OUTER_L3_OFF_HIGH_MASK) >> 3)
+				   << AL_ETH_TX_META_OUTER_L3_OFF_HIGH_SHIFT);
+
+			meta_word_3 |=
+				((l3_offset &
+				   AL_ETH_TX_META_OUTER_L3_OFF_LOW_MASK)
+				   << AL_ETH_TX_META_OUTER_L3_OFF_LOW_SHIFT);
+
+			/*
+			 * shift right 2 bits to work in multiplication of 4
+			 * as the HW expect to get it
+			 */
+			meta_word_3 |=
+				(((pkt->meta->outer_l3_len >> 2) &
+				   AL_ETH_TX_META_OUTER_L3_LEN_MASK)
+				   << AL_ETH_TX_META_OUTER_L3_LEN_SHIFT);
+		}
+
+		tx_desc->tx_meta.len_ctrl = cpu_to_le32(meta_word_0);
+		tx_desc->tx_meta.meta_ctrl = cpu_to_le32(meta_word_1);
+		tx_desc->tx_meta.meta1 = cpu_to_le32(meta_word_2);
+		tx_desc->tx_meta.meta2 = cpu_to_le32(meta_word_3);
+		al_dump_tx_desc(adapter, tx_desc);
+	}
+
+	meta_ctrl = pkt->flags & AL_ETH_TX_PKT_META_FLAGS;
+
+	meta_ctrl |= pkt->l3_proto_idx;
+	meta_ctrl |= pkt->l4_proto_idx << AL_ETH_TX_L4_PROTO_IDX_SHIFT;
+	meta_ctrl |= pkt->source_vlan_count << AL_ETH_TX_SRC_VLAN_CNT_SHIFT;
+	meta_ctrl |= pkt->vlan_mod_add_count << AL_ETH_TX_VLAN_MOD_ADD_SHIFT;
+	meta_ctrl |= pkt->vlan_mod_del_count << AL_ETH_TX_VLAN_MOD_DEL_SHIFT;
+	meta_ctrl |= pkt->vlan_mod_v1_ether_sel << AL_ETH_TX_VLAN_MOD_E_SEL_SHIFT;
+	meta_ctrl |= pkt->vlan_mod_v1_vid_sel << AL_ETH_TX_VLAN_MOD_VID_SEL_SHIFT;
+	meta_ctrl |= pkt->vlan_mod_v1_pbits_sel << AL_ETH_TX_VLAN_MOD_PBIT_SEL_SHIFT;
+
+	meta_ctrl |= pkt->tunnel_mode << AL_ETH_TX_TUNNEL_MODE_SHIFT;
+	if (pkt->outer_l3_proto_idx == AL_ETH_PROTO_ID_IPv4)
+		meta_ctrl |= BIT(AL_ETH_TX_OUTER_L3_PROTO_SHIFT);
+
+	flags |= pkt->flags & AL_ETH_TX_PKT_UDMA_FLAGS;
+	for (buf_idx = 0; buf_idx < pkt->num_of_bufs; buf_idx++) {
+		u32 flags_len = flags;
+
+		tx_desc = al_udma_desc_get(tx_dma_q);
+		/* get ring id, and clear FIRST and Int flags */
+		ring_id = al_udma_ring_id_get(tx_dma_q) <<
+			AL_M2S_DESC_RING_ID_SHIFT;
+
+		flags_len |= ring_id;
+
+		if (buf_idx == (pkt->num_of_bufs - 1))
+			flags_len |= AL_M2S_DESC_LAST;
+
+		/* clear First and Int flags */
+		flags &= AL_ETH_TX_FLAGS_NO_SNOOP;
+		flags |= AL_M2S_DESC_CONCAT;
+
+		flags_len |= pkt->bufs[buf_idx].len & AL_M2S_DESC_LEN_MASK;
+		tx_desc->tx.len_ctrl = cpu_to_le32(flags_len);
+		if (buf_idx == 0)
+			tx_desc->tx.meta_ctrl = cpu_to_le32(meta_ctrl);
+		tx_desc->tx.buf_ptr = cpu_to_le64(
+			pkt->bufs[buf_idx].addr | tgtid);
+		al_dump_tx_desc(adapter, tx_desc);
+	}
+
+	netdev_dbg(adapter->netdev,
+		   "[%s %d]: pkt descriptors written into the tx queue. descs num (%d)\n",
+		   tx_dma_q->udma->name, tx_dma_q->qid, tx_descs);
+
+	return tx_descs;
+}
+
+void al_eth_tx_dma_action(struct al_udma_q *tx_dma_q, u32 tx_descs)
+{
+	/* add tx descriptors */
+	al_udma_desc_action_add(tx_dma_q, tx_descs);
+}
+
+/* get number of completed tx descriptors, upper layer should derive from */
+int al_eth_comp_tx_get(struct al_hw_eth_adapter *adapter,
+		       struct al_udma_q *tx_dma_q)
+{
+	int rc;
+
+	rc = al_udma_cdesc_get_all(tx_dma_q, NULL);
+	if (rc != 0) {
+		al_udma_cdesc_ack(tx_dma_q, rc);
+		netdev_dbg(adapter->netdev,
+			   "[%s %d]: tx completion: descs (%d)\n",
+			   tx_dma_q->udma->name, tx_dma_q->qid, rc);
+	}
+
+	return rc;
+}
+
+/* add buffer to receive queue */
+int al_eth_rx_buffer_add(struct al_hw_eth_adapter *adapter,
+			 struct al_udma_q *rx_dma_q,
+			 struct al_buf *buf, u32 flags,
+			 struct al_buf *header_buf)
+{
+	u64 tgtid = ((u64)flags & AL_ETH_RX_FLAGS_TGTID_MASK) <<
+		AL_UDMA_DESC_TGTID_SHIFT;
+	u32 flags_len = flags & ~AL_ETH_RX_FLAGS_TGTID_MASK;
+	union al_udma_desc *rx_desc;
+
+	netdev_dbg(adapter->netdev, "[%s %d]: add rx buffer.\n",
+		   rx_dma_q->udma->name, rx_dma_q->qid);
+
+	if (unlikely(al_udma_available_get(rx_dma_q) < 1)) {
+		netdev_dbg(adapter->netdev,
+			   "[%s]: rx q (%d) has no enough free descriptor",
+			   rx_dma_q->udma->name, rx_dma_q->qid);
+		return -ENOSPC;
+	}
+
+	rx_desc = al_udma_desc_get(rx_dma_q);
+
+	flags_len |= al_udma_ring_id_get(rx_dma_q) << AL_S2M_DESC_RING_ID_SHIFT;
+	flags_len |= buf->len & AL_S2M_DESC_LEN_MASK;
+
+	if (flags & AL_S2M_DESC_DUAL_BUF) {
+		WARN_ON(!header_buf); /*header valid in dual buf */
+		WARN_ON((rx_dma_q->udma->rev_id < AL_UDMA_REV_ID_2) &&
+		       (AL_ADDR_HIGH(buf->addr) != AL_ADDR_HIGH(header_buf->addr)));
+
+		flags_len |= ((header_buf->len >> AL_S2M_DESC_LEN2_GRANULARITY_SHIFT)
+			<< AL_S2M_DESC_LEN2_SHIFT) & AL_S2M_DESC_LEN2_MASK;
+		rx_desc->rx.buf2_ptr_lo = cpu_to_le32(AL_ADDR_LOW(header_buf->addr));
+	}
+	rx_desc->rx.len_ctrl = cpu_to_le32(flags_len);
+	rx_desc->rx.buf1_ptr = cpu_to_le64(buf->addr | tgtid);
+
+	return 0;
+}
+
+/* notify the hw engine about rx descriptors that were added to the receive queue */
+void al_eth_rx_buffer_action(struct al_hw_eth_adapter *adapter,
+			     struct al_udma_q *rx_dma_q, u32 descs_num)
+{
+	netdev_dbg(adapter->netdev,
+		   "[%s]: update the rx engine tail pointer: queue %d. descs %d\n",
+		   rx_dma_q->udma->name, rx_dma_q->qid, descs_num);
+
+	/* add rx descriptor */
+	al_udma_desc_action_add(rx_dma_q, descs_num);
+}
+
+/* get packet from RX completion ring */
+u32 al_eth_pkt_rx(struct al_hw_eth_adapter *adapter, struct al_udma_q *rx_dma_q,
+		  struct al_eth_pkt *pkt)
+{
+	volatile union al_udma_cdesc *cdesc;
+	volatile struct al_eth_rx_cdesc *rx_desc;
+	u32 i, rc = al_udma_cdesc_packet_get(rx_dma_q, &cdesc);
+
+	if (rc == 0)
+		return 0;
+
+	WARN_ON(rc > AL_ETH_PKT_MAX_BUFS);
+
+	netdev_dbg(adapter->netdev, "[%s]: fetch rx packet: queue %d.\n",
+		   rx_dma_q->udma->name, rx_dma_q->qid);
+
+	pkt->rx_header_len = 0;
+	for (i = 0; i < rc; i++) {
+		u32 buf1_len, buf2_len;
+
+		/* get next descriptor */
+		rx_desc = (volatile struct al_eth_rx_cdesc *)al_cdesc_next(rx_dma_q,
+									   cdesc,
+									   i);
+
+		buf1_len = le32_to_cpu(rx_desc->len);
+
+		if ((i == 0) && (le32_to_cpu(rx_desc->word2) &
+			AL_UDMA_CDESC_BUF2_USED)) {
+			buf2_len = le32_to_cpu(rx_desc->word2);
+			pkt->rx_header_len = (buf2_len & AL_S2M_DESC_LEN2_MASK) >>
+			AL_S2M_DESC_LEN2_SHIFT;
+		}
+		pkt->bufs[i].len = buf1_len & AL_S2M_DESC_LEN_MASK;
+	}
+	/* get flags from last desc */
+	pkt->flags = le32_to_cpu(rx_desc->ctrl_meta);
+
+	/* update L3/L4 proto index */
+	pkt->l3_proto_idx = pkt->flags & AL_ETH_RX_L3_PROTO_IDX_MASK;
+	pkt->l4_proto_idx = (pkt->flags >> AL_ETH_RX_L4_PROTO_IDX_SHIFT) &
+				AL_ETH_RX_L4_PROTO_IDX_MASK;
+	pkt->rxhash = (le32_to_cpu(rx_desc->len) & AL_ETH_RX_HASH_MASK) >>
+			AL_ETH_RX_HASH_SHIFT;
+	pkt->l3_offset = (le32_to_cpu(rx_desc->word2) & AL_ETH_RX_L3_OFFSET_MASK) >>
+		AL_ETH_RX_L3_OFFSET_SHIFT;
+
+	al_udma_cdesc_ack(rx_dma_q, rc);
+	return rc;
+}
+
+#define AL_ETH_THASH_UDMA_SHIFT		0
+#define AL_ETH_THASH_UDMA_MASK		(0xF << AL_ETH_THASH_UDMA_SHIFT)
+
+#define AL_ETH_THASH_Q_SHIFT		4
+#define AL_ETH_THASH_Q_MASK		(0x3 << AL_ETH_THASH_Q_SHIFT)
+
+int al_eth_thash_table_set(struct al_hw_eth_adapter *adapter, u32 idx, u8 udma,
+			   u32 queue)
+{
+	u32 entry;
+
+	WARN_ON(idx >= AL_ETH_RX_THASH_TABLE_SIZE); /* valid THASH index */
+
+	entry = (udma << AL_ETH_THASH_UDMA_SHIFT) & AL_ETH_THASH_UDMA_MASK;
+	entry |= (queue << AL_ETH_THASH_Q_SHIFT) & AL_ETH_THASH_Q_MASK;
+
+	writel(idx, &adapter->ec_regs_base->rfw.thash_table_addr);
+	writel(entry, &adapter->ec_regs_base->rfw.thash_table_data);
+	return 0;
+}
+
+int al_eth_fsm_table_set(struct al_hw_eth_adapter *adapter, u32 idx, u32 entry)
+{
+	WARN_ON(idx >= AL_ETH_RX_FSM_TABLE_SIZE); /* valid FSM index */
+
+	writel(idx, &adapter->ec_regs_base->rfw.fsm_table_addr);
+	writel(entry, &adapter->ec_regs_base->rfw.fsm_table_data);
+	return 0;
+}
+
+static u32 al_eth_fwd_ctrl_entry_to_val(struct al_eth_fwd_ctrl_table_entry *entry)
+{
+	u32 val = 0;
+
+	val &= ~GENMASK(3, 0);
+	val |= (entry->prio_sel << 0) & GENMASK(3, 0);
+	val &= ~GENMASK(7, 4);
+	val |= (entry->queue_sel_1 << 4) & GENMASK(7, 4);
+	val &= ~GENMASK(9, 8);
+	val |= (entry->queue_sel_2 << 8) & GENMASK(9, 8);
+	val &= ~GENMASK(13, 10);
+	val |= (entry->udma_sel << 10) & GENMASK(13, 10);
+	val &= ~GENMASK(17, 15);
+	val |= (!!entry->filter << 19);
+
+	return val;
+}
+
+void al_eth_ctrl_table_def_set(struct al_hw_eth_adapter *adapter,
+			       bool use_table,
+			       struct al_eth_fwd_ctrl_table_entry *entry)
+{
+	u32 val = al_eth_fwd_ctrl_entry_to_val(entry);
+
+	if (use_table)
+		val |= EC_RFW_CTRL_TABLE_DEF_SEL;
+
+	writel(val, &adapter->ec_regs_base->rfw.ctrl_table_def);
+}
+
+void al_eth_hash_key_set(struct al_hw_eth_adapter *adapter, u32 idx, u32 val)
+{
+	writel(val, &adapter->ec_regs_base->rfw_hash[idx].key);
+}
+
+static u32 al_eth_fwd_mac_table_entry_to_val(struct al_eth_fwd_mac_table_entry *entry)
+{
+	u32 val = 0;
+
+	val |= entry->filter ? EC_FWD_MAC_CTRL_RX_VAL_DROP : 0;
+	val |= ((entry->udma_mask << EC_FWD_MAC_CTRL_RX_VAL_UDMA_SHIFT) &
+					EC_FWD_MAC_CTRL_RX_VAL_UDMA_MASK);
+
+	val |= ((entry->qid << EC_FWD_MAC_CTRL_RX_VAL_QID_SHIFT) &
+					EC_FWD_MAC_CTRL_RX_VAL_QID_MASK);
+
+	val |= entry->rx_valid ? EC_FWD_MAC_CTRL_RX_VALID : 0;
+
+	val |= ((entry->tx_target << EC_FWD_MAC_CTRL_TX_VAL_SHIFT) &
+					EC_FWD_MAC_CTRL_TX_VAL_MASK);
+
+	val |= entry->tx_valid ? EC_FWD_MAC_CTRL_TX_VALID : 0;
+
+	return val;
+}
+
+void al_eth_fwd_mac_table_set(struct al_hw_eth_adapter *adapter, u32 idx,
+			      struct al_eth_fwd_mac_table_entry *entry)
+{
+	u32 val;
+
+	WARN_ON(idx >= AL_ETH_FWD_MAC_NUM);
+
+	val = (entry->addr[2] << 24) | (entry->addr[3] << 16) |
+	      (entry->addr[4] << 8) | entry->addr[5];
+	writel(val, &adapter->ec_regs_base->fwd_mac[idx].data_l);
+	val = (entry->addr[0] << 8) | entry->addr[1];
+	writel(val, &adapter->ec_regs_base->fwd_mac[idx].data_h);
+	val = (entry->mask[2] << 24) | (entry->mask[3] << 16) |
+	      (entry->mask[4] << 8) | entry->mask[5];
+	writel(val, &adapter->ec_regs_base->fwd_mac[idx].mask_l);
+	val = (entry->mask[0] << 8) | entry->mask[1];
+	writel(val, &adapter->ec_regs_base->fwd_mac[idx].mask_h);
+
+	val = al_eth_fwd_mac_table_entry_to_val(entry);
+	writel(val, &adapter->ec_regs_base->fwd_mac[idx].ctrl);
+}
+
+void al_eth_mac_addr_store(void * __iomem ec_base, u32 idx, u8 *addr)
+{
+	struct al_ec_regs __iomem *ec_regs_base =
+		(struct al_ec_regs __iomem *)ec_base;
+	u32 val;
+
+	val = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
+	writel(val, &ec_regs_base->fwd_mac[idx].data_l);
+	val = (addr[0] << 8) | addr[1];
+	writel(val, &ec_regs_base->fwd_mac[idx].data_h);
+}
+
+void al_eth_mac_addr_read(void * __iomem ec_base, u32 idx, u8 *addr)
+{
+	struct al_ec_regs __iomem *ec_regs_base =
+		(struct al_ec_regs __iomem *)ec_base;
+	u32 addr_lo = readl(&ec_regs_base->fwd_mac[idx].data_l);
+	u16 addr_hi = readl(&ec_regs_base->fwd_mac[idx].data_h);
+
+	addr[5] = addr_lo & 0xff;
+	addr[4] = (addr_lo >> 8) & 0xff;
+	addr[3] = (addr_lo >> 16) & 0xff;
+	addr[2] = (addr_lo >> 24) & 0xff;
+	addr[1] = addr_hi & 0xff;
+	addr[0] = (addr_hi >> 8) & 0xff;
+}
+
+void al_eth_fwd_pbits_table_set(struct al_hw_eth_adapter *adapter, u32 idx, u8 prio)
+{
+	WARN_ON(idx >= AL_ETH_FWD_PBITS_TABLE_NUM); /* valid PBIT index */
+	WARN_ON(prio >= AL_ETH_FWD_PRIO_TABLE_NUM); /* valid PRIO index */
+
+	writel(idx, &adapter->ec_regs_base->rfw.pbits_table_addr);
+	writel(prio, &adapter->ec_regs_base->rfw.pbits_table_data);
+}
+
+void al_eth_fwd_priority_table_set(struct al_hw_eth_adapter *adapter, u8 prio, u8 qid)
+{
+	WARN_ON(prio >= AL_ETH_FWD_PRIO_TABLE_NUM); /* valid PRIO index */
+
+	writel(qid, &adapter->ec_regs_base->rfw_priority[prio].queue);
+}
+
+#define AL_ETH_RFW_FILTER_SUPPORTED(rev_id)	\
+	(AL_ETH_RFW_FILTER_UNDET_MAC | \
+	AL_ETH_RFW_FILTER_DET_MAC | \
+	AL_ETH_RFW_FILTER_TAGGED | \
+	AL_ETH_RFW_FILTER_UNTAGGED | \
+	AL_ETH_RFW_FILTER_BC | \
+	AL_ETH_RFW_FILTER_MC | \
+	AL_ETH_RFW_FILTER_VLAN_VID | \
+	AL_ETH_RFW_FILTER_CTRL_TABLE | \
+	AL_ETH_RFW_FILTER_PROT_INDEX | \
+	AL_ETH_RFW_FILTER_WOL | \
+	AL_ETH_RFW_FILTER_PARSE)
+
+/* Configure the receive filters */
+int al_eth_filter_config(struct al_hw_eth_adapter *adapter,
+			 struct al_eth_filter_params *params)
+{
+	u32 reg;
+
+	if (params->filters & ~(AL_ETH_RFW_FILTER_SUPPORTED(adapter->rev_id))) {
+		netdev_err(adapter->netdev,
+			   "[%s]: unsupported filter options (0x%08x)\n",
+			   adapter->name, params->filters);
+		return -EINVAL;
+	}
+
+	reg = readl(&adapter->ec_regs_base->rfw.out_cfg);
+
+	if (params->enable)
+		reg |= EC_RFW_OUT_CFG_DROP_EN;
+	else
+		reg &= ~EC_RFW_OUT_CFG_DROP_EN;
+
+	writel(reg, &adapter->ec_regs_base->rfw.out_cfg);
+
+	reg = readl(&adapter->ec_regs_base->rfw.filter);
+	reg &= ~AL_ETH_RFW_FILTER_SUPPORTED(adapter->rev_id);
+	reg |= params->filters;
+	writel(reg, &adapter->ec_regs_base->rfw.filter);
+
+	if (params->filters & AL_ETH_RFW_FILTER_PROT_INDEX) {
+		int i;
+
+		for (i = 0; i < AL_ETH_PROTOCOLS_NUM; i++) {
+			reg = readl(&adapter->ec_regs_base->epe_a[i].prot_act);
+			if (params->filter_proto[i])
+				reg |= EC_EPE_A_PROT_ACT_DROP;
+			else
+				reg &= ~EC_EPE_A_PROT_ACT_DROP;
+			writel(reg, &adapter->ec_regs_base->epe_a[i].prot_act);
+		}
+	}
+
+	return 0;
+}
+
+int al_eth_flow_control_config(struct al_hw_eth_adapter *adapter,
+			       struct al_eth_flow_control_params *params)
+{
+	u32 reg;
+	int i;
+
+	WARN_ON(!params); /* valid params pointer */
+
+	switch (params->type) {
+	case AL_ETH_FLOW_CONTROL_TYPE_LINK_PAUSE:
+		netdev_dbg(adapter->netdev,
+			   "[%s]: config flow control to link pause mode.\n",
+			   adapter->name);
+
+		/* config the mac */
+		if (AL_ETH_IS_1G_MAC(adapter->mac_mode)) {
+			/* set quanta value */
+			writel(params->quanta,
+			       &adapter->mac_regs_base->mac_1g.pause_quant);
+			writel(params->quanta_th,
+			       &adapter->ec_regs_base->efc.xoff_timer_1g);
+
+		} else if (AL_ETH_IS_10G_MAC(adapter->mac_mode) ||
+			   AL_ETH_IS_25G_MAC(adapter->mac_mode)) {
+			/* set quanta value */
+			writel(params->quanta,
+			       &adapter->mac_regs_base->mac_10g.cl01_pause_quanta);
+			/* set quanta threshold value */
+			writel(params->quanta_th,
+			       &adapter->mac_regs_base->mac_10g.cl01_quanta_thresh);
+		} else {
+			/* set quanta value */
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL01_PAUSE_QUANTA_ADDR,
+						 params->quanta);
+			/* set quanta threshold value */
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL01_QUANTA_THRESH_ADDR,
+						 params->quanta_th);
+		}
+
+		if (params->obay_enable)
+			/* Tx path FIFO, unmask pause_on from MAC when PAUSE packet received */
+			writel(1, &adapter->ec_regs_base->efc.ec_pause);
+		else
+			writel(0, &adapter->ec_regs_base->efc.ec_pause);
+
+		/* Rx path */
+		if (params->gen_enable)
+			/* enable generating xoff from ec fifo almost full indication in hysteresis mode */
+			writel(BIT(EC_EFC_EC_XOFF_MASK_2_SHIFT),
+			       &adapter->ec_regs_base->efc.ec_xoff);
+		else
+			writel(0, &adapter->ec_regs_base->efc.ec_xoff);
+
+		if (AL_ETH_IS_1G_MAC(adapter->mac_mode))
+			/* in 1G mode, enable generating xon from ec fifo in hysteresis mode*/
+			writel(EC_EFC_XON_MASK_2 | EC_EFC_XON_MASK_1,
+			       &adapter->ec_regs_base->efc.xon);
+
+		/* set hysteresis mode thresholds */
+		writel(params->rx_fifo_th_low | (params->rx_fifo_th_high << EC_EFC_RX_FIFO_HYST_TH_HIGH_SHIFT),
+		       &adapter->ec_regs_base->efc.rx_fifo_hyst);
+
+		for (i = 0; i < 4; i++) {
+			if (params->obay_enable)
+				/* Tx path UDMA, unmask pause_on for all queues */
+				writel(params->prio_q_map[i][0],
+				       &adapter->ec_regs_base->fc_udma[i].q_pause_0);
+			else
+				writel(0,
+				       &adapter->ec_regs_base->fc_udma[i].q_pause_0);
+
+			if (params->gen_enable)
+				/* Rx path UDMA, enable generating xoff from UDMA queue almost full indication */
+				writel(params->prio_q_map[i][0],
+				       &adapter->ec_regs_base->fc_udma[i].q_xoff_0);
+			else
+				writel(0,
+				       &adapter->ec_regs_base->fc_udma[i].q_xoff_0);
+		}
+	break;
+	case AL_ETH_FLOW_CONTROL_TYPE_PFC:
+		netdev_dbg(adapter->netdev,
+			   "[%s]: config flow control to PFC mode.\n",
+			   adapter->name);
+		WARN_ON(!!AL_ETH_IS_1G_MAC(adapter->mac_mode)); /* pfc not available for RGMII mode */
+
+		for (i = 0; i < 4; i++) {
+			int prio;
+
+			for (prio = 0; prio < 8; prio++) {
+				if (params->obay_enable)
+					/* Tx path UDMA, unmask pause_on for all queues */
+					writel(params->prio_q_map[i][prio],
+					       &adapter->ec_regs_base->fc_udma[i].q_pause_0 + prio);
+				else
+					writel(0,
+					       &adapter->ec_regs_base->fc_udma[i].q_pause_0 + prio);
+
+				if (params->gen_enable)
+					writel(params->prio_q_map[i][prio],
+					       &adapter->ec_regs_base->fc_udma[i].q_xoff_0 + prio);
+				else
+					writel(0,
+					       &adapter->ec_regs_base->fc_udma[i].q_xoff_0 + prio);
+			}
+		}
+
+		/* Rx path */
+		/* enable generating xoff from ec fifo almost full indication in hysteresis mode */
+		if (params->gen_enable)
+			writel(0xFF << EC_EFC_EC_XOFF_MASK_2_SHIFT,
+			       &adapter->ec_regs_base->efc.ec_xoff);
+		else
+			writel(0, &adapter->ec_regs_base->efc.ec_xoff);
+
+		/* set hysteresis mode thresholds */
+		writel(params->rx_fifo_th_low | (params->rx_fifo_th_high << EC_EFC_RX_FIFO_HYST_TH_HIGH_SHIFT),
+		       &adapter->ec_regs_base->efc.rx_fifo_hyst);
+
+		if (AL_ETH_IS_10G_MAC(adapter->mac_mode) || AL_ETH_IS_25G_MAC(adapter->mac_mode)) {
+			/* config the 10g_mac */
+			/* set quanta value (same value for all prios) */
+			reg = params->quanta | (params->quanta << 16);
+			writel(reg,
+			       &adapter->mac_regs_base->mac_10g.cl01_pause_quanta);
+			writel(reg,
+			       &adapter->mac_regs_base->mac_10g.cl23_pause_quanta);
+			writel(reg,
+			       &adapter->mac_regs_base->mac_10g.cl45_pause_quanta);
+			writel(reg,
+			       &adapter->mac_regs_base->mac_10g.cl67_pause_quanta);
+			/* set quanta threshold value (same value for all prios) */
+			reg = params->quanta_th | (params->quanta_th << 16);
+			writel(reg,
+			       &adapter->mac_regs_base->mac_10g.cl01_quanta_thresh);
+			writel(reg,
+			       &adapter->mac_regs_base->mac_10g.cl23_quanta_thresh);
+			writel(reg,
+			       &adapter->mac_regs_base->mac_10g.cl45_quanta_thresh);
+			writel(reg,
+			       &adapter->mac_regs_base->mac_10g.cl67_quanta_thresh);
+
+			/* enable PFC in the 10g_MAC */
+			reg = readl(&adapter->mac_regs_base->mac_10g.cmd_cfg);
+			reg |= BIT(19);
+			writel(reg, &adapter->mac_regs_base->mac_10g.cmd_cfg);
+		} else {
+			/* config the 40g_mac */
+			/* set quanta value (same value for all prios) */
+			reg = params->quanta | (params->quanta << 16);
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL01_PAUSE_QUANTA_ADDR, reg);
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL23_PAUSE_QUANTA_ADDR, reg);
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL45_PAUSE_QUANTA_ADDR, reg);
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL67_PAUSE_QUANTA_ADDR, reg);
+			/* set quanta threshold value (same value for all prios) */
+			reg = params->quanta_th | (params->quanta_th << 16);
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL01_QUANTA_THRESH_ADDR, reg);
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL23_QUANTA_THRESH_ADDR, reg);
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL45_QUANTA_THRESH_ADDR, reg);
+			al_eth_40g_mac_reg_write(adapter,
+						 ETH_MAC_GEN_V3_MAC_40G_CL67_QUANTA_THRESH_ADDR, reg);
+
+			/* enable PFC in the 40g_MAC */
+			reg = readl(&adapter->mac_regs_base->mac_10g.cmd_cfg);
+			reg |= BIT(19);
+			writel(reg, &adapter->mac_regs_base->mac_10g.cmd_cfg);
+			reg = al_eth_40g_mac_reg_read(adapter, ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_ADDR);
+
+			reg |= ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_PFC_MODE;
+
+			al_eth_40g_mac_reg_write(adapter, ETH_MAC_GEN_V3_MAC_40G_COMMAND_CONFIG_ADDR, reg);
+		}
+		break;
+	default:
+		netdev_err(adapter->netdev,
+			   "[%s]: unsupported flow control type %d\n",
+			   adapter->name, params->type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Traffic control */
+
+int al_eth_flr_rmn(int (*pci_read_config_u32)(void *handle, int where, u32 *val),
+		   int (*pci_write_config_u32)(void *handle, int where, u32 val),
+		   void *handle, void __iomem *mac_base)
+{
+	struct al_eth_mac_regs __iomem *mac_regs_base =
+		(struct	al_eth_mac_regs __iomem *)mac_base;
+	u32 cfg_reg_store[6];
+	u32 reg;
+	u32 mux_sel;
+	int i = 0;
+
+	(*pci_read_config_u32)(handle, AL_ADAPTER_GENERIC_CONTROL_0, &reg);
+
+	/* reset 1G mac */
+	reg |= AL_ADAPTER_GENERIC_CONTROL_0_ETH_RESET_1GMAC;
+	(*pci_write_config_u32)(handle, AL_ADAPTER_GENERIC_CONTROL_0, reg);
+	udelay(1000);
+	/* don't reset 1G mac */
+	reg &= ~AL_ADAPTER_GENERIC_CONTROL_0_ETH_RESET_1GMAC;
+	/* prevent 1G mac reset on FLR */
+	reg &= ~AL_ADAPTER_GENERIC_CONTROL_0_ETH_RESET_1GMAC_ON_FLR;
+	/* prevent adapter reset */
+	(*pci_write_config_u32)(handle, AL_ADAPTER_GENERIC_CONTROL_0, reg);
+
+	mux_sel = readl(&mac_regs_base->gen.mux_sel);
+
+	/* save pci register that get reset due to flr*/
+	(*pci_read_config_u32)(handle, AL_PCI_COMMAND, &cfg_reg_store[i++]);
+	(*pci_read_config_u32)(handle, 0xC, &cfg_reg_store[i++]);
+	(*pci_read_config_u32)(handle, 0x10, &cfg_reg_store[i++]);
+	(*pci_read_config_u32)(handle, 0x18, &cfg_reg_store[i++]);
+	(*pci_read_config_u32)(handle, 0x20, &cfg_reg_store[i++]);
+	(*pci_read_config_u32)(handle, 0x110, &cfg_reg_store[i++]);
+
+	/* do flr */
+	(*pci_write_config_u32)(handle, AL_PCI_EXP_CAP_BASE + AL_PCI_EXP_DEVCTL, AL_PCI_EXP_DEVCTL_BCR_FLR);
+	udelay(1000);
+	/* restore command */
+	i = 0;
+	(*pci_write_config_u32)(handle, AL_PCI_COMMAND, cfg_reg_store[i++]);
+	(*pci_write_config_u32)(handle, 0xC, cfg_reg_store[i++]);
+	(*pci_write_config_u32)(handle, 0x10, cfg_reg_store[i++]);
+	(*pci_write_config_u32)(handle, 0x18, cfg_reg_store[i++]);
+	(*pci_write_config_u32)(handle, 0x20, cfg_reg_store[i++]);
+	(*pci_write_config_u32)(handle, 0x110, cfg_reg_store[i++]);
+
+	writel((readl(&mac_regs_base->gen.mux_sel) & ~ETH_MAC_GEN_MUX_SEL_KR_IN_MASK) | mux_sel,
+	       &mac_regs_base->gen.mux_sel);
+
+	/* set SGMII clock to 125MHz */
+	writel(0x03320501, &mac_regs_base->sgmii.clk_div);
+
+	/* reset 1G mac */
+	reg |= AL_ADAPTER_GENERIC_CONTROL_0_ETH_RESET_1GMAC;
+	(*pci_write_config_u32)(handle, AL_ADAPTER_GENERIC_CONTROL_0, reg);
+
+	udelay(1000);
+
+	/* clear 1G mac reset */
+	reg &= ~AL_ADAPTER_GENERIC_CONTROL_0_ETH_RESET_1GMAC;
+	(*pci_write_config_u32)(handle, AL_ADAPTER_GENERIC_CONTROL_0, reg);
+
+	/* reset SGMII mac clock to default */
+	writel(0x00320501, &mac_regs_base->sgmii.clk_div);
+	udelay(1000);
+	/* reset async fifo */
+	reg = readl(&mac_regs_base->gen.sd_fifo_ctrl);
+	reg |= 0xF0;
+	writel(reg, &mac_regs_base->gen.sd_fifo_ctrl);
+	reg = readl(&mac_regs_base->gen.sd_fifo_ctrl);
+	reg &= ~0xF0;
+	writel(reg, &mac_regs_base->gen.sd_fifo_ctrl);
+
+	return 0;
+}
+
+/* board params register 1 */
+#define AL_HW_ETH_MEDIA_TYPE_MASK	(GENMASK(3, 0))
+#define AL_HW_ETH_MEDIA_TYPE_SHIFT	0
+#define AL_HW_ETH_EXT_PHY_SHIFT	4
+#define AL_HW_ETH_PHY_ADDR_MASK	(GENMASK(9, 5))
+#define AL_HW_ETH_PHY_ADDR_SHIFT	5
+#define AL_HW_ETH_SFP_EXIST_SHIFT	10
+#define AL_HW_ETH_AN_ENABLE_SHIFT	11
+#define AL_HW_ETH_KR_LT_ENABLE_SHIFT	12
+#define AL_HW_ETH_KR_FEC_ENABLE_SHIFT	13
+#define AL_HW_ETH_MDIO_FREQ_MASK	(GENMASK(15, 14))
+#define AL_HW_ETH_MDIO_FREQ_SHIFT	14
+#define AL_HW_ETH_I2C_ADAPTER_ID_MASK	(GENMASK(19, 16))
+#define AL_HW_ETH_I2C_ADAPTER_ID_SHIFT	16
+#define AL_HW_ETH_EXT_PHY_IF_MASK	(GENMASK(21, 20))
+#define AL_HW_ETH_EXT_PHY_IF_SHIFT	20
+#define AL_HW_ETH_AUTO_NEG_MODE_SHIFT	22
+#define AL_HW_ETH_REF_CLK_FREQ_MASK	(GENMASK(31, 29))
+#define AL_HW_ETH_REF_CLK_FREQ_SHIFT	29
+
+/* board params register 2 */
+#define AL_HW_ETH_1000_BASE_X_SHIFT		1
+#define AL_HW_ETH_1G_AN_DISABLE_SHIFT		2
+#define AL_HW_ETH_1G_SPEED_MASK		(GENMASK(4, 3))
+#define AL_HW_ETH_1G_SPEED_SHIFT		3
+#define AL_HW_ETH_1G_HALF_DUPLEX_SHIFT		5
+#define AL_HW_ETH_1G_FC_DISABLE_SHIFT		6
+#define AL_HW_ETH_RETIMER_EXIST_SHIFT		7
+#define AL_HW_ETH_RETIMER_BUS_ID_MASK		(GENMASK(11, 8))
+#define AL_HW_ETH_RETIMER_BUS_ID_SHIFT		8
+#define AL_HW_ETH_RETIMER_I2C_ADDR_MASK	(GENMASK(18, 12))
+#define AL_HW_ETH_RETIMER_I2C_ADDR_SHIFT	12
+#define AL_HW_ETH_RETIMER_CHANNEL_SHIFT	19
+#define AL_HW_ETH_DAC_LENGTH_MASK		(GENMASK(23, 20))
+#define AL_HW_ETH_DAC_LENGTH_SHIFT		20
+#define AL_HW_ETH_DAC_SHIFT			24
+#define AL_HW_ETH_RETIMER_TYPE_MASK		(GENMASK(26, 25))
+#define AL_HW_ETH_RETIMER_TYPE_SHIFT		25
+#define AL_HW_ETH_RETIMER_CHANNEL_2_MASK	(GENMASK(28, 27))
+#define AL_HW_ETH_RETIMER_CHANNEL_2_SHIFT	27
+#define AL_HW_ETH_RETIMER_TX_CHANNEL_MASK	(GENMASK(31, 29))
+#define AL_HW_ETH_RETIMER_TX_CHANNEL_SHIFT	29
+
+/* board params register 3 */
+#define AL_HW_ETH_GPIO_SFP_PRESENT_MASK	(GENMASK(5, 0))
+#define AL_HW_ETH_GPIO_SFP_PRESENT_SHIFT	0
+
+int al_eth_board_params_set(void * __iomem mac_base,
+			    struct al_eth_board_params *params)
+{
+	struct al_eth_mac_regs __iomem *mac_regs_base =
+		(struct	al_eth_mac_regs __iomem *)mac_base;
+	u32 reg = 0;
+
+	/* ************* Setting Board params register 1 **************** */
+	reg &= ~AL_HW_ETH_MEDIA_TYPE_MASK;
+	reg |= (params->media_type << AL_HW_ETH_MEDIA_TYPE_SHIFT) & AL_HW_ETH_MEDIA_TYPE_MASK;
+	reg |= !!params->phy_exist << AL_HW_ETH_EXT_PHY_SHIFT;
+	reg &= ~AL_HW_ETH_PHY_ADDR_MASK;
+	reg |= (params->phy_mdio_addr << AL_HW_ETH_PHY_ADDR_SHIFT) & AL_HW_ETH_PHY_ADDR_MASK;
+
+	reg |= !!params->sfp_plus_module_exist << AL_HW_ETH_SFP_EXIST_SHIFT;
+
+	reg |= !!params->autoneg_enable << AL_HW_ETH_AN_ENABLE_SHIFT;
+	reg |= !!params->kr_lt_enable << AL_HW_ETH_KR_LT_ENABLE_SHIFT;
+	reg |= !!params->kr_fec_enable << AL_HW_ETH_KR_FEC_ENABLE_SHIFT;
+	reg &= ~AL_HW_ETH_MDIO_FREQ_MASK;
+	reg |= (params->mdio_freq << AL_HW_ETH_MDIO_FREQ_SHIFT) & AL_HW_ETH_MDIO_FREQ_MASK;
+	reg &= ~AL_HW_ETH_I2C_ADAPTER_ID_MASK;
+	reg |= (params->i2c_adapter_id << AL_HW_ETH_I2C_ADAPTER_ID_SHIFT) & AL_HW_ETH_I2C_ADAPTER_ID_MASK;
+	reg &= ~AL_HW_ETH_EXT_PHY_IF_MASK;
+	reg |= (params->phy_if << AL_HW_ETH_EXT_PHY_IF_SHIFT) & AL_HW_ETH_EXT_PHY_IF_MASK;
+
+	reg |= (params->an_mode == AL_ETH_BOARD_AUTONEG_IN_BAND << AL_HW_ETH_AUTO_NEG_MODE_SHIFT);
+
+	reg &= ~AL_HW_ETH_REF_CLK_FREQ_MASK;
+	reg |= (params->ref_clk_freq << AL_HW_ETH_REF_CLK_FREQ_SHIFT) & AL_HW_ETH_REF_CLK_FREQ_MASK;
+
+	WARN_ON(!reg);
+
+	writel(reg, &mac_regs_base->mac_1g.scratch);
+
+	/* ************* Setting Board params register 2 **************** */
+	reg = 0;
+	reg |= !!params->force_1000_base_x << AL_HW_ETH_1000_BASE_X_SHIFT;
+
+	reg |= !!params->an_disable << AL_HW_ETH_1G_AN_DISABLE_SHIFT;
+
+	reg &= ~AL_HW_ETH_1G_SPEED_MASK;
+	reg |= (params->speed << AL_HW_ETH_1G_SPEED_SHIFT) & AL_HW_ETH_1G_SPEED_MASK;
+
+	reg |= !!params->half_duplex << AL_HW_ETH_1G_HALF_DUPLEX_SHIFT;
+
+	reg |= !!params->fc_disable << AL_HW_ETH_1G_FC_DISABLE_SHIFT;
+
+	reg |= !!params->retimer_exist << AL_HW_ETH_RETIMER_EXIST_SHIFT;
+	reg &= ~AL_HW_ETH_RETIMER_BUS_ID_MASK;
+	reg |= (params->retimer_bus_id << AL_HW_ETH_RETIMER_BUS_ID_SHIFT) & AL_HW_ETH_RETIMER_BUS_ID_MASK;
+	reg &= ~AL_HW_ETH_RETIMER_I2C_ADDR_MASK;
+	reg |= (params->retimer_i2c_addr << AL_HW_ETH_RETIMER_I2C_ADDR_SHIFT) & AL_HW_ETH_RETIMER_I2C_ADDR_MASK;
+
+	reg |= ((params->retimer_channel & BIT(0)) << AL_HW_ETH_RETIMER_CHANNEL_SHIFT);
+
+	reg &= ~AL_HW_ETH_RETIMER_CHANNEL_2_MASK;
+	reg |= ((params->retimer_channel & 0x6) >> 1 << AL_HW_ETH_RETIMER_CHANNEL_2_SHIFT) & AL_HW_ETH_RETIMER_CHANNEL_2_MASK;
+
+	reg &= ~AL_HW_ETH_DAC_LENGTH_MASK;
+	reg |= (params->dac_len << AL_HW_ETH_DAC_LENGTH_SHIFT) & AL_HW_ETH_DAC_LENGTH_MASK;
+	reg |= (params->dac << AL_HW_ETH_DAC_SHIFT);
+
+	reg &= ~AL_HW_ETH_RETIMER_TYPE_MASK;
+	reg |= (params->retimer_type << AL_HW_ETH_RETIMER_TYPE_SHIFT) & AL_HW_ETH_RETIMER_TYPE_MASK;
+
+	reg &= ~AL_HW_ETH_RETIMER_TX_CHANNEL_MASK;
+	reg |= (params->retimer_tx_channel << AL_HW_ETH_RETIMER_TX_CHANNEL_SHIFT) & AL_HW_ETH_RETIMER_TX_CHANNEL_MASK;
+
+	writel(reg, &mac_regs_base->mac_10g.scratch);
+
+	/* ************* Setting Board params register 3 **************** */
+	reg = 0;
+
+	reg &= ~AL_HW_ETH_GPIO_SFP_PRESENT_MASK;
+	reg |= (params->gpio_sfp_present << AL_HW_ETH_GPIO_SFP_PRESENT_SHIFT) & AL_HW_ETH_GPIO_SFP_PRESENT_MASK;
+
+	writel(reg, &mac_regs_base->mac_1g.mac_0);
+
+	return 0;
+}
+
+int al_eth_board_params_get(void * __iomem mac_base, struct al_eth_board_params *params)
+{
+	struct al_eth_mac_regs __iomem *mac_regs_base =
+		(struct	al_eth_mac_regs __iomem *)mac_base;
+	u32	reg = readl(&mac_regs_base->mac_1g.scratch);
+
+	/* check if the register was initialized, 0 is not a valid value */
+	if (!reg)
+		return -ENOENT;
+
+	/* ************* Getting Board params register 1 **************** */
+	params->media_type = (reg & AL_HW_ETH_MEDIA_TYPE_MASK)
+			>> AL_HW_ETH_MEDIA_TYPE_SHIFT;
+	if (((reg >> AL_HW_ETH_EXT_PHY_SHIFT) & 0x1))
+		params->phy_exist = true;
+	else
+		params->phy_exist = false;
+
+	params->phy_mdio_addr = (reg & AL_HW_ETH_PHY_ADDR_MASK) >>
+			AL_HW_ETH_PHY_ADDR_SHIFT;
+
+	if (((reg >> AL_HW_ETH_SFP_EXIST_SHIFT) & 0x1))
+		params->sfp_plus_module_exist = true;
+	else
+		params->sfp_plus_module_exist = false;
+
+	if (((reg >> AL_HW_ETH_AN_ENABLE_SHIFT) & 0x1))
+		params->autoneg_enable = true;
+	else
+		params->autoneg_enable = false;
+
+	if (((reg >> AL_HW_ETH_KR_LT_ENABLE_SHIFT) & 0x1))
+		params->kr_lt_enable = true;
+	else
+		params->kr_lt_enable = false;
+
+	if (((reg >> AL_HW_ETH_KR_FEC_ENABLE_SHIFT) & 0x1))
+		params->kr_fec_enable = true;
+	else
+		params->kr_fec_enable = false;
+
+	params->mdio_freq = (reg & AL_HW_ETH_MDIO_FREQ_MASK) >>
+			AL_HW_ETH_MDIO_FREQ_SHIFT;
+
+	params->i2c_adapter_id = (reg & AL_HW_ETH_I2C_ADAPTER_ID_MASK) >>
+			AL_HW_ETH_I2C_ADAPTER_ID_SHIFT;
+
+	params->phy_if = (reg & AL_HW_ETH_EXT_PHY_IF_MASK) >>
+			AL_HW_ETH_EXT_PHY_IF_SHIFT;
+
+	if (((reg >> AL_HW_ETH_AUTO_NEG_MODE_SHIFT) & 0x1))
+		params->an_mode = true;
+	else
+		params->an_mode = false;
+
+	params->ref_clk_freq = (reg & AL_HW_ETH_REF_CLK_FREQ_MASK) >>
+			AL_HW_ETH_REF_CLK_FREQ_SHIFT;
+
+	/* ************* Getting Board params register 2 **************** */
+	reg = readl(&mac_regs_base->mac_10g.scratch);
+
+	if (((reg >> AL_HW_ETH_1000_BASE_X_SHIFT) & 0x1))
+		params->force_1000_base_x = true;
+	else
+		params->force_1000_base_x = false;
+
+	if (((reg >> AL_HW_ETH_1G_AN_DISABLE_SHIFT) & 0x1))
+		params->an_disable = true;
+	else
+		params->an_disable = false;
+
+	params->speed = (reg & AL_HW_ETH_1G_SPEED_MASK) >>
+			AL_HW_ETH_1G_SPEED_SHIFT;
+
+	if (((reg >> AL_HW_ETH_1G_HALF_DUPLEX_SHIFT) & 0x1))
+		params->half_duplex = true;
+	else
+		params->half_duplex = false;
+
+	if (((reg >> AL_HW_ETH_1G_FC_DISABLE_SHIFT) & 0x1))
+		params->fc_disable = true;
+	else
+		params->fc_disable = false;
+
+	if (((reg >> AL_HW_ETH_RETIMER_EXIST_SHIFT) & 0x1))
+		params->retimer_exist = true;
+	else
+		params->retimer_exist = false;
+
+	params->retimer_bus_id = (reg & AL_HW_ETH_RETIMER_BUS_ID_MASK) >>
+			AL_HW_ETH_RETIMER_BUS_ID_SHIFT;
+	params->retimer_i2c_addr = (reg & AL_HW_ETH_RETIMER_I2C_ADDR_MASK) >>
+			AL_HW_ETH_RETIMER_I2C_ADDR_SHIFT;
+
+	params->retimer_channel =
+		((((reg >> AL_HW_ETH_RETIMER_CHANNEL_SHIFT) & 0x1)) |
+		 ((reg & AL_HW_ETH_RETIMER_CHANNEL_2_MASK) >>
+		  AL_HW_ETH_RETIMER_CHANNEL_2_SHIFT) << 1);
+
+	params->dac_len = (reg & AL_HW_ETH_DAC_LENGTH_MASK) >>
+			AL_HW_ETH_DAC_LENGTH_SHIFT;
+
+	if (((reg >> AL_HW_ETH_DAC_SHIFT) & 0x1))
+		params->dac = true;
+	else
+		params->dac = false;
+
+	params->retimer_type = (reg & AL_HW_ETH_RETIMER_TYPE_MASK) >>
+			AL_HW_ETH_RETIMER_TYPE_SHIFT;
+
+	params->retimer_tx_channel = (reg & AL_HW_ETH_RETIMER_TX_CHANNEL_MASK) >>
+			AL_HW_ETH_RETIMER_TX_CHANNEL_SHIFT;
+
+	/* ************* Getting Board params register 3 **************** */
+	reg = readl(&mac_regs_base->mac_1g.mac_0);
+
+	params->gpio_sfp_present = (reg & AL_HW_ETH_GPIO_SFP_PRESENT_MASK) >>
+			AL_HW_ETH_GPIO_SFP_PRESENT_SHIFT;
+
+	return 0;
+}
+
+/* Wake-On-Lan (WoL) */
+static inline void al_eth_byte_arr_to_reg(u32 *reg, u8 *arr,
+					  unsigned int num_bytes)
+{
+	u32 mask = 0xff;
+	unsigned int i;
+
+	WARN_ON(num_bytes > 4);
+
+	*reg = 0;
+
+	for (i = 0 ; i < num_bytes ; i++) {
+		*reg &= ~mask;
+		*reg |= (arr[i] << (sizeof(u8) * i)) & mask;
+		mask = mask << sizeof(u8);
+	}
+}
+
+int al_eth_wol_enable(struct al_hw_eth_adapter *adapter,
+		      struct al_eth_wol_params *wol)
+{
+	u32 reg = 0;
+
+	if (wol->int_mask & AL_ETH_WOL_INT_MAGIC_PSWD) {
+		WARN_ON(!wol->pswd);
+
+		al_eth_byte_arr_to_reg(&reg, &wol->pswd[0], 4);
+		writel(reg, &adapter->ec_regs_base->wol.magic_pswd_l);
+
+		al_eth_byte_arr_to_reg(&reg, &wol->pswd[4], 2);
+		writel(reg, &adapter->ec_regs_base->wol.magic_pswd_h);
+	}
+
+	if (wol->int_mask & AL_ETH_WOL_INT_IPV4) {
+		WARN_ON(!wol->ipv4);
+
+		al_eth_byte_arr_to_reg(&reg, &wol->ipv4[0], 4);
+		writel(reg, &adapter->ec_regs_base->wol.ipv4_dip);
+	}
+
+	if (wol->int_mask & AL_ETH_WOL_INT_IPV6) {
+		WARN_ON(!wol->ipv6);
+
+		al_eth_byte_arr_to_reg(&reg, &wol->ipv6[0], 4);
+		writel(reg, &adapter->ec_regs_base->wol.ipv6_dip_word0);
+
+		al_eth_byte_arr_to_reg(&reg, &wol->ipv6[4], 4);
+		writel(reg, &adapter->ec_regs_base->wol.ipv6_dip_word1);
+
+		al_eth_byte_arr_to_reg(&reg, &wol->ipv6[8], 4);
+		writel(reg, &adapter->ec_regs_base->wol.ipv6_dip_word2);
+
+		al_eth_byte_arr_to_reg(&reg, &wol->ipv6[12], 4);
+		writel(reg, &adapter->ec_regs_base->wol.ipv6_dip_word3);
+	}
+
+	if (wol->int_mask &
+	    (AL_ETH_WOL_INT_ETHERTYPE_BC | AL_ETH_WOL_INT_ETHERTYPE_DA)) {
+		reg = ((u32)wol->ethr_type2 << 16);
+		reg |= wol->ethr_type1;
+
+		writel(reg, &adapter->ec_regs_base->wol.ethertype);
+	}
+
+	/* make sure we dont forwarding packets without interrupt */
+	WARN_ON((wol->forward_mask | wol->int_mask) != wol->int_mask);
+
+	reg = ((u32)wol->forward_mask << 16);
+	reg |= wol->int_mask;
+	writel(reg, &adapter->ec_regs_base->wol.wol_en);
+
+	return 0;
+}
+
+int al_eth_wol_disable(struct al_hw_eth_adapter *adapter)
+{
+	writel(0, &adapter->ec_regs_base->wol.wol_en);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/annapurna/al_hw_unit_adapter_regs.h b/drivers/net/ethernet/annapurna/al_hw_unit_adapter_regs.h
new file mode 100644
index 000000000000..1ad514c4bc5a
--- /dev/null
+++ b/drivers/net/ethernet/annapurna/al_hw_unit_adapter_regs.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017, Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __AL_HW_UNIT_ADAPTER_REGS_H__
+#define __AL_HW_UNIT_ADAPTER_REGS_H__
+
+#define AL_PCI_COMMAND		0x04	/* 16 bits */
+
+#define AL_PCI_EXP_CAP_BASE		0x40
+#define AL_PCI_EXP_DEVCTL		8       /* Device Control */
+#define  AL_PCI_EXP_DEVCTL_BCR_FLR	0x8000  /* Bridge Configuration Retry / FLR */
+
+#define AL_ADAPTER_GENERIC_CONTROL_0		0x1E0
+
+/* When set, all transactions through the PCI conf & mem BARs get timeout */
+#define AL_ADAPTER_GENERIC_CONTROL_0_ETH_RESET_1GMAC		BIT(18)
+#define AL_ADAPTER_GENERIC_CONTROL_0_ETH_RESET_1GMAC_ON_FLR	BIT(26)
+
+#endif
-- 
2.11.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ