[PATCH v3] net: Add NIC controller driver for OcteonTX

Stefan Roese sr at denx.de
Wed Oct 14 10:13:17 CEST 2020


On 26.08.20 14:37, Stefan Roese wrote:
> From: Suneel Garapati <sgarapati at marvell.com>
> 
> Adds support for Network Interface controllers found on
> OcteonTX SoC platforms.
> 
> Signed-off-by: Suneel Garapati <sgarapati at marvell.com>
> Signed-off-by: Stefan Roese <sr at denx.de>
> Cc: Joe Hershberger <joe.hershberger at ni.com>
> ---
> Series-changes: 3
> - Add SoB from Stefan
> - Remove spdx.org line from comment
> - Remove inclusion of common.h header
> - Order header file inclusion
> - Misc minor checkpatch fixes
> 
> Series-changes: 1
> - Change patch subject
> - Rebased on latest TOT
> - Removed inclusion of common.h

Applied to u-boot-marvell/master

Thanks,
Stefan

>   drivers/net/Kconfig                 |   14 +
>   drivers/net/Makefile                |    2 +
>   drivers/net/octeontx/Makefile       |    7 +
>   drivers/net/octeontx/bgx.c          | 1565 +++++++++++++++++++++++++++
>   drivers/net/octeontx/bgx.h          |  259 +++++
>   drivers/net/octeontx/nic.h          |  508 +++++++++
>   drivers/net/octeontx/nic_main.c     |  778 +++++++++++++
>   drivers/net/octeontx/nic_reg.h      |  250 +++++
>   drivers/net/octeontx/nicvf_main.c   |  581 ++++++++++
>   drivers/net/octeontx/nicvf_queues.c | 1140 +++++++++++++++++++
>   drivers/net/octeontx/nicvf_queues.h |  353 ++++++
>   drivers/net/octeontx/q_struct.h     |  695 ++++++++++++
>   drivers/net/octeontx/smi.c          |  380 +++++++
>   drivers/net/octeontx/xcv.c          |  124 +++
>   14 files changed, 6656 insertions(+)
>   create mode 100644 drivers/net/octeontx/Makefile
>   create mode 100644 drivers/net/octeontx/bgx.c
>   create mode 100644 drivers/net/octeontx/bgx.h
>   create mode 100644 drivers/net/octeontx/nic.h
>   create mode 100644 drivers/net/octeontx/nic_main.c
>   create mode 100644 drivers/net/octeontx/nic_reg.h
>   create mode 100644 drivers/net/octeontx/nicvf_main.c
>   create mode 100644 drivers/net/octeontx/nicvf_queues.c
>   create mode 100644 drivers/net/octeontx/nicvf_queues.h
>   create mode 100644 drivers/net/octeontx/q_struct.h
>   create mode 100644 drivers/net/octeontx/smi.c
>   create mode 100644 drivers/net/octeontx/xcv.c
> 
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 039f9fb058..26ea53d346 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -407,6 +407,20 @@ config MT7628_ETH
>   	  The MediaTek MT7628 ethernet interface is used on MT7628 and
>   	  MT7688 based boards.
>   
> +config NET_OCTEONTX
> +	bool "OcteonTX Ethernet support"
> +	depends on ARCH_OCTEONTX
> +	depends on PCI_SRIOV
> +	help
> +	  You must select Y to enable network device support for
> +	  OcteonTX SoCs. If unsure, say n
> +config OCTEONTX_SMI
> +	bool "OcteonTX SMI Device support"
> +	depends on ARCH_OCTEONTX || ARCH_OCTEONTX2
> +	help
> +	  You must select Y to enable SMI controller support for
> +	  OcteonTX or OcteonTX2 SoCs. If unsure, say n
> +
>   config PCH_GBE
>   	bool "Intel Platform Controller Hub EG20T GMAC driver"
>   	depends on DM_ETH && DM_PCI
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 1ecdc40b8f..bee9680f76 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -65,6 +65,8 @@ obj-$(CONFIG_RENESAS_RAVB) += ravb.o
>   obj-$(CONFIG_SMC91111) += smc91111.o
>   obj-$(CONFIG_SMC911X) += smc911x.o
>   obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o
> +obj-$(CONFIG_NET_OCTEONTX) += octeontx/
> +obj-$(CONFIG_OCTEONTX_SMI) += octeontx/smi.o
>   obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
>   obj-$(CONFIG_ULI526X) += uli526x.o
>   obj-$(CONFIG_VSC7385_ENET) += vsc7385.o
> diff --git a/drivers/net/octeontx/Makefile b/drivers/net/octeontx/Makefile
> new file mode 100644
> index 0000000000..d4adb7cdba
> --- /dev/null
> +++ b/drivers/net/octeontx/Makefile
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier:    GPL-2.0
> +#
> +# Copyright (C) 2018 Marvell International Ltd.
> +#
> +
> +obj-$(CONFIG_NET_OCTEONTX) += bgx.o nic_main.o nicvf_queues.o nicvf_main.o \
> +				xcv.o
> diff --git a/drivers/net/octeontx/bgx.c b/drivers/net/octeontx/bgx.c
> new file mode 100644
> index 0000000000..fbe2e2c073
> --- /dev/null
> +++ b/drivers/net/octeontx/bgx.c
> @@ -0,0 +1,1565 @@
> +// SPDX-License-Identifier:    GPL-2.0
> +/*
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#include <config.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <fdt_support.h>
> +#include <malloc.h>
> +#include <miiphy.h>
> +#include <misc.h>
> +#include <net.h>
> +#include <netdev.h>
> +#include <pci.h>
> +#include <pci_ids.h>
> +#include <asm/io.h>
> +#include <asm/arch/board.h>
> +#include <linux/delay.h>
> +#include <linux/libfdt.h>
> +
> +#include "nic_reg.h"
> +#include "nic.h"
> +#include "bgx.h"
> +
> +static const phy_interface_t if_mode[] = {
> +	[QLM_MODE_SGMII]  = PHY_INTERFACE_MODE_SGMII,
> +	[QLM_MODE_RGMII]  = PHY_INTERFACE_MODE_RGMII,
> +	[QLM_MODE_QSGMII] = PHY_INTERFACE_MODE_QSGMII,
> +	[QLM_MODE_XAUI]   = PHY_INTERFACE_MODE_XAUI,
> +	[QLM_MODE_RXAUI]  = PHY_INTERFACE_MODE_RXAUI,
> +};
> +
> +struct lmac {
> +	struct bgx		*bgx;
> +	int			dmac;
> +	u8			mac[6];
> +	bool			link_up;
> +	bool			init_pend;
> +	int			lmacid; /* ID within BGX */
> +	int			phy_addr; /* ID on board */
> +	struct udevice		*dev;
> +	struct mii_dev		*mii_bus;
> +	struct phy_device	*phydev;
> +	unsigned int		last_duplex;
> +	unsigned int		last_link;
> +	unsigned int		last_speed;
> +	int			lane_to_sds;
> +	int			use_training;
> +	int			lmac_type;
> +	u8			qlm_mode;
> +	int			qlm;
> +	bool			is_1gx;
> +};
> +
> +struct bgx {
> +	u8			bgx_id;
> +	int			node;
> +	struct	lmac		lmac[MAX_LMAC_PER_BGX];
> +	int			lmac_count;
> +	u8			max_lmac;
> +	void __iomem		*reg_base;
> +	struct pci_dev		*pdev;
> +	bool			is_rgx;
> +};
> +
> +struct bgx_board_info bgx_board_info[MAX_BGX_PER_NODE];
> +
> +struct bgx *bgx_vnic[MAX_BGX_PER_NODE];
> +
> +/* APIs to read/write BGXX CSRs */
> +static u64 bgx_reg_read(struct bgx *bgx, uint8_t lmac, u64 offset)
> +{
> +	u64 addr = (uintptr_t)bgx->reg_base +
> +				((uint32_t)lmac << 20) + offset;
> +
> +	return readq((void *)addr);
> +}
> +
> +static void bgx_reg_write(struct bgx *bgx, uint8_t lmac,
> +			  u64 offset, u64 val)
> +{
> +	u64 addr = (uintptr_t)bgx->reg_base +
> +				((uint32_t)lmac << 20) + offset;
> +
> +	writeq(val, (void *)addr);
> +}
> +
> +static void bgx_reg_modify(struct bgx *bgx, uint8_t lmac,
> +			   u64 offset, u64 val)
> +{
> +	u64 addr = (uintptr_t)bgx->reg_base +
> +				((uint32_t)lmac << 20) + offset;
> +
> +	writeq(val | bgx_reg_read(bgx, lmac, offset), (void *)addr);
> +}
> +
> +static int bgx_poll_reg(struct bgx *bgx, uint8_t lmac,
> +			u64 reg, u64 mask, bool zero)
> +{
> +	int timeout = 200;
> +	u64 reg_val;
> +
> +	while (timeout) {
> +		reg_val = bgx_reg_read(bgx, lmac, reg);
> +		if (zero && !(reg_val & mask))
> +			return 0;
> +		if (!zero && (reg_val & mask))
> +			return 0;
> +		mdelay(1);
> +		timeout--;
> +	}
> +	return 1;
> +}
> +
> +static int gser_poll_reg(u64 reg, int bit, u64 mask, u64 expected_val,
> +			 int timeout)
> +{
> +	u64 reg_val;
> +
> +	debug("%s reg = %#llx, mask = %#llx,", __func__, reg, mask);
> +	debug(" expected_val = %#llx, bit = %d\n", expected_val, bit);
> +	while (timeout) {
> +		reg_val = readq(reg) >> bit;
> +		if ((reg_val & mask) == (expected_val))
> +			return 0;
> +		mdelay(1);
> +		timeout--;
> +	}
> +	return 1;
> +}
> +
> +static bool is_bgx_port_valid(int bgx, int lmac)
> +{
> +	debug("%s bgx %d lmac %d valid %d\n", __func__, bgx, lmac,
> +	      bgx_board_info[bgx].lmac_reg[lmac]);
> +
> +	if (bgx_board_info[bgx].lmac_reg[lmac])
> +		return 1;
> +	else
> +		return 0;
> +}
> +
> +struct lmac *bgx_get_lmac(int node, int bgx_idx, int lmacid)
> +{
> +	struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
> +
> +	if (bgx)
> +		return &bgx->lmac[lmacid];
> +
> +	return NULL;
> +}
> +
> +const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid)
> +{
> +	struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
> +
> +	if (bgx)
> +		return bgx->lmac[lmacid].mac;
> +
> +	return NULL;
> +}
> +
> +void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac)
> +{
> +	struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
> +
> +	if (!bgx)
> +		return;
> +
> +	memcpy(bgx->lmac[lmacid].mac, mac, 6);
> +}
> +
> +/* Return number of BGX present in HW */
> +void bgx_get_count(int node, int *bgx_count)
> +{
> +	int i;
> +	struct bgx *bgx;
> +
> +	*bgx_count = 0;
> +	for (i = 0; i < MAX_BGX_PER_NODE; i++) {
> +		bgx = bgx_vnic[node * MAX_BGX_PER_NODE + i];
> +		debug("bgx_vnic[%u]: %p\n", node * MAX_BGX_PER_NODE + i,
> +		      bgx);
> +		if (bgx)
> +			*bgx_count |= (1 << i);
> +	}
> +}
> +
> +/* Return number of LMAC configured for this BGX */
> +int bgx_get_lmac_count(int node, int bgx_idx)
> +{
> +	struct bgx *bgx;
> +
> +	bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
> +	if (bgx)
> +		return bgx->lmac_count;
> +
> +	return 0;
> +}
> +
> +void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable)
> +{
> +	struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
> +	u64 cfg;
> +
> +	if (!bgx)
> +		return;
> +
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
> +	if (enable)
> +		cfg |= CMR_PKT_RX_EN | CMR_PKT_TX_EN;
> +	else
> +		cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN);
> +	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
> +}
> +
> +static void bgx_flush_dmac_addrs(struct bgx *bgx, u64 lmac)
> +{
> +	u64 dmac = 0x00;
> +	u64 offset, addr;
> +
> +	while (bgx->lmac[lmac].dmac > 0) {
> +		offset = ((bgx->lmac[lmac].dmac - 1) * sizeof(dmac)) +
> +			(lmac * MAX_DMAC_PER_LMAC * sizeof(dmac));
> +		addr = (uintptr_t)bgx->reg_base +
> +				BGX_CMR_RX_DMACX_CAM + offset;
> +		writeq(dmac, (void *)addr);
> +		bgx->lmac[lmac].dmac--;
> +	}
> +}
> +
> +/* Configure BGX LMAC in internal loopback mode */
> +void bgx_lmac_internal_loopback(int node, int bgx_idx,
> +				int lmac_idx, bool enable)
> +{
> +	struct bgx *bgx;
> +	struct lmac *lmac;
> +	u64    cfg;
> +
> +	bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
> +	if (!bgx)
> +		return;
> +
> +	lmac = &bgx->lmac[lmac_idx];
> +	if (lmac->qlm_mode == QLM_MODE_SGMII) {
> +		cfg = bgx_reg_read(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL);
> +		if (enable)
> +			cfg |= PCS_MRX_CTL_LOOPBACK1;
> +		else
> +			cfg &= ~PCS_MRX_CTL_LOOPBACK1;
> +		bgx_reg_write(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL, cfg);
> +	} else {
> +		cfg = bgx_reg_read(bgx, lmac_idx, BGX_SPUX_CONTROL1);
> +		if (enable)
> +			cfg |= SPU_CTL_LOOPBACK;
> +		else
> +			cfg &= ~SPU_CTL_LOOPBACK;
> +		bgx_reg_write(bgx, lmac_idx, BGX_SPUX_CONTROL1, cfg);
> +	}
> +}
> +
> +/* Return the DLM used for the BGX */
> +static int get_qlm_for_bgx(int node, int bgx_id, int index)
> +{
> +	int qlm = 0;
> +	u64 cfg;
> +
> +	if (otx_is_soc(CN81XX)) {
> +		qlm = (bgx_id) ? 2 : 0;
> +		qlm += (index >= 2) ? 1 : 0;
> +	} else if (otx_is_soc(CN83XX)) {
> +		switch (bgx_id) {
> +		case 0:
> +			qlm = 2;
> +			break;
> +		case 1:
> +			qlm = 3;
> +			break;
> +		case 2:
> +			if (index >= 2)
> +				qlm = 6;
> +			else
> +				qlm = 5;
> +			break;
> +		case 3:
> +			qlm = 4;
> +			break;
> +		}
> +	}
> +
> +	cfg = readq(GSERX_CFG(qlm)) & GSERX_CFG_BGX;
> +	debug("%s:qlm%d: cfg = %lld\n", __func__, qlm, cfg);
> +
> +	/* Check if DLM is configured as BGX# */
> +	if (cfg) {
> +		if (readq(GSERX_PHY_CTL(qlm)))
> +			return -1;
> +		return qlm;
> +	}
> +	return -1;
> +}
> +
> +static int bgx_lmac_sgmii_init(struct bgx *bgx, int lmacid)
> +{
> +	u64 cfg;
> +	struct lmac *lmac;
> +
> +	lmac = &bgx->lmac[lmacid];
> +
> +	debug("%s:bgx_id = %d, lmacid = %d\n", __func__, bgx->bgx_id, lmacid);
> +
> +	bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_THRESH, 0x30);
> +	/* max packet size */
> +	bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_RXX_JABBER, MAX_FRAME_SIZE);
> +
> +	/* Disable frame alignment if using preamble */
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND);
> +	if (cfg & 1)
> +		bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SGMII_CTL, 0);
> +
> +	/* Enable lmac */
> +	bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
> +
> +	/* PCS reset */
> +	bgx_reg_modify(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, PCS_MRX_CTL_RESET);
> +	if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_CTL,
> +			 PCS_MRX_CTL_RESET, true)) {
> +		printf("BGX PCS reset not completed\n");
> +		return -1;
> +	}
> +
> +	/* power down, reset autoneg, autoneg enable */
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL);
> +	cfg &= ~PCS_MRX_CTL_PWR_DN;
> +
> +	if (bgx_board_info[bgx->bgx_id].phy_info[lmacid].autoneg_dis)
> +		cfg |= (PCS_MRX_CTL_RST_AN);
> +	else
> +		cfg |= (PCS_MRX_CTL_RST_AN | PCS_MRX_CTL_AN_EN);
> +	bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg);
> +
> +	/* Disable disparity for QSGMII mode, to prevent propogation across
> +	 * ports.
> +	 */
> +
> +	if (lmac->qlm_mode == QLM_MODE_QSGMII) {
> +		cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL);
> +		cfg &= ~PCS_MISCX_CTL_DISP_EN;
> +		bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL, cfg);
> +		return 0; /* Skip checking AN_CPT */
> +	}
> +
> +	if (lmac->is_1gx) {
> +		cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL);
> +		cfg |= PCS_MISC_CTL_MODE;
> +		bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL, cfg);
> +	}
> +
> +	if (lmac->qlm_mode == QLM_MODE_SGMII) {
> +		if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS,
> +				 PCS_MRX_STATUS_AN_CPT, false)) {
> +			printf("BGX AN_CPT not completed\n");
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int bgx_lmac_sgmii_set_link_speed(struct lmac *lmac)
> +{
> +	u64 prtx_cfg;
> +	u64 pcs_miscx_ctl;
> +	u64 cfg;
> +	struct bgx *bgx = lmac->bgx;
> +	unsigned int lmacid = lmac->lmacid;
> +
> +	debug("%s: lmacid %d\n", __func__, lmac->lmacid);
> +
> +	/* Disable LMAC before setting up speed */
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
> +	cfg &= ~CMR_EN;
> +	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
> +
> +	/* Read GMX CFG */
> +	prtx_cfg = bgx_reg_read(bgx, lmacid,
> +				BGX_GMP_GMI_PRTX_CFG);
> +	/* Read PCS MISCS CTL */
> +	pcs_miscx_ctl = bgx_reg_read(bgx, lmacid,
> +				     BGX_GMP_PCS_MISCX_CTL);
> +
> +	/* Use GMXENO to force the link down*/
> +	if (lmac->link_up) {
> +		pcs_miscx_ctl &= ~PCS_MISC_CTL_GMX_ENO;
> +		/* change the duplex setting if the link is up */
> +		prtx_cfg |= GMI_PORT_CFG_DUPLEX;
> +	} else {
> +		pcs_miscx_ctl |= PCS_MISC_CTL_GMX_ENO;
> +	}
> +
> +	/* speed based setting for GMX */
> +	switch (lmac->last_speed) {
> +	case 10:
> +		prtx_cfg &= ~GMI_PORT_CFG_SPEED;
> +		prtx_cfg |= GMI_PORT_CFG_SPEED_MSB;
> +		prtx_cfg &= ~GMI_PORT_CFG_SLOT_TIME;
> +		pcs_miscx_ctl |= 50; /* sampling point */
> +		bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SLOT, 0x40);
> +		bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_BURST, 0);
> +		break;
> +	case 100:
> +		prtx_cfg &= ~GMI_PORT_CFG_SPEED;
> +		prtx_cfg &= ~GMI_PORT_CFG_SPEED_MSB;
> +		prtx_cfg &= ~GMI_PORT_CFG_SLOT_TIME;
> +		pcs_miscx_ctl |= 0x5; /* sampling point */
> +		bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SLOT, 0x40);
> +		bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_BURST, 0);
> +		break;
> +	case 1000:
> +		prtx_cfg |= GMI_PORT_CFG_SPEED;
> +		prtx_cfg &= ~GMI_PORT_CFG_SPEED_MSB;
> +		prtx_cfg |= GMI_PORT_CFG_SLOT_TIME;
> +		pcs_miscx_ctl |= 0x1; /* sampling point */
> +		bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SLOT, 0x200);
> +		if (lmac->last_duplex)
> +			bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_BURST, 0);
> +		else /* half duplex */
> +			bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_BURST,
> +				      0x2000);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	/* write back the new PCS misc and GMX settings */
> +	bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MISCX_CTL, pcs_miscx_ctl);
> +	bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_PRTX_CFG, prtx_cfg);
> +
> +	/* read back GMX CFG again to check config completion */
> +	bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_PRTX_CFG);
> +
> +	/* enable BGX back */
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
> +	cfg |= CMR_EN;
> +	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
> +
> +	return 0;
> +}
> +
> +static int bgx_lmac_xaui_init(struct bgx *bgx, int lmacid, int lmac_type)
> +{
> +	u64 cfg;
> +	struct lmac *lmac;
> +
> +	lmac = &bgx->lmac[lmacid];
> +
> +	/* Reset SPU */
> +	bgx_reg_modify(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET);
> +	if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET, true)) {
> +		printf("BGX SPU reset not completed\n");
> +		return -1;
> +	}
> +
> +	/* Disable LMAC */
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
> +	cfg &= ~CMR_EN;
> +	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
> +
> +	bgx_reg_modify(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_LOW_POWER);
> +	/* Set interleaved running disparity for RXAUI */
> +	if (lmac->qlm_mode != QLM_MODE_RXAUI)
> +		bgx_reg_modify(bgx, lmacid,
> +			       BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
> +	else
> +		bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL,
> +			       SPU_MISC_CTL_RX_DIS | SPU_MISC_CTL_INTLV_RDISP);
> +
> +	/* clear all interrupts */
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_RX_INT);
> +	bgx_reg_write(bgx, lmacid, BGX_SMUX_RX_INT, cfg);
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_INT);
> +	bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_INT, cfg);
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
> +	bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
> +
> +	if (lmac->use_training) {
> +		bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LP_CUP, 0x00);
> +		bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LD_CUP, 0x00);
> +		bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LD_REP, 0x00);
> +		/* training enable */
> +		bgx_reg_modify(bgx, lmacid,
> +			       BGX_SPUX_BR_PMD_CRTL, SPU_PMD_CRTL_TRAIN_EN);
> +	}
> +
> +	/* Append FCS to each packet */
> +	bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_APPEND, SMU_TX_APPEND_FCS_D);
> +
> +	/* Disable forward error correction */
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_FEC_CONTROL);
> +	cfg &= ~SPU_FEC_CTL_FEC_EN;
> +	bgx_reg_write(bgx, lmacid, BGX_SPUX_FEC_CONTROL, cfg);
> +
> +	/* Disable autoneg */
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_CONTROL);
> +	cfg = cfg & ~(SPU_AN_CTL_XNP_EN);
> +	if (lmac->use_training)
> +		cfg = cfg | (SPU_AN_CTL_AN_EN);
> +	else
> +		cfg = cfg & ~(SPU_AN_CTL_AN_EN);
> +	bgx_reg_write(bgx, lmacid, BGX_SPUX_AN_CONTROL, cfg);
> +
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_ADV);
> +	/* Clear all KR bits, configure according to the mode */
> +	cfg &= ~((0xfULL << 22) | (1ULL << 12));
> +	if (lmac->qlm_mode == QLM_MODE_10G_KR)
> +		cfg |= (1 << 23);
> +	else if (lmac->qlm_mode == QLM_MODE_40G_KR4)
> +		cfg |= (1 << 24);
> +	bgx_reg_write(bgx, lmacid, BGX_SPUX_AN_ADV, cfg);
> +
> +	cfg = bgx_reg_read(bgx, 0, BGX_SPU_DBG_CONTROL);
> +	if (lmac->use_training)
> +		cfg |= SPU_DBG_CTL_AN_ARB_LINK_CHK_EN;
> +	else
> +		cfg &= ~SPU_DBG_CTL_AN_ARB_LINK_CHK_EN;
> +	bgx_reg_write(bgx, 0, BGX_SPU_DBG_CONTROL, cfg);
> +
> +	/* Enable lmac */
> +	bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
> +
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_CONTROL1);
> +	cfg &= ~SPU_CTL_LOW_POWER;
> +	bgx_reg_write(bgx, lmacid, BGX_SPUX_CONTROL1, cfg);
> +
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_CTL);
> +	cfg &= ~SMU_TX_CTL_UNI_EN;
> +	cfg |= SMU_TX_CTL_DIC_EN;
> +	bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_CTL, cfg);
> +
> +	/* take lmac_count into account */
> +	bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_THRESH, (0x100 - 1));
> +	/* max packet size */
> +	bgx_reg_modify(bgx, lmacid, BGX_SMUX_RX_JABBER, MAX_FRAME_SIZE);
> +
> +	debug("xaui_init: lmacid = %d, qlm = %d, qlm_mode = %d\n",
> +	      lmacid, lmac->qlm, lmac->qlm_mode);
> +	/* RXAUI with Marvell PHY requires some tweaking */
> +	if (lmac->qlm_mode == QLM_MODE_RXAUI) {
> +		char mii_name[20];
> +		struct phy_info *phy;
> +
> +		phy = &bgx_board_info[bgx->bgx_id].phy_info[lmacid];
> +		snprintf(mii_name, sizeof(mii_name), "smi%d", phy->mdio_bus);
> +
> +		debug("mii_name: %s\n", mii_name);
> +		lmac->mii_bus = miiphy_get_dev_by_name(mii_name);
> +		lmac->phy_addr = phy->phy_addr;
> +		rxaui_phy_xs_init(lmac->mii_bus, lmac->phy_addr);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Get max number of lanes present in a given QLM/DLM */
> +static int get_qlm_lanes(int qlm)
> +{
> +	if (otx_is_soc(CN81XX))
> +		return 2;
> +	else if (otx_is_soc(CN83XX))
> +		return (qlm >= 5) ? 2 : 4;
> +	else
> +		return -1;
> +}
> +
> +int __rx_equalization(int qlm, int lane)
> +{
> +	int max_lanes = get_qlm_lanes(qlm);
> +	int l;
> +	int fail = 0;
> +
> +	/* Before completing Rx equalization wait for
> +	 * GSERx_RX_EIE_DETSTS[CDRLOCK] to be set
> +	 * This ensures the rx data is valid
> +	 */
> +	if (lane == -1) {
> +		if (gser_poll_reg(GSER_RX_EIE_DETSTS(qlm), GSER_CDRLOCK, 0xf,
> +				  (1 << max_lanes) - 1, 100)) {
> +			debug("ERROR: CDR Lock not detected");
> +			debug(" on DLM%d for 2 lanes\n", qlm);
> +			return -1;
> +		}
> +	} else {
> +		if (gser_poll_reg(GSER_RX_EIE_DETSTS(qlm), GSER_CDRLOCK,
> +				  (0xf & (1 << lane)), (1 << lane), 100)) {
> +			debug("ERROR: DLM%d: CDR Lock not detected", qlm);
> +			debug(" on %d lane\n", lane);
> +			return -1;
> +		}
> +	}
> +
> +	for (l = 0; l < max_lanes; l++) {
> +		u64 rctl, reer;
> +
> +		if (lane != -1 && lane != l)
> +			continue;
> +
> +		/* Enable software control */
> +		rctl = readq(GSER_BR_RXX_CTL(qlm, l));
> +		rctl |= GSER_BR_RXX_CTL_RXT_SWM;
> +		writeq(rctl, GSER_BR_RXX_CTL(qlm, l));
> +
> +		/* Clear the completion flag and initiate a new request */
> +		reer = readq(GSER_BR_RXX_EER(qlm, l));
> +		reer &= ~GSER_BR_RXX_EER_RXT_ESV;
> +		reer |= GSER_BR_RXX_EER_RXT_EER;
> +		writeq(reer, GSER_BR_RXX_EER(qlm, l));
> +	}
> +
> +	/* Wait for RX equalization to complete */
> +	for (l = 0; l < max_lanes; l++) {
> +		u64 rctl, reer;
> +
> +		if (lane != -1 && lane != l)
> +			continue;
> +
> +		gser_poll_reg(GSER_BR_RXX_EER(qlm, l), EER_RXT_ESV, 1, 1, 200);
> +		reer = readq(GSER_BR_RXX_EER(qlm, l));
> +
> +		/* Switch back to hardware control */
> +		rctl = readq(GSER_BR_RXX_CTL(qlm, l));
> +		rctl &= ~GSER_BR_RXX_CTL_RXT_SWM;
> +		writeq(rctl, GSER_BR_RXX_CTL(qlm, l));
> +
> +		if (reer & GSER_BR_RXX_EER_RXT_ESV) {
> +			debug("Rx equalization completed on DLM%d", qlm);
> +			debug(" QLM%d rxt_esm = 0x%llx\n", l, (reer & 0x3fff));
> +		} else {
> +			debug("Rx equalization timedout on DLM%d", qlm);
> +			debug(" lane %d\n", l);
> +			fail = 1;
> +		}
> +	}
> +
> +	return (fail) ? -1 : 0;
> +}
> +
> +static int bgx_xaui_check_link(struct lmac *lmac)
> +{
> +	struct bgx *bgx = lmac->bgx;
> +	int lmacid = lmac->lmacid;
> +	int lmac_type = lmac->lmac_type;
> +	u64 cfg;
> +
> +	bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
> +
> +	/* check if auto negotiation is complete */
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_CONTROL);
> +	if (cfg & SPU_AN_CTL_AN_EN) {
> +		cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_STATUS);
> +		if (!(cfg & SPU_AN_STS_AN_COMPLETE)) {
> +			/* Restart autonegotiation */
> +			debug("restarting auto-neg\n");
> +			bgx_reg_modify(bgx, lmacid, BGX_SPUX_AN_CONTROL,
> +				       SPU_AN_CTL_AN_RESTART);
> +			return -1;
> +		}
> +	}
> +
> +	debug("%s link use_training %d\n", __func__, lmac->use_training);
> +	if (lmac->use_training) {
> +		cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
> +		if (!(cfg & (1ull << 13))) {
> +			debug("waiting for link training\n");
> +			/* Clear the training interrupts (W1C) */
> +			cfg = (1ull << 13) | (1ull << 14);
> +			bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
> +
> +			udelay(2000);
> +			/* Restart training */
> +			cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL);
> +			cfg |= (1ull << 0);
> +			bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL, cfg);
> +			return -1;
> +		}
> +	}
> +
> +	/* Perform RX Equalization. Applies to non-KR interfaces for speeds
> +	 * >= 6.25Gbps.
> +	 */
> +	if (!lmac->use_training) {
> +		int qlm;
> +		bool use_dlm = 0;
> +
> +		if (otx_is_soc(CN81XX) || (otx_is_soc(CN83XX) &&
> +					   bgx->bgx_id == 2))
> +			use_dlm = 1;
> +		switch (lmac->lmac_type) {
> +		default:
> +		case BGX_MODE_SGMII:
> +		case BGX_MODE_RGMII:
> +		case BGX_MODE_XAUI:
> +			/* Nothing to do */
> +			break;
> +		case BGX_MODE_XLAUI:
> +			if (use_dlm) {
> +				if (__rx_equalization(lmac->qlm, -1) ||
> +				    __rx_equalization(lmac->qlm + 1, -1)) {
> +					printf("BGX%d:%d", bgx->bgx_id, lmacid);
> +					printf(" Waiting for RX Equalization");
> +					printf(" on DLM%d/DLM%d\n",
> +					       lmac->qlm, lmac->qlm + 1);
> +					return -1;
> +				}
> +			} else {
> +				if (__rx_equalization(lmac->qlm, -1)) {
> +					printf("BGX%d:%d", bgx->bgx_id, lmacid);
> +					printf(" Waiting for RX Equalization");
> +					printf(" on QLM%d\n", lmac->qlm);
> +					return -1;
> +				}
> +			}
> +			break;
> +		case BGX_MODE_RXAUI:
> +			/* RXAUI0 uses LMAC0:QLM0/QLM2 and RXAUI1 uses
> +			 * LMAC1:QLM1/QLM3 RXAUI requires 2 lanes
> +			 * for each interface
> +			 */
> +			qlm = lmac->qlm;
> +			if (__rx_equalization(qlm, 0)) {
> +				printf("BGX%d:%d", bgx->bgx_id, lmacid);
> +				printf(" Waiting for RX Equalization");
> +				printf(" on QLM%d, Lane0\n", qlm);
> +				return -1;
> +			}
> +			if (__rx_equalization(qlm, 1)) {
> +				printf("BGX%d:%d", bgx->bgx_id, lmacid);
> +				printf(" Waiting for RX Equalization");
> +				printf(" on QLM%d, Lane1\n", qlm);
> +				return -1;
> +			}
> +			break;
> +		case BGX_MODE_XFI:
> +			{
> +				int lid;
> +				bool altpkg = otx_is_altpkg();
> +
> +				if (bgx->bgx_id == 0 && altpkg && lmacid)
> +					lid = 0;
> +				else if ((lmacid >= 2) && use_dlm)
> +					lid = lmacid - 2;
> +				else
> +					lid = lmacid;
> +
> +				if (__rx_equalization(lmac->qlm, lid)) {
> +					printf("BGX%d:%d", bgx->bgx_id, lid);
> +					printf(" Waiting for RX Equalization");
> +					printf(" on QLM%d\n", lmac->qlm);
> +				}
> +			}
> +			break;
> +		}
> +	}
> +
> +	/* wait for PCS to come out of reset */
> +	if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET, true)) {
> +		printf("BGX SPU reset not completed\n");
> +		return -1;
> +	}
> +
> +	if (lmac_type == 3 || lmac_type == 4) {
> +		if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_BR_STATUS1,
> +				 SPU_BR_STATUS_BLK_LOCK, false)) {
> +			printf("SPU_BR_STATUS_BLK_LOCK not completed\n");
> +			return -1;
> +		}
> +	} else {
> +		if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_BX_STATUS,
> +				 SPU_BX_STATUS_RX_ALIGN, false)) {
> +			printf("SPU_BX_STATUS_RX_ALIGN not completed\n");
> +			return -1;
> +		}
> +	}
> +
> +	/* Clear rcvflt bit (latching high) and read it back */
> +	bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS2, SPU_STATUS2_RCVFLT);
> +	if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
> +		printf("Receive fault, retry training\n");
> +		if (lmac->use_training) {
> +			cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
> +			if (!(cfg & (1ull << 13))) {
> +				cfg = (1ull << 13) | (1ull << 14);
> +				bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
> +				cfg = bgx_reg_read(bgx, lmacid,
> +						   BGX_SPUX_BR_PMD_CRTL);
> +				cfg |= (1ull << 0);
> +				bgx_reg_write(bgx, lmacid,
> +					      BGX_SPUX_BR_PMD_CRTL, cfg);
> +				return -1;
> +			}
> +		}
> +		return -1;
> +	}
> +
> +	/* Wait for MAC RX to be ready */
> +	if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_RX_CTL,
> +			 SMU_RX_CTL_STATUS, true)) {
> +		printf("SMU RX link not okay\n");
> +		return -1;
> +	}
> +
> +	/* Wait for BGX RX to be idle */
> +	if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL, SMU_CTL_RX_IDLE, false)) {
> +		printf("SMU RX not idle\n");
> +		return -1;
> +	}
> +
> +	/* Wait for BGX TX to be idle */
> +	if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL, SMU_CTL_TX_IDLE, false)) {
> +		printf("SMU TX not idle\n");
> +		return -1;
> +	}
> +
> +	if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
> +		printf("Receive fault\n");
> +		return -1;
> +	}
> +
> +	/* Receive link is latching low. Force it high and verify it */
> +	if (!(bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS1) &
> +	    SPU_STATUS1_RCV_LNK))
> +		bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS1,
> +			       SPU_STATUS1_RCV_LNK);
> +	if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_STATUS1,
> +			 SPU_STATUS1_RCV_LNK, false)) {
> +		printf("SPU receive link down\n");
> +		return -1;
> +	}
> +
> +	cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_MISC_CONTROL);
> +	cfg &= ~SPU_MISC_CTL_RX_DIS;
> +	bgx_reg_write(bgx, lmacid, BGX_SPUX_MISC_CONTROL, cfg);
> +	return 0;
> +}
> +
> +static int bgx_lmac_enable(struct bgx *bgx, int8_t lmacid)
> +{
> +	struct lmac *lmac;
> +	u64 cfg;
> +
> +	lmac = &bgx->lmac[lmacid];
> +
> +	debug("%s: lmac: %p, lmacid = %d\n", __func__, lmac, lmacid);
> +
> +	if (lmac->qlm_mode == QLM_MODE_SGMII ||
> +	    lmac->qlm_mode == QLM_MODE_RGMII ||
> +	    lmac->qlm_mode == QLM_MODE_QSGMII) {
> +		if (bgx_lmac_sgmii_init(bgx, lmacid)) {
> +			debug("bgx_lmac_sgmii_init failed\n");
> +			return -1;
> +		}
> +		cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND);
> +		cfg |= ((1ull << 2) | (1ull << 1)); /* FCS and PAD */
> +		bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND, cfg);
> +		bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_MIN_PKT, 60 - 1);
> +	} else {
> +		if (bgx_lmac_xaui_init(bgx, lmacid, lmac->lmac_type))
> +			return -1;
> +		cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_APPEND);
> +		cfg |= ((1ull << 2) | (1ull << 1)); /* FCS and PAD */
> +		bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_APPEND, cfg);
> +		bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_MIN_PKT, 60 + 4);
> +	}
> +
> +	/* Enable lmac */
> +	bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG,
> +		       CMR_EN | CMR_PKT_RX_EN | CMR_PKT_TX_EN);
> +
> +	return 0;
> +}
> +
> +int bgx_poll_for_link(int node, int bgx_idx, int lmacid)
> +{
> +	int ret;
> +	struct lmac *lmac = bgx_get_lmac(node, bgx_idx, lmacid);
> +	char mii_name[10];
> +	struct phy_info *phy;
> +
> +	if (!lmac) {
> +		printf("LMAC %d/%d/%d is disabled or doesn't exist\n",
> +		       node, bgx_idx, lmacid);
> +		return 0;
> +	}
> +
> +	debug("%s: %d, lmac: %d/%d/%d %p\n",
> +	      __FILE__, __LINE__,
> +	      node, bgx_idx, lmacid, lmac);
> +	if (lmac->init_pend) {
> +		ret = bgx_lmac_enable(lmac->bgx, lmacid);
> +		if (ret < 0) {
> +			printf("BGX%d LMAC%d lmac_enable failed\n", bgx_idx,
> +			       lmacid);
> +			return ret;
> +		}
> +		lmac->init_pend = 0;
> +		mdelay(100);
> +	}
> +	if (lmac->qlm_mode == QLM_MODE_SGMII ||
> +	    lmac->qlm_mode == QLM_MODE_RGMII ||
> +	    lmac->qlm_mode == QLM_MODE_QSGMII) {
> +		if (bgx_board_info[bgx_idx].phy_info[lmacid].phy_addr == -1) {
> +			lmac->link_up = 1;
> +			lmac->last_speed = 1000;
> +			lmac->last_duplex = 1;
> +			printf("BGX%d:LMAC %u link up\n", bgx_idx, lmacid);
> +			return lmac->link_up;
> +		}
> +		snprintf(mii_name, sizeof(mii_name), "smi%d",
> +			 bgx_board_info[bgx_idx].phy_info[lmacid].mdio_bus);
> +
> +		debug("mii_name: %s\n", mii_name);
> +
> +		lmac->mii_bus = miiphy_get_dev_by_name(mii_name);
> +		phy = &bgx_board_info[bgx_idx].phy_info[lmacid];
> +		lmac->phy_addr = phy->phy_addr;
> +
> +		debug("lmac->mii_bus: %p\n", lmac->mii_bus);
> +		if (!lmac->mii_bus) {
> +			printf("MDIO device %s not found\n", mii_name);
> +			ret = -ENODEV;
> +			return ret;
> +		}
> +
> +		lmac->phydev = phy_connect(lmac->mii_bus, lmac->phy_addr,
> +					   lmac->dev,
> +					   if_mode[lmac->qlm_mode]);
> +
> +		if (!lmac->phydev) {
> +			printf("%s: No PHY device\n", __func__);
> +			return -1;
> +		}
> +
> +		ret = phy_config(lmac->phydev);
> +		if (ret) {
> +			printf("%s: Could not initialize PHY %s\n",
> +			       __func__, lmac->phydev->dev->name);
> +			return ret;
> +		}
> +
> +		ret = phy_startup(lmac->phydev);
> +		debug("%s: %d\n", __FILE__, __LINE__);
> +		if (ret) {
> +			printf("%s: Could not initialize PHY %s\n",
> +			       __func__, lmac->phydev->dev->name);
> +		}
> +
> +#ifdef OCTEONTX_XCV
> +		if (lmac->qlm_mode == QLM_MODE_RGMII)
> +			xcv_setup_link(lmac->phydev->link, lmac->phydev->speed);
> +#endif
> +
> +		lmac->link_up = lmac->phydev->link;
> +		lmac->last_speed = lmac->phydev->speed;
> +		lmac->last_duplex = lmac->phydev->duplex;
> +
> +		debug("%s qlm_mode %d phy link status 0x%x,last speed 0x%x,",
> +		      __func__, lmac->qlm_mode, lmac->link_up,
> +		      lmac->last_speed);
> +		debug(" duplex 0x%x\n", lmac->last_duplex);
> +
> +		if (lmac->qlm_mode != QLM_MODE_RGMII)
> +			bgx_lmac_sgmii_set_link_speed(lmac);
> +
> +	} else {
> +		u64 status1;
> +		u64 tx_ctl;
> +		u64 rx_ctl;
> +
> +		status1 = bgx_reg_read(lmac->bgx, lmac->lmacid,
> +				       BGX_SPUX_STATUS1);
> +		tx_ctl = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SMUX_TX_CTL);
> +		rx_ctl = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SMUX_RX_CTL);
> +
> +		debug("BGX%d LMAC%d BGX_SPUX_STATUS2: %lx\n", bgx_idx, lmacid,
> +		      (unsigned long)bgx_reg_read(lmac->bgx, lmac->lmacid,
> +						  BGX_SPUX_STATUS2));
> +		debug("BGX%d LMAC%d BGX_SPUX_STATUS1: %lx\n", bgx_idx, lmacid,
> +		      (unsigned long)bgx_reg_read(lmac->bgx, lmac->lmacid,
> +						  BGX_SPUX_STATUS1));
> +		debug("BGX%d LMAC%d BGX_SMUX_RX_CTL: %lx\n", bgx_idx, lmacid,
> +		      (unsigned long)bgx_reg_read(lmac->bgx, lmac->lmacid,
> +						  BGX_SMUX_RX_CTL));
> +		debug("BGX%d LMAC%d BGX_SMUX_TX_CTL: %lx\n", bgx_idx, lmacid,
> +		      (unsigned long)bgx_reg_read(lmac->bgx, lmac->lmacid,
> +						  BGX_SMUX_TX_CTL));
> +
> +		if ((status1 & SPU_STATUS1_RCV_LNK) &&
> +		    ((tx_ctl & SMU_TX_CTL_LNK_STATUS) == 0) &&
> +		    ((rx_ctl & SMU_RX_CTL_STATUS) == 0)) {
> +			lmac->link_up = 1;
> +			if (lmac->lmac_type == 4)
> +				lmac->last_speed = 40000;
> +			else
> +				lmac->last_speed = 10000;
> +			lmac->last_duplex = 1;
> +		} else {
> +			lmac->link_up = 0;
> +			lmac->last_speed = 0;
> +			lmac->last_duplex = 0;
> +			return bgx_xaui_check_link(lmac);
> +		}
> +
> +		lmac->last_link = lmac->link_up;
> +	}
> +
> +	printf("BGX%d:LMAC %u link %s\n", bgx_idx, lmacid,
> +	       (lmac->link_up) ? "up" : "down");
> +
> +	return lmac->link_up;
> +}
> +
> +void bgx_lmac_disable(struct bgx *bgx, uint8_t lmacid)
> +{
> +	struct lmac *lmac;
> +	u64 cmrx_cfg;
> +
> +	lmac = &bgx->lmac[lmacid];
> +
> +	cmrx_cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
> +	cmrx_cfg &= ~(1 << 15);
> +	bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cmrx_cfg);
> +	bgx_flush_dmac_addrs(bgx, lmacid);
> +
> +	if (lmac->phydev)
> +		phy_shutdown(lmac->phydev);
> +
> +	lmac->phydev = NULL;
> +}
> +
> +/* Program BGXX_CMRX_CONFIG.{lmac_type,lane_to_sds} for each interface.
> + * And the number of LMACs used by this interface. Each lmac can be in
> + * programmed in a different mode, so parse each lmac one at a time.
> + */
> +static void bgx_init_hw(struct bgx *bgx)
> +{
> +	struct lmac *lmac;
> +	int i, lmacid, count = 0, inc = 0;
> +	char buf[40];
> +	static int qsgmii_configured;
> +
> +	for (lmacid = 0; lmacid < MAX_LMAC_PER_BGX; lmacid++) {
> +		struct lmac *tlmac;
> +
> +		lmac = &bgx->lmac[lmacid];
> +		debug("%s: lmacid = %d, qlm = %d, mode = %d\n",
> +		      __func__, lmacid, lmac->qlm, lmac->qlm_mode);
> +		/* If QLM is not programmed, skip */
> +		if (lmac->qlm == -1)
> +			continue;
> +
> +		switch (lmac->qlm_mode) {
> +		case QLM_MODE_SGMII:
> +		{
> +			/* EBB8000 (alternative pkg) has only lane0 present on
> +			 * DLM0 and DLM1, skip configuring other lanes
> +			 */
> +			if (bgx->bgx_id == 0 && otx_is_altpkg()) {
> +				if (lmacid % 2)
> +					continue;
> +			}
> +			lmac->lane_to_sds = lmacid;
> +			lmac->lmac_type = 0;
> +			snprintf(buf, sizeof(buf),
> +				 "BGX%d QLM%d LMAC%d mode: %s\n",
> +				 bgx->bgx_id, lmac->qlm, lmacid,
> +				 lmac->is_1gx ? "1000Base-X" : "SGMII");
> +			break;
> +		}
> +		case QLM_MODE_XAUI:
> +			if (lmacid != 0)
> +				continue;
> +			lmac->lmac_type = 1;
> +			lmac->lane_to_sds = 0xE4;
> +			snprintf(buf, sizeof(buf),
> +				 "BGX%d QLM%d LMAC%d mode: XAUI\n",
> +				 bgx->bgx_id, lmac->qlm, lmacid);
> +			break;
> +		case QLM_MODE_RXAUI:
> +			if (lmacid == 0) {
> +				lmac->lmac_type = 2;
> +				lmac->lane_to_sds = 0x4;
> +			} else if (lmacid == 1) {
> +				struct lmac *tlmac;
> +
> +				tlmac = &bgx->lmac[2];
> +				if (tlmac->qlm_mode == QLM_MODE_RXAUI) {
> +					lmac->lmac_type = 2;
> +					lmac->lane_to_sds = 0xe;
> +					lmac->qlm = tlmac->qlm;
> +				}
> +			} else {
> +				continue;
> +			}
> +			snprintf(buf, sizeof(buf),
> +				 "BGX%d QLM%d LMAC%d mode: RXAUI\n",
> +				 bgx->bgx_id, lmac->qlm, lmacid);
> +			break;
> +		case QLM_MODE_XFI:
> +			/* EBB8000 (alternative pkg) has only lane0 present on
> +			 * DLM0 and DLM1, skip configuring other lanes
> +			 */
> +			if (bgx->bgx_id == 0 && otx_is_altpkg()) {
> +				if (lmacid % 2)
> +					continue;
> +			}
> +			lmac->lane_to_sds = lmacid;
> +			lmac->lmac_type = 3;
> +			snprintf(buf, sizeof(buf),
> +				 "BGX%d QLM%d LMAC%d mode: XFI\n",
> +				 bgx->bgx_id, lmac->qlm, lmacid);
> +			break;
> +		case QLM_MODE_XLAUI:
> +			if (lmacid != 0)
> +				continue;
> +			lmac->lmac_type = 4;
> +			lmac->lane_to_sds = 0xE4;
> +			snprintf(buf, sizeof(buf),
> +				 "BGX%d QLM%d LMAC%d mode: XLAUI\n",
> +				 bgx->bgx_id, lmac->qlm, lmacid);
> +			break;
> +		case QLM_MODE_10G_KR:
> +			/* EBB8000 (alternative pkg) has only lane0 present on
> +			 * DLM0 and DLM1, skip configuring other lanes
> +			 */
> +			if (bgx->bgx_id == 0 && otx_is_altpkg()) {
> +				if (lmacid % 2)
> +					continue;
> +			}
> +			lmac->lane_to_sds = lmacid;
> +			lmac->lmac_type = 3;
> +			lmac->use_training = 1;
> +			snprintf(buf, sizeof(buf),
> +				 "BGX%d QLM%d LMAC%d mode: 10G-KR\n",
> +				 bgx->bgx_id, lmac->qlm, lmacid);
> +			break;
> +		case QLM_MODE_40G_KR4:
> +			if (lmacid != 0)
> +				continue;
> +			lmac->lmac_type = 4;
> +			lmac->lane_to_sds = 0xE4;
> +			lmac->use_training = 1;
> +			snprintf(buf, sizeof(buf),
> +				 "BGX%d QLM%d LMAC%d mode: 40G-KR4\n",
> +				 bgx->bgx_id, lmac->qlm, lmacid);
> +			break;
> +		case QLM_MODE_RGMII:
> +			if (lmacid != 0)
> +				continue;
> +			lmac->lmac_type = 5;
> +			lmac->lane_to_sds = 0xE4;
> +			snprintf(buf, sizeof(buf),
> +				 "BGX%d LMAC%d mode: RGMII\n",
> +				 bgx->bgx_id, lmacid);
> +			break;
> +		case QLM_MODE_QSGMII:
> +			if (qsgmii_configured)
> +				continue;
> +			if (lmacid == 0 || lmacid == 2) {
> +				count = 4;
> +				printf("BGX%d QLM%d LMAC%d mode: QSGMII\n",
> +				       bgx->bgx_id, lmac->qlm, lmacid);
> +				for (i = 0; i < count; i++) {
> +					struct lmac *l;
> +					int type;
> +
> +					l = &bgx->lmac[i];
> +					l->lmac_type = 6;
> +					type = l->lmac_type;
> +					l->qlm_mode = QLM_MODE_QSGMII;
> +					l->lane_to_sds = lmacid + i;
> +					if (is_bgx_port_valid(bgx->bgx_id, i))
> +						bgx_reg_write(bgx, i,
> +							      BGX_CMRX_CFG,
> +							      (type << 8) |
> +							      l->lane_to_sds);
> +				}
> +				qsgmii_configured = 1;
> +			}
> +			continue;
> +		default:
> +			continue;
> +		}
> +
> +		/* Reset lmac to the unused slot */
> +		if (is_bgx_port_valid(bgx->bgx_id, count) &&
> +		    lmac->qlm_mode != QLM_MODE_QSGMII) {
> +			int lmac_en = 0;
> +			int tmp, idx;
> +
> +			tlmac = &bgx->lmac[count];
> +			tlmac->lmac_type = lmac->lmac_type;
> +			idx = bgx->bgx_id;
> +			tmp = count + inc;
> +			/* Adjust lane_to_sds based on BGX-ENABLE */
> +			for (; tmp < MAX_LMAC_PER_BGX; inc++) {
> +				lmac_en = bgx_board_info[idx].lmac_enable[tmp];
> +				if (lmac_en)
> +					break;
> +				tmp = count + inc;
> +			}
> +
> +			if (inc != 0 && inc < MAX_LMAC_PER_BGX &&
> +			    lmac_en && inc != count)
> +				tlmac->lane_to_sds =
> +					lmac->lane_to_sds + abs(inc - count);
> +			else
> +				tlmac->lane_to_sds = lmac->lane_to_sds;
> +			tlmac->qlm = lmac->qlm;
> +			tlmac->qlm_mode = lmac->qlm_mode;
> +
> +			printf("%s", buf);
> +			/* Initialize lmac_type and lane_to_sds */
> +			bgx_reg_write(bgx, count, BGX_CMRX_CFG,
> +				      (tlmac->lmac_type << 8) |
> +				      tlmac->lane_to_sds);
> +
> +			if (tlmac->lmac_type == BGX_MODE_SGMII) {
> +				if (tlmac->is_1gx) {
> +					/* This is actually 1000BASE-X, so
> +					 * mark the LMAC as such.
> +					 */
> +					bgx_reg_modify(bgx, count,
> +						       BGX_GMP_PCS_MISCX_CTL,
> +						       PCS_MISC_CTL_MODE);
> +				}
> +
> +				if (!bgx_board_info[bgx->bgx_id].phy_info[lmacid].autoneg_dis) {
> +					/* The Linux DTS does not disable
> +					 * autoneg for this LMAC (in SGMII or
> +					 * 1000BASE-X mode), so that means
> +					 * enable autoneg.
> +					 */
> +					bgx_reg_modify(bgx, count,
> +						       BGX_GMP_PCS_MRX_CTL,
> +						       PCS_MRX_CTL_AN_EN);
> +				}
> +			}
> +
> +			count += 1;
> +		}
> +	}
> +
> +	/* Done probing all 4 lmacs, now clear qsgmii_configured */
> +	qsgmii_configured = 0;
> +
> +	printf("BGX%d LMACs: %d\n", bgx->bgx_id, count);
> +	bgx->lmac_count = count;
> +	bgx_reg_write(bgx, 0, BGX_CMR_RX_LMACS, count);
> +	bgx_reg_write(bgx, 0, BGX_CMR_TX_LMACS, count);
> +
> +	bgx_reg_modify(bgx, 0, BGX_CMR_GLOBAL_CFG, CMR_GLOBAL_CFG_FCS_STRIP);
> +	if (bgx_reg_read(bgx, 0, BGX_CMR_BIST_STATUS))
> +		printf("BGX%d BIST failed\n", bgx->bgx_id);
> +
> +	/* Set the backpressure AND mask */
> +	for (i = 0; i < bgx->lmac_count; i++)
> +		bgx_reg_modify(bgx, 0, BGX_CMR_CHAN_MSK_AND,
> +			       ((1ULL << MAX_BGX_CHANS_PER_LMAC) - 1) <<
> +				(i * MAX_BGX_CHANS_PER_LMAC));
> +
> +	/* Disable all MAC filtering */
> +	for (i = 0; i < RX_DMAC_COUNT; i++)
> +		bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM + (i * 8), 0x00);
> +
> +	/* Disable MAC steering (NCSI traffic) */
> +	for (i = 0; i < RX_TRAFFIC_STEER_RULE_COUNT; i++)
> +		bgx_reg_write(bgx, 0, BGX_CMR_RX_STREERING + (i * 8), 0x00);
> +}
> +
> +static void bgx_get_qlm_mode(struct bgx *bgx)
> +{
> +	struct lmac *lmac;
> +	int lmacid;
> +
> +	/* Read LMACx type to figure out QLM mode
> +	 * This is configured by low level firmware
> +	 */
> +	for (lmacid = 0; lmacid < MAX_LMAC_PER_BGX; lmacid++) {
> +		int lmac_type;
> +		int train_en;
> +		int index = 0;
> +
> +		if (otx_is_soc(CN81XX) || (otx_is_soc(CN83XX) &&
> +					   bgx->bgx_id == 2))
> +			index = (lmacid < 2) ? 0 : 2;
> +
> +		lmac = &bgx->lmac[lmacid];
> +
> +		/* check if QLM is programmed, if not, skip */
> +		if (lmac->qlm == -1)
> +			continue;
> +
> +		lmac_type = bgx_reg_read(bgx, index, BGX_CMRX_CFG);
> +		lmac->lmac_type = (lmac_type >> 8) & 0x07;
> +		debug("%s:%d:%d: lmac_type = %d, altpkg = %d\n", __func__,
> +		      bgx->bgx_id, lmacid, lmac->lmac_type, otx_is_altpkg());
> +
> +		train_en = (readq(GSERX_SCRATCH(lmac->qlm))) & 0xf;
> +		lmac->is_1gx = bgx_reg_read(bgx, index, BGX_GMP_PCS_MISCX_CTL)
> +				& (PCS_MISC_CTL_MODE) ? true : false;
> +
> +		switch (lmac->lmac_type) {
> +		case BGX_MODE_SGMII:
> +			if (bgx->is_rgx) {
> +				if (lmacid == 0) {
> +					lmac->qlm_mode = QLM_MODE_RGMII;
> +					debug("BGX%d LMAC%d mode: RGMII\n",
> +					      bgx->bgx_id, lmacid);
> +				}
> +				continue;
> +			} else {
> +				if (bgx->bgx_id == 0 && otx_is_altpkg()) {
> +					if (lmacid % 2)
> +						continue;
> +				}
> +				lmac->qlm_mode = QLM_MODE_SGMII;
> +				debug("BGX%d QLM%d LMAC%d mode: %s\n",
> +				      bgx->bgx_id, lmac->qlm, lmacid,
> +				      lmac->is_1gx ? "1000Base-X" : "SGMII");
> +			}
> +			break;
> +		case BGX_MODE_XAUI:
> +			if (bgx->bgx_id == 0 && otx_is_altpkg())
> +				continue;
> +			lmac->qlm_mode = QLM_MODE_XAUI;
> +			if (lmacid != 0)
> +				continue;
> +			debug("BGX%d QLM%d LMAC%d mode: XAUI\n",
> +			      bgx->bgx_id, lmac->qlm, lmacid);
> +			break;
> +		case BGX_MODE_RXAUI:
> +			if (bgx->bgx_id == 0 && otx_is_altpkg())
> +				continue;
> +			lmac->qlm_mode = QLM_MODE_RXAUI;
> +			if (index == lmacid) {
> +				debug("BGX%d QLM%d LMAC%d mode: RXAUI\n",
> +				      bgx->bgx_id, lmac->qlm, (index ? 1 : 0));
> +			}
> +			break;
> +		case BGX_MODE_XFI:
> +			if (bgx->bgx_id == 0 && otx_is_altpkg()) {
> +				if (lmacid % 2)
> +					continue;
> +			}
> +			if ((lmacid < 2 && (train_en & (1 << lmacid))) ||
> +			    (train_en & (1 << (lmacid - 2)))) {
> +				lmac->qlm_mode = QLM_MODE_10G_KR;
> +				debug("BGX%d QLM%d LMAC%d mode: 10G_KR\n",
> +				      bgx->bgx_id, lmac->qlm, lmacid);
> +			} else {
> +				lmac->qlm_mode = QLM_MODE_XFI;
> +				debug("BGX%d QLM%d LMAC%d mode: XFI\n",
> +				      bgx->bgx_id, lmac->qlm, lmacid);
> +			}
> +			break;
> +		case BGX_MODE_XLAUI:
> +			if (bgx->bgx_id == 0 && otx_is_altpkg())
> +				continue;
> +			if (train_en) {
> +				lmac->qlm_mode = QLM_MODE_40G_KR4;
> +				if (lmacid != 0)
> +					break;
> +				debug("BGX%d QLM%d LMAC%d mode: 40G_KR4\n",
> +				      bgx->bgx_id, lmac->qlm, lmacid);
> +			} else {
> +				lmac->qlm_mode = QLM_MODE_XLAUI;
> +				if (lmacid != 0)
> +					break;
> +				debug("BGX%d QLM%d LMAC%d mode: XLAUI\n",
> +				      bgx->bgx_id, lmac->qlm, lmacid);
> +			}
> +		break;
> +		case BGX_MODE_QSGMII:
> +			/* If QLM is configured as QSGMII, use lmac0 */
> +			if (otx_is_soc(CN83XX) && lmacid == 2 &&
> +			    bgx->bgx_id != 2) {
> +				//lmac->qlm_mode = QLM_MODE_DISABLED;
> +				continue;
> +			}
> +
> +			if (lmacid == 0 || lmacid == 2) {
> +				lmac->qlm_mode = QLM_MODE_QSGMII;
> +				debug("BGX%d QLM%d LMAC%d mode: QSGMII\n",
> +				      bgx->bgx_id, lmac->qlm, lmacid);
> +			}
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +}
> +
> +void bgx_set_board_info(int bgx_id, int *mdio_bus,
> +			int *phy_addr, bool *autoneg_dis, bool *lmac_reg,
> +			bool *lmac_enable)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < MAX_LMAC_PER_BGX; i++) {
> +		bgx_board_info[bgx_id].phy_info[i].phy_addr = phy_addr[i];
> +		bgx_board_info[bgx_id].phy_info[i].mdio_bus = mdio_bus[i];
> +		bgx_board_info[bgx_id].phy_info[i].autoneg_dis = autoneg_dis[i];
> +		bgx_board_info[bgx_id].lmac_reg[i] = lmac_reg[i];
> +		bgx_board_info[bgx_id].lmac_enable[i] = lmac_enable[i];
> +		debug("%s bgx_id %d lmac %d\n", __func__, bgx_id, i);
> +		debug("phy addr %x mdio bus %d autoneg_dis %d lmac_reg %d\n",
> +		      bgx_board_info[bgx_id].phy_info[i].phy_addr,
> +		      bgx_board_info[bgx_id].phy_info[i].mdio_bus,
> +		      bgx_board_info[bgx_id].phy_info[i].autoneg_dis,
> +		      bgx_board_info[bgx_id].lmac_reg[i]);
> +		debug("lmac_enable = %x\n",
> +		      bgx_board_info[bgx_id].lmac_enable[i]);
> +	}
> +}
> +
> +int octeontx_bgx_remove(struct udevice *dev)
> +{
> +	int lmacid;
> +	u64 cfg;
> +	int count = MAX_LMAC_PER_BGX;
> +	struct bgx *bgx = dev_get_priv(dev);
> +
> +	if (!bgx->reg_base)
> +		return 0;
> +
> +	if (bgx->is_rgx)
> +		count = 1;
> +
> +	for (lmacid = 0; lmacid < count; lmacid++) {
> +		struct lmac *lmac;
> +
> +		lmac = &bgx->lmac[lmacid];
> +		cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
> +		cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN);
> +		bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
> +
> +		/* Disable PCS for 1G interface */
> +		if (lmac->lmac_type == BGX_MODE_SGMII ||
> +		    lmac->lmac_type == BGX_MODE_QSGMII) {
> +			cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL);
> +			cfg |= PCS_MRX_CTL_PWR_DN;
> +			bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg);
> +		}
> +
> +		debug("%s disabling bgx%d lmacid%d\n", __func__, bgx->bgx_id,
> +		      lmacid);
> +		bgx_lmac_disable(bgx, lmacid);
> +	}
> +	return 0;
> +}
> +
> +int octeontx_bgx_probe(struct udevice *dev)
> +{
> +	struct bgx *bgx = dev_get_priv(dev);
> +	u8 lmac = 0;
> +	int qlm[4] = {-1, -1, -1, -1};
> +	int bgx_idx, node;
> +	int inc = 1;
> +
> +	bgx->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
> +				       PCI_REGION_MEM);
> +	if (!bgx->reg_base) {
> +		debug("No PCI region found\n");
> +		return 0;
> +	}
> +
> +#ifdef OCTEONTX_XCV
> +	/* Use FAKE BGX2 for RGX interface */
> +	if ((((uintptr_t)bgx->reg_base >> 24) & 0xf) == 0x8) {
> +		bgx->bgx_id = 2;
> +		bgx->is_rgx = true;
> +		for (lmac = 0; lmac < MAX_LMAC_PER_BGX; lmac++) {
> +			if (lmac == 0) {
> +				bgx->lmac[lmac].lmacid = 0;
> +				bgx->lmac[lmac].qlm = 0;
> +			} else {
> +				bgx->lmac[lmac].qlm = -1;
> +			}
> +		}
> +		xcv_init_hw();
> +		goto skip_qlm_config;
> +	}
> +#endif
> +
> +	node = node_id(bgx->reg_base);
> +	bgx_idx = ((uintptr_t)bgx->reg_base >> 24) & 3;
> +	bgx->bgx_id = (node * MAX_BGX_PER_NODE) + bgx_idx;
> +	if (otx_is_soc(CN81XX))
> +		inc = 2;
> +	else if (otx_is_soc(CN83XX) && (bgx_idx == 2))
> +		inc = 2;
> +
> +	for (lmac = 0; lmac < MAX_LMAC_PER_BGX; lmac += inc) {
> +		/* BGX3 (DLM4), has only 2 lanes */
> +		if (otx_is_soc(CN83XX) && bgx_idx == 3 && lmac >= 2)
> +			continue;
> +		qlm[lmac + 0] = get_qlm_for_bgx(node, bgx_idx, lmac);
> +		/* Each DLM has 2 lanes, configure both lanes with
> +		 * same qlm configuration
> +		 */
> +		if (inc == 2)
> +			qlm[lmac + 1] = qlm[lmac];
> +		debug("qlm[%d] = %d\n", lmac, qlm[lmac]);
> +	}
> +
> +	/* A BGX can take 1 or 2 DLMs, if both the DLMs are not configured
> +	 * as BGX, then return, nothing to initialize
> +	 */
> +	if (otx_is_soc(CN81XX))
> +		if ((qlm[0] == -1) && (qlm[2] == -1))
> +			return -ENODEV;
> +
> +	/* MAP configuration registers */
> +	for (lmac = 0; lmac < MAX_LMAC_PER_BGX; lmac++) {
> +		bgx->lmac[lmac].qlm = qlm[lmac];
> +		bgx->lmac[lmac].lmacid = lmac;
> +	}
> +
> +#ifdef OCTEONTX_XCV
> +skip_qlm_config:
> +#endif
> +	bgx_vnic[bgx->bgx_id] = bgx;
> +	bgx_get_qlm_mode(bgx);
> +	debug("bgx_vnic[%u]: %p\n", bgx->bgx_id, bgx);
> +
> +	bgx_init_hw(bgx);
> +
> +	/* Init LMACs */
> +	for (lmac = 0; lmac < bgx->lmac_count; lmac++) {
> +		struct lmac *tlmac = &bgx->lmac[lmac];
> +
> +		tlmac->dev = dev;
> +		tlmac->init_pend = 1;
> +		tlmac->bgx = bgx;
> +	}
> +
> +	return 0;
> +}
> +
> +U_BOOT_DRIVER(octeontx_bgx) = {
> +	.name	= "octeontx_bgx",
> +	.id	= UCLASS_MISC,
> +	.probe	= octeontx_bgx_probe,
> +	.remove	= octeontx_bgx_remove,
> +	.priv_auto_alloc_size = sizeof(struct bgx),
> +	.flags  = DM_FLAG_OS_PREPARE,
> +};
> +
> +static struct pci_device_id octeontx_bgx_supported[] = {
> +	{ PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_BGX) },
> +	{ PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_RGX) },
> +	{}
> +};
> +
> +U_BOOT_PCI_DEVICE(octeontx_bgx, octeontx_bgx_supported);
> diff --git a/drivers/net/octeontx/bgx.h b/drivers/net/octeontx/bgx.h
> new file mode 100644
> index 0000000000..8402630bf5
> --- /dev/null
> +++ b/drivers/net/octeontx/bgx.h
> @@ -0,0 +1,259 @@
> +/* SPDX-License-Identifier:    GPL-2.0
> + *
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#ifndef BGX_H
> +#define BGX_H
> +
> +#include <asm/arch/board.h>
> +
> +/* PCI device IDs */
> +#define	PCI_DEVICE_ID_OCTEONTX_BGX	0xA026
> +#define	PCI_DEVICE_ID_OCTEONTX_RGX	0xA054
> +
> +#define    MAX_LMAC_PER_BGX			4
> +#define    MAX_BGX_CHANS_PER_LMAC		16
> +#define    MAX_DMAC_PER_LMAC			8
> +#define    MAX_FRAME_SIZE			9216
> +
> +#define    MAX_DMAC_PER_LMAC_TNS_BYPASS_MODE	2
> +
> +#define    MAX_LMAC	(MAX_BGX_PER_NODE * MAX_LMAC_PER_BGX)
> +
> +#define    NODE_ID_MASK				0x300000000000
> +#define    NODE_ID(x)				(((x) & NODE_ID_MASK) >> 44)
> +
> +/* Registers */
> +#define GSERX_CFG(x)		(0x87E090000080ull + (x) * 0x1000000ull)
> +#define GSERX_SCRATCH(x)	(0x87E090000020ull + (x) * 0x1000000ull)
> +#define GSERX_PHY_CTL(x)	(0x87E090000000ull + (x) * 0x1000000ull)
> +#define GSERX_CFG_BGX		BIT(2)
> +#define GSER_RX_EIE_DETSTS(x)	(0x87E090000150ull + (x) * 0x1000000ull)
> +#define GSER_CDRLOCK		(8)
> +#define GSER_BR_RXX_CTL(x, y)	(0x87E090000400ull + (x) * 0x1000000ull + \
> +				(y) * 0x80)
> +#define GSER_BR_RXX_CTL_RXT_SWM	BIT(2)
> +#define GSER_BR_RXX_EER(x, y)	(0x87E090000418ull + (x) * 0x1000000ull + \
> +				(y) * 0x80)
> +#define GSER_BR_RXX_EER_RXT_ESV BIT(14)
> +#define GSER_BR_RXX_EER_RXT_EER BIT(15)
> +#define EER_RXT_ESV		(14)
> +
> +#define BGX_CMRX_CFG			0x00
> +#define CMR_PKT_TX_EN				BIT_ULL(13)
> +#define CMR_PKT_RX_EN				BIT_ULL(14)
> +#define CMR_EN					BIT_ULL(15)
> +#define BGX_CMR_GLOBAL_CFG		0x08
> +#define CMR_GLOBAL_CFG_FCS_STRIP		BIT_ULL(6)
> +#define BGX_CMRX_RX_ID_MAP		0x60
> +#define BGX_CMRX_RX_STAT0		0x70
> +#define BGX_CMRX_RX_STAT1		0x78
> +#define BGX_CMRX_RX_STAT2		0x80
> +#define BGX_CMRX_RX_STAT3		0x88
> +#define BGX_CMRX_RX_STAT4		0x90
> +#define BGX_CMRX_RX_STAT5		0x98
> +#define BGX_CMRX_RX_STAT6		0xA0
> +#define BGX_CMRX_RX_STAT7		0xA8
> +#define BGX_CMRX_RX_STAT8		0xB0
> +#define BGX_CMRX_RX_STAT9		0xB8
> +#define BGX_CMRX_RX_STAT10		0xC0
> +#define BGX_CMRX_RX_BP_DROP		0xC8
> +#define BGX_CMRX_RX_DMAC_CTL		0x0E8
> +#define BGX_CMR_RX_DMACX_CAM		0x200
> +#define RX_DMACX_CAM_EN				BIT_ULL(48)
> +#define RX_DMACX_CAM_LMACID(x)			((x) << 49)
> +#define RX_DMAC_COUNT			32
> +#define BGX_CMR_RX_STREERING		0x300
> +#define RX_TRAFFIC_STEER_RULE_COUNT	8
> +#define BGX_CMR_CHAN_MSK_AND		0x450
> +#define BGX_CMR_BIST_STATUS		0x460
> +#define BGX_CMR_RX_LMACS		0x468
> +#define BGX_CMRX_TX_STAT0		0x600
> +#define BGX_CMRX_TX_STAT1		0x608
> +#define BGX_CMRX_TX_STAT2		0x610
> +#define BGX_CMRX_TX_STAT3		0x618
> +#define BGX_CMRX_TX_STAT4		0x620
> +#define BGX_CMRX_TX_STAT5		0x628
> +#define BGX_CMRX_TX_STAT6		0x630
> +#define BGX_CMRX_TX_STAT7		0x638
> +#define BGX_CMRX_TX_STAT8		0x640
> +#define BGX_CMRX_TX_STAT9		0x648
> +#define BGX_CMRX_TX_STAT10		0x650
> +#define BGX_CMRX_TX_STAT11		0x658
> +#define BGX_CMRX_TX_STAT12		0x660
> +#define BGX_CMRX_TX_STAT13		0x668
> +#define BGX_CMRX_TX_STAT14		0x670
> +#define BGX_CMRX_TX_STAT15		0x678
> +#define BGX_CMRX_TX_STAT16		0x680
> +#define BGX_CMRX_TX_STAT17		0x688
> +#define BGX_CMR_TX_LMACS		0x1000
> +
> +#define BGX_SPUX_CONTROL1		0x10000
> +#define SPU_CTL_LOW_POWER			BIT_ULL(11)
> +#define SPU_CTL_LOOPBACK                        BIT_ULL(14)
> +#define SPU_CTL_RESET				BIT_ULL(15)
> +#define BGX_SPUX_STATUS1		0x10008
> +#define SPU_STATUS1_RCV_LNK			BIT_ULL(2)
> +#define BGX_SPUX_STATUS2		0x10020
> +#define SPU_STATUS2_RCVFLT			BIT_ULL(10)
> +#define BGX_SPUX_BX_STATUS		0x10028
> +#define SPU_BX_STATUS_RX_ALIGN                  BIT_ULL(12)
> +#define BGX_SPUX_BR_STATUS1		0x10030
> +#define SPU_BR_STATUS_BLK_LOCK			BIT_ULL(0)
> +#define SPU_BR_STATUS_RCV_LNK			BIT_ULL(12)
> +#define BGX_SPUX_BR_PMD_CRTL		0x10068
> +#define SPU_PMD_CRTL_TRAIN_EN			BIT_ULL(1)
> +#define BGX_SPUX_BR_PMD_LP_CUP		0x10078
> +#define BGX_SPUX_BR_PMD_LD_CUP		0x10088
> +#define BGX_SPUX_BR_PMD_LD_REP		0x10090
> +#define BGX_SPUX_FEC_CONTROL		0x100A0
> +#define SPU_FEC_CTL_FEC_EN			BIT_ULL(0)
> +#define SPU_FEC_CTL_ERR_EN			BIT_ULL(1)
> +#define BGX_SPUX_AN_CONTROL		0x100C8
> +#define SPU_AN_CTL_AN_EN			BIT_ULL(12)
> +#define SPU_AN_CTL_XNP_EN			BIT_ULL(13)
> +#define SPU_AN_CTL_AN_RESTART			BIT_ULL(15)
> +#define BGX_SPUX_AN_STATUS		0x100D0
> +#define SPU_AN_STS_AN_COMPLETE			BIT_ULL(5)
> +#define BGX_SPUX_AN_ADV			0x100D8
> +#define BGX_SPUX_MISC_CONTROL		0x10218
> +#define SPU_MISC_CTL_INTLV_RDISP		BIT_ULL(10)
> +#define SPU_MISC_CTL_RX_DIS			BIT_ULL(12)
> +#define BGX_SPUX_INT			0x10220	/* +(0..3) << 20 */
> +#define BGX_SPUX_INT_W1S		0x10228
> +#define BGX_SPUX_INT_ENA_W1C		0x10230
> +#define BGX_SPUX_INT_ENA_W1S		0x10238
> +#define BGX_SPU_DBG_CONTROL		0x10300
> +#define SPU_DBG_CTL_AN_ARB_LINK_CHK_EN		BIT_ULL(18)
> +#define SPU_DBG_CTL_AN_NONCE_MCT_DIS		BIT_ULL(29)
> +
> +#define BGX_SMUX_RX_INT			0x20000
> +#define BGX_SMUX_RX_JABBER		0x20030
> +#define BGX_SMUX_RX_CTL			0x20048
> +#define SMU_RX_CTL_STATUS			(3ull << 0)
> +#define BGX_SMUX_TX_APPEND		0x20100
> +#define SMU_TX_APPEND_FCS_D			BIT_ULL(2)
> +#define BGX_SMUX_TX_MIN_PKT		0x20118
> +#define BGX_SMUX_TX_INT			0x20140
> +#define BGX_SMUX_TX_CTL			0x20178
> +#define SMU_TX_CTL_DIC_EN			BIT_ULL(0)
> +#define SMU_TX_CTL_UNI_EN			BIT_ULL(1)
> +#define SMU_TX_CTL_LNK_STATUS			(3ull << 4)
> +#define BGX_SMUX_TX_THRESH		0x20180
> +#define BGX_SMUX_CTL			0x20200
> +#define SMU_CTL_RX_IDLE				BIT_ULL(0)
> +#define SMU_CTL_TX_IDLE				BIT_ULL(1)
> +
> +#define BGX_GMP_PCS_MRX_CTL		0x30000
> +#define	PCS_MRX_CTL_RST_AN			BIT_ULL(9)
> +#define	PCS_MRX_CTL_PWR_DN			BIT_ULL(11)
> +#define	PCS_MRX_CTL_AN_EN			BIT_ULL(12)
> +#define PCS_MRX_CTL_LOOPBACK1                   BIT_ULL(14)
> +#define	PCS_MRX_CTL_RESET			BIT_ULL(15)
> +#define BGX_GMP_PCS_MRX_STATUS		0x30008
> +#define	PCS_MRX_STATUS_AN_CPT			BIT_ULL(5)
> +#define BGX_GMP_PCS_ANX_AN_RESULTS	0x30020
> +#define BGX_GMP_PCS_SGM_AN_ADV		0x30068
> +#define BGX_GMP_PCS_MISCX_CTL		0x30078
> +#define PCS_MISCX_CTL_DISP_EN			BIT_ULL(13)
> +#define PCS_MISC_CTL_GMX_ENO			BIT_ULL(11)
> +#define PCS_MISC_CTL_SAMP_PT_MASK		0x7Full
> +#define PCS_MISC_CTL_MODE			BIT_ULL(8)
> +#define BGX_GMP_GMI_PRTX_CFG		0x38020
> +#define GMI_PORT_CFG_SPEED			BIT_ULL(1)
> +#define GMI_PORT_CFG_DUPLEX			BIT_ULL(2)
> +#define GMI_PORT_CFG_SLOT_TIME			BIT_ULL(3)
> +#define GMI_PORT_CFG_SPEED_MSB			BIT_ULL(8)
> +#define BGX_GMP_GMI_RXX_JABBER		0x38038
> +#define BGX_GMP_GMI_TXX_THRESH		0x38210
> +#define BGX_GMP_GMI_TXX_APPEND		0x38218
> +#define BGX_GMP_GMI_TXX_SLOT		0x38220
> +#define BGX_GMP_GMI_TXX_BURST		0x38228
> +#define BGX_GMP_GMI_TXX_MIN_PKT		0x38240
> +#define BGX_GMP_GMI_TXX_SGMII_CTL	0x38300
> +
> +#define BGX_MSIX_VEC_0_29_ADDR		0x400000 /* +(0..29) << 4 */
> +#define BGX_MSIX_VEC_0_29_CTL		0x400008
> +#define BGX_MSIX_PBA_0			0x4F0000
> +
> +/* MSI-X interrupts */
> +#define BGX_MSIX_VECTORS	30
> +#define BGX_LMAC_VEC_OFFSET	7
> +#define BGX_MSIX_VEC_SHIFT	4
> +
> +#define CMRX_INT		0
> +#define SPUX_INT		1
> +#define SMUX_RX_INT		2
> +#define SMUX_TX_INT		3
> +#define GMPX_PCS_INT		4
> +#define GMPX_GMI_RX_INT		5
> +#define GMPX_GMI_TX_INT		6
> +#define CMR_MEM_INT		28
> +#define SPU_MEM_INT		29
> +
> +#define LMAC_INTR_LINK_UP	BIT(0)
> +#define LMAC_INTR_LINK_DOWN	BIT(1)
> +
> +/*  RX_DMAC_CTL configuration*/
> +enum MCAST_MODE {
> +		MCAST_MODE_REJECT,
> +		MCAST_MODE_ACCEPT,
> +		MCAST_MODE_CAM_FILTER,
> +		RSVD
> +};
> +
> +#define BCAST_ACCEPT	1
> +#define CAM_ACCEPT	1
> +
> +int octeontx_bgx_initialize(unsigned int bgx_idx, unsigned int node);
> +void bgx_add_dmac_addr(u64 dmac, int node, int bgx_idx, int lmac);
> +void bgx_get_count(int node, int *bgx_count);
> +int bgx_get_lmac_count(int node, int bgx);
> +void bgx_print_stats(int bgx_idx, int lmac);
> +void xcv_init_hw(void);
> +void xcv_setup_link(bool link_up, int link_speed);
> +
> +#undef LINK_INTR_ENABLE
> +
> +enum qlm_mode {
> +	QLM_MODE_SGMII,         /* SGMII, each lane independent */
> +	QLM_MODE_XAUI,      /* 1 XAUI or DXAUI, 4 lanes */
> +	QLM_MODE_RXAUI,     /* 2 RXAUI, 2 lanes each */
> +	QLM_MODE_XFI,       /* 4 XFI, 1 lane each */
> +	QLM_MODE_XLAUI,     /* 1 XLAUI, 4 lanes each */
> +	QLM_MODE_10G_KR,    /* 4 10GBASE-KR, 1 lane each */
> +	QLM_MODE_40G_KR4,   /* 1 40GBASE-KR4, 4 lanes each */
> +	QLM_MODE_QSGMII,    /* 4 QSGMII, each lane independent */
> +	QLM_MODE_RGMII,     /* 1 RGX */
> +};
> +
> +struct phy_info {
> +	int mdio_bus;
> +	int phy_addr;
> +	bool autoneg_dis;
> +};
> +
> +struct bgx_board_info {
> +	struct phy_info phy_info[MAX_LMAC_PER_BGX];
> +	bool lmac_reg[MAX_LMAC_PER_BGX];
> +	bool lmac_enable[MAX_LMAC_PER_BGX];
> +};
> +
> +enum LMAC_TYPE {
> +	BGX_MODE_SGMII = 0, /* 1 lane, 1.250 Gbaud */
> +	BGX_MODE_XAUI = 1,  /* 4 lanes, 3.125 Gbaud */
> +	BGX_MODE_DXAUI = 1, /* 4 lanes, 6.250 Gbaud */
> +	BGX_MODE_RXAUI = 2, /* 2 lanes, 6.250 Gbaud */
> +	BGX_MODE_XFI = 3,   /* 1 lane, 10.3125 Gbaud */
> +	BGX_MODE_XLAUI = 4, /* 4 lanes, 10.3125 Gbaud */
> +	BGX_MODE_10G_KR = 3,/* 1 lane, 10.3125 Gbaud */
> +	BGX_MODE_40G_KR = 4,/* 4 lanes, 10.3125 Gbaud */
> +	BGX_MODE_RGMII = 5,
> +	BGX_MODE_QSGMII = 6,
> +	BGX_MODE_INVALID = 7,
> +};
> +
> +int rxaui_phy_xs_init(struct mii_dev *bus, int phy_addr);
> +
> +#endif /* BGX_H */
> diff --git a/drivers/net/octeontx/nic.h b/drivers/net/octeontx/nic.h
> new file mode 100644
> index 0000000000..af3576cfbb
> --- /dev/null
> +++ b/drivers/net/octeontx/nic.h
> @@ -0,0 +1,508 @@
> +/* SPDX-License-Identifier:    GPL-2.0
> + *
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#ifndef NIC_H
> +#define	NIC_H
> +
> +#include <linux/netdevice.h>
> +#include "bgx.h"
> +
> +#define	PCI_DEVICE_ID_CAVIUM_NICVF_1	0x0011
> +
> +/* Subsystem device IDs */
> +#define PCI_SUBSYS_DEVID_88XX_NIC_PF		0xA11E
> +#define PCI_SUBSYS_DEVID_81XX_NIC_PF		0xA21E
> +#define PCI_SUBSYS_DEVID_83XX_NIC_PF		0xA31E
> +
> +#define PCI_SUBSYS_DEVID_88XX_PASS1_NIC_VF	0xA11E
> +#define PCI_SUBSYS_DEVID_88XX_NIC_VF		0xA134
> +#define PCI_SUBSYS_DEVID_81XX_NIC_VF		0xA234
> +#define PCI_SUBSYS_DEVID_83XX_NIC_VF		0xA334
> +
> +#define	NIC_INTF_COUNT			2  /* Interfaces btw VNIC and TNS/BGX */
> +#define	NIC_CHANS_PER_INF		128
> +#define	NIC_MAX_CHANS			(NIC_INTF_COUNT * NIC_CHANS_PER_INF)
> +
> +/* PCI BAR nos */
> +#define	PCI_CFG_REG_BAR_NUM		0
> +#define	PCI_MSIX_REG_BAR_NUM		4
> +
> +/* NIC SRIOV VF count */
> +#define	MAX_NUM_VFS_SUPPORTED		128
> +#define	DEFAULT_NUM_VF_ENABLED		8
> +
> +#define	NIC_TNS_BYPASS_MODE		0
> +#define	NIC_TNS_MODE			1
> +
> +/* NIC priv flags */
> +#define	NIC_SRIOV_ENABLED		BIT(0)
> +#define	NIC_TNS_ENABLED			BIT(1)
> +
> +/* VNIC HW optimiation features */
> +#define	VNIC_RX_CSUM_OFFLOAD_SUPPORT
> +#undef	VNIC_TX_CSUM_OFFLOAD_SUPPORT
> +#undef	VNIC_SG_SUPPORT
> +#undef	VNIC_TSO_SUPPORT
> +#undef	VNIC_LRO_SUPPORT
> +#undef  VNIC_RSS_SUPPORT
> +
> +/* TSO not supported in Thunder pass1 */
> +#ifdef	VNIC_TSO_SUPPORT
> +#define	VNIC_SW_TSO_SUPPORT
> +#undef	VNIC_HW_TSO_SUPPORT
> +#endif
> +
> +/* ETHTOOL enable or disable, undef this to disable */
> +#define	NICVF_ETHTOOL_ENABLE
> +
> +/* Min/Max packet size */
> +#define	NIC_HW_MIN_FRS			64
> +#define	NIC_HW_MAX_FRS			9200 /* 9216 max packet including FCS */
> +
> +/* Max pkinds */
> +#define	NIC_MAX_PKIND			16
> +
> +/* Max when CPI_ALG is IP diffserv */
> +#define	NIC_MAX_CPI_PER_LMAC		64
> +
> +/* NIC VF Interrupts */
> +#define	NICVF_INTR_CQ			0
> +#define	NICVF_INTR_SQ			1
> +#define	NICVF_INTR_RBDR			2
> +#define	NICVF_INTR_PKT_DROP		3
> +#define	NICVF_INTR_TCP_TIMER	4
> +#define	NICVF_INTR_MBOX			5
> +#define	NICVF_INTR_QS_ERR		6
> +
> +#define	NICVF_INTR_CQ_SHIFT			0
> +#define	NICVF_INTR_SQ_SHIFT			8
> +#define	NICVF_INTR_RBDR_SHIFT		16
> +#define	NICVF_INTR_PKT_DROP_SHIFT	20
> +#define	NICVF_INTR_TCP_TIMER_SHIFT	21
> +#define	NICVF_INTR_MBOX_SHIFT		22
> +#define	NICVF_INTR_QS_ERR_SHIFT		23
> +
> +#define	NICVF_INTR_CQ_MASK		(0xFF << NICVF_INTR_CQ_SHIFT)
> +#define	NICVF_INTR_SQ_MASK		(0xFF << NICVF_INTR_SQ_SHIFT)
> +#define	NICVF_INTR_RBDR_MASK		(0x03 << NICVF_INTR_RBDR_SHIFT)
> +#define	NICVF_INTR_PKT_DROP_MASK	BIT(NICVF_INTR_PKT_DROP_SHIFT)
> +#define	NICVF_INTR_TCP_TIMER_MASK	BIT(NICVF_INTR_TCP_TIMER_SHIFT)
> +#define	NICVF_INTR_MBOX_MASK		BIT(NICVF_INTR_MBOX_SHIFT)
> +#define	NICVF_INTR_QS_ERR_MASK		BIT(NICVF_INTR_QS_ERR_SHIFT)
> +
> +/* MSI-X interrupts */
> +#define	NIC_PF_MSIX_VECTORS		10
> +#define	NIC_VF_MSIX_VECTORS		20
> +
> +#define NIC_PF_INTR_ID_ECC0_SBE		0
> +#define NIC_PF_INTR_ID_ECC0_DBE		1
> +#define NIC_PF_INTR_ID_ECC1_SBE		2
> +#define NIC_PF_INTR_ID_ECC1_DBE		3
> +#define NIC_PF_INTR_ID_ECC2_SBE		4
> +#define NIC_PF_INTR_ID_ECC2_DBE		5
> +#define NIC_PF_INTR_ID_ECC3_SBE		6
> +#define NIC_PF_INTR_ID_ECC3_DBE		7
> +#define NIC_PF_INTR_ID_MBOX0		8
> +#define NIC_PF_INTR_ID_MBOX1		9
> +
> +/* Global timer for CQ timer thresh interrupts
> + * Calculated for SCLK of 700Mhz
> + * value written should be a 1/16thof what is expected
> + *
> + * 1 tick per ms
> + */
> +#define NICPF_CLK_PER_INT_TICK		43750
> +
> +struct nicvf_cq_poll {
> +	u8	cq_idx;		/* Completion queue index */
> +};
> +
> +#define NIC_MAX_RSS_HASH_BITS		8
> +#define NIC_MAX_RSS_IDR_TBL_SIZE	BIT(NIC_MAX_RSS_HASH_BITS)
> +#define RSS_HASH_KEY_SIZE		5 /* 320 bit key */
> +
> +#ifdef VNIC_RSS_SUPPORT
> +struct nicvf_rss_info {
> +	bool enable;
> +#define	RSS_L2_EXTENDED_HASH_ENA	BIT(0)
> +#define	RSS_IP_HASH_ENA			BIT(1)
> +#define	RSS_TCP_HASH_ENA		BIT(2)
> +#define	RSS_TCP_SYN_DIS			BIT(3)
> +#define	RSS_UDP_HASH_ENA		BIT(4)
> +#define RSS_L4_EXTENDED_HASH_ENA	BIT(5)
> +#define	RSS_ROCE_ENA			BIT(6)
> +#define	RSS_L3_BI_DIRECTION_ENA		BIT(7)
> +#define	RSS_L4_BI_DIRECTION_ENA		BIT(8)
> +	u64 cfg;
> +	u8  hash_bits;
> +	u16 rss_size;
> +	u8  ind_tbl[NIC_MAX_RSS_IDR_TBL_SIZE];
> +	u64 key[RSS_HASH_KEY_SIZE];
> +};
> +#endif
> +
> +enum rx_stats_reg_offset {
> +	RX_OCTS = 0x0,
> +	RX_UCAST = 0x1,
> +	RX_BCAST = 0x2,
> +	RX_MCAST = 0x3,
> +	RX_RED = 0x4,
> +	RX_RED_OCTS = 0x5,
> +	RX_ORUN = 0x6,
> +	RX_ORUN_OCTS = 0x7,
> +	RX_FCS = 0x8,
> +	RX_L2ERR = 0x9,
> +	RX_DRP_BCAST = 0xa,
> +	RX_DRP_MCAST = 0xb,
> +	RX_DRP_L3BCAST = 0xc,
> +	RX_DRP_L3MCAST = 0xd,
> +	RX_STATS_ENUM_LAST,
> +};
> +
> +enum tx_stats_reg_offset {
> +	TX_OCTS = 0x0,
> +	TX_UCAST = 0x1,
> +	TX_BCAST = 0x2,
> +	TX_MCAST = 0x3,
> +	TX_DROP = 0x4,
> +	TX_STATS_ENUM_LAST,
> +};
> +
> +struct nicvf_hw_stats {
> +	u64 rx_bytes_ok;
> +	u64 rx_ucast_frames_ok;
> +	u64 rx_bcast_frames_ok;
> +	u64 rx_mcast_frames_ok;
> +	u64 rx_fcs_errors;
> +	u64 rx_l2_errors;
> +	u64 rx_drop_red;
> +	u64 rx_drop_red_bytes;
> +	u64 rx_drop_overrun;
> +	u64 rx_drop_overrun_bytes;
> +	u64 rx_drop_bcast;
> +	u64 rx_drop_mcast;
> +	u64 rx_drop_l3_bcast;
> +	u64 rx_drop_l3_mcast;
> +	u64 tx_bytes_ok;
> +	u64 tx_ucast_frames_ok;
> +	u64 tx_bcast_frames_ok;
> +	u64 tx_mcast_frames_ok;
> +	u64 tx_drops;
> +};
> +
> +struct nicvf_drv_stats {
> +	/* Rx */
> +	u64 rx_frames_ok;
> +	u64 rx_frames_64;
> +	u64 rx_frames_127;
> +	u64 rx_frames_255;
> +	u64 rx_frames_511;
> +	u64 rx_frames_1023;
> +	u64 rx_frames_1518;
> +	u64 rx_frames_jumbo;
> +	u64 rx_drops;
> +	/* Tx */
> +	u64 tx_frames_ok;
> +	u64 tx_drops;
> +	u64 tx_busy;
> +	u64 tx_tso;
> +};
> +
> +struct hw_info {
> +	u8		bgx_cnt;
> +	u8		chans_per_lmac;
> +	u8		chans_per_bgx; /* Rx/Tx chans */
> +	u8		chans_per_rgx;
> +	u8		chans_per_lbk;
> +	u16		cpi_cnt;
> +	u16		rssi_cnt;
> +	u16		rss_ind_tbl_size;
> +	u16		tl4_cnt;
> +	u16		tl3_cnt;
> +	u8		tl2_cnt;
> +	u8		tl1_cnt;
> +	bool		tl1_per_bgx; /* TL1 per BGX or per LMAC */
> +	u8		model_id;
> +};
> +
> +struct nicvf {
> +	struct udevice		*dev;
> +	u8			vf_id;
> +	bool			sqs_mode:1;
> +	bool			loopback_supported:1;
> +	u8			tns_mode;
> +	u8			node;
> +	u16		mtu;
> +	struct queue_set	*qs;
> +#define		MAX_SQS_PER_VF_SINGLE_NODE	5
> +#define		MAX_SQS_PER_VF			11
> +	u8			num_qs;
> +	void			*addnl_qs;
> +	u16		vf_mtu;
> +	void __iomem		*reg_base;
> +#define	MAX_QUEUES_PER_QSET			8
> +	struct nicvf_cq_poll	*napi[8];
> +
> +	u8			cpi_alg;
> +
> +	struct nicvf_hw_stats	stats;
> +	struct nicvf_drv_stats	drv_stats;
> +
> +	struct nicpf		*nicpf;
> +
> +	/* VF <-> PF mailbox communication */
> +	bool			pf_acked;
> +	bool			pf_nacked;
> +	bool			set_mac_pending;
> +
> +	bool			link_up;
> +	u8			duplex;
> +	u32		speed;
> +	u8			rev_id;
> +	u8			rx_queues;
> +	u8			tx_queues;
> +
> +	bool			open;
> +	bool			rb_alloc_fail;
> +	void			*rcv_buf;
> +	bool			hw_tso;
> +};
> +
> +static inline int node_id(void *addr)
> +{
> +	return ((uintptr_t)addr >> 44) & 0x3;
> +}
> +
> +struct nicpf {
> +	struct udevice		*udev;
> +	struct hw_info		*hw;
> +	u8			node;
> +	unsigned int		flags;
> +	u16			total_vf_cnt;	/* Total num of VF supported */
> +	u16			num_vf_en;	/* No of VF enabled */
> +	void __iomem		*reg_base;	/* Register start address */
> +	u16			rss_ind_tbl_size;
> +	u8			num_sqs_en;	/* Secondary qsets enabled */
> +	u64			nicvf[MAX_NUM_VFS_SUPPORTED];
> +	u8			vf_sqs[MAX_NUM_VFS_SUPPORTED][MAX_SQS_PER_VF];
> +	u8			pqs_vf[MAX_NUM_VFS_SUPPORTED];
> +	bool			sqs_used[MAX_NUM_VFS_SUPPORTED];
> +	struct pkind_cfg	pkind;
> +	u8			bgx_cnt;
> +	u8			rev_id;
> +#define	NIC_SET_VF_LMAC_MAP(bgx, lmac)	((((bgx) & 0xF) << 4) | ((lmac) & 0xF))
> +#define	NIC_GET_BGX_FROM_VF_LMAC_MAP(map)	(((map) >> 4) & 0xF)
> +#define	NIC_GET_LMAC_FROM_VF_LMAC_MAP(map)	((map) & 0xF)
> +	u8			vf_lmac_map[MAX_LMAC];
> +	u16			cpi_base[MAX_NUM_VFS_SUPPORTED];
> +	u64			mac[MAX_NUM_VFS_SUPPORTED];
> +	bool			mbx_lock[MAX_NUM_VFS_SUPPORTED];
> +	u8			link[MAX_LMAC];
> +	u8			duplex[MAX_LMAC];
> +	u32			speed[MAX_LMAC];
> +	bool			vf_enabled[MAX_NUM_VFS_SUPPORTED];
> +	u16			rssi_base[MAX_NUM_VFS_SUPPORTED];
> +	u8			lmac_cnt;
> +};
> +
> +/* PF <--> VF Mailbox communication
> + * Eight 64bit registers are shared between PF and VF.
> + * Separate set for each VF.
> + * Writing '1' into last register mbx7 means end of message.
> + */
> +
> +/* PF <--> VF mailbox communication */
> +#define	NIC_PF_VF_MAILBOX_SIZE		2
> +#define	NIC_PF_VF_MBX_TIMEOUT		2000 /* ms */
> +
> +/* Mailbox message types */
> +#define	NIC_MBOX_MSG_READY		0x01	/* Is PF ready to rcv msgs */
> +#define	NIC_MBOX_MSG_ACK		0x02	/* ACK the message received */
> +#define	NIC_MBOX_MSG_NACK		0x03	/* NACK the message received */
> +#define	NIC_MBOX_MSG_QS_CFG		0x04	/* Configure Qset */
> +#define	NIC_MBOX_MSG_RQ_CFG		0x05	/* Configure receive queue */
> +#define	NIC_MBOX_MSG_SQ_CFG		0x06	/* Configure Send queue */
> +#define	NIC_MBOX_MSG_RQ_DROP_CFG	0x07	/* Configure receive queue */
> +#define	NIC_MBOX_MSG_SET_MAC		0x08	/* Add MAC ID to DMAC filter */
> +#define	NIC_MBOX_MSG_SET_MAX_FRS	0x09	/* Set max frame size */
> +#define	NIC_MBOX_MSG_CPI_CFG		0x0A	/* Config CPI, RSSI */
> +#define	NIC_MBOX_MSG_RSS_SIZE		0x0B	/* Get RSS indir_tbl size */
> +#define	NIC_MBOX_MSG_RSS_CFG		0x0C	/* Config RSS table */
> +#define	NIC_MBOX_MSG_RSS_CFG_CONT	0x0D	/* RSS config continuation */
> +#define	NIC_MBOX_MSG_RQ_BP_CFG		0x0E	/* RQ backpressure config */
> +#define	NIC_MBOX_MSG_RQ_SW_SYNC		0x0F	/* Flush inflight pkts to RQ */
> +#define	NIC_MBOX_MSG_BGX_STATS		0x10	/* Get stats from BGX */
> +#define	NIC_MBOX_MSG_BGX_LINK_CHANGE	0x11	/* BGX:LMAC link status */
> +#define	NIC_MBOX_MSG_ALLOC_SQS		0x12	/* Allocate secondary Qset */
> +#define	NIC_MBOX_MSG_NICVF_PTR		0x13	/* Send nicvf ptr to PF */
> +#define	NIC_MBOX_MSG_PNICVF_PTR		0x14	/* Get primary qset nicvf ptr */
> +#define	NIC_MBOX_MSG_SNICVF_PTR		0x15	/* Send sqet nicvf ptr to PVF */
> +#define	NIC_MBOX_MSG_LOOPBACK		0x16	/* Set interface in loopback */
> +#define	NIC_MBOX_MSG_CFG_DONE		0xF0	/* VF configuration done */
> +#define	NIC_MBOX_MSG_SHUTDOWN		0xF1	/* VF is being shutdown */
> +
> +struct nic_cfg_msg {
> +	u8    msg;
> +	u8    vf_id;
> +	u8    node_id;
> +	bool  tns_mode:1;
> +	bool  sqs_mode:1;
> +	bool  loopback_supported:1;
> +	u8    mac_addr[6];
> +};
> +
> +/* Qset configuration */
> +struct qs_cfg_msg {
> +	u8    msg;
> +	u8    num;
> +	u8    sqs_count;
> +	u64   cfg;
> +};
> +
> +/* Receive queue configuration */
> +struct rq_cfg_msg {
> +	u8    msg;
> +	u8    qs_num;
> +	u8    rq_num;
> +	u64   cfg;
> +};
> +
> +/* Send queue configuration */
> +struct sq_cfg_msg {
> +	u8    msg;
> +	u8    qs_num;
> +	u8    sq_num;
> +	bool  sqs_mode;
> +	u64   cfg;
> +};
> +
> +/* Set VF's MAC address */
> +struct set_mac_msg {
> +	u8    msg;
> +	u8    vf_id;
> +	u8    mac_addr[6];
> +};
> +
> +/* Set Maximum frame size */
> +struct set_frs_msg {
> +	u8    msg;
> +	u8    vf_id;
> +	u16   max_frs;
> +};
> +
> +/* Set CPI algorithm type */
> +struct cpi_cfg_msg {
> +	u8    msg;
> +	u8    vf_id;
> +	u8    rq_cnt;
> +	u8    cpi_alg;
> +};
> +
> +/* Get RSS table size */
> +struct rss_sz_msg {
> +	u8    msg;
> +	u8    vf_id;
> +	u16   ind_tbl_size;
> +};
> +
> +/* Set RSS configuration */
> +struct rss_cfg_msg {
> +	u8    msg;
> +	u8    vf_id;
> +	u8    hash_bits;
> +	u8    tbl_len;
> +	u8    tbl_offset;
> +#define RSS_IND_TBL_LEN_PER_MBX_MSG	8
> +	u8    ind_tbl[RSS_IND_TBL_LEN_PER_MBX_MSG];
> +};
> +
> +struct bgx_stats_msg {
> +	u8    msg;
> +	u8    vf_id;
> +	u8    rx;
> +	u8    idx;
> +	u64   stats;
> +};
> +
> +/* Physical interface link status */
> +struct bgx_link_status {
> +	u8    msg;
> +	u8    link_up;
> +	u8    duplex;
> +	u32   speed;
> +};
> +
> +#ifdef VNIC_MULTI_QSET_SUPPORT
> +/* Get Extra Qset IDs */
> +struct sqs_alloc {
> +	u8    msg;
> +	u8    vf_id;
> +	u8    qs_count;
> +};
> +
> +struct nicvf_ptr {
> +	u8    msg;
> +	u8    vf_id;
> +	bool  sqs_mode;
> +	u8    sqs_id;
> +	u64   nicvf;
> +};
> +#endif
> +
> +/* Set interface in loopback mode */
> +struct set_loopback {
> +	u8    msg;
> +	u8    vf_id;
> +	bool  enable;
> +};
> +
> +/* 128 bit shared memory between PF and each VF */
> +union nic_mbx {
> +	struct { u8 msg; }	msg;
> +	struct nic_cfg_msg	nic_cfg;
> +	struct qs_cfg_msg	qs;
> +	struct rq_cfg_msg	rq;
> +	struct sq_cfg_msg	sq;
> +	struct set_mac_msg	mac;
> +	struct set_frs_msg	frs;
> +	struct cpi_cfg_msg	cpi_cfg;
> +	struct rss_sz_msg	rss_size;
> +	struct rss_cfg_msg	rss_cfg;
> +	struct bgx_stats_msg    bgx_stats;
> +	struct bgx_link_status  link_status;
> +#ifdef VNIC_MULTI_QSET_SUPPORT
> +	struct sqs_alloc        sqs_alloc;
> +	struct nicvf_ptr	nicvf;
> +#endif
> +	struct set_loopback	lbk;
> +};
> +
> +int nicvf_set_real_num_queues(struct udevice *dev,
> +			      int tx_queues, int rx_queues);
> +int nicvf_open(struct udevice *dev);
> +void nicvf_stop(struct udevice *dev);
> +int nicvf_send_msg_to_pf(struct nicvf *vf, union nic_mbx *mbx);
> +void nicvf_update_stats(struct nicvf *nic);
> +
> +void nic_handle_mbx_intr(struct nicpf *nic, int vf);
> +
> +int bgx_poll_for_link(int node, int bgx_idx, int lmacid);
> +const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid);
> +void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac);
> +void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable);
> +void bgx_lmac_internal_loopback(int node, int bgx_idx,
> +				int lmac_idx, bool enable);
> +
> +static inline bool pass1_silicon(unsigned int revision, int model_id)
> +{
> +	return ((revision < 8) && (model_id == 0x88));
> +}
> +
> +static inline bool pass2_silicon(unsigned int revision, int model_id)
> +{
> +	return ((revision >= 8) && (model_id == 0x88));
> +}
> +
> +#endif /* NIC_H */
> diff --git a/drivers/net/octeontx/nic_main.c b/drivers/net/octeontx/nic_main.c
> new file mode 100644
> index 0000000000..1a805f7a46
> --- /dev/null
> +++ b/drivers/net/octeontx/nic_main.c
> @@ -0,0 +1,778 @@
> +// SPDX-License-Identifier:    GPL-2.0
> +/*
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#include <config.h>
> +#include <net.h>
> +#include <netdev.h>
> +#include <malloc.h>
> +#include <miiphy.h>
> +#include <dm.h>
> +#include <misc.h>
> +#include <pci.h>
> +#include <pci_ids.h>
> +#include <asm/io.h>
> +#include <linux/delay.h>
> +
> +#include "nic_reg.h"
> +#include "nic.h"
> +#include "q_struct.h"
> +
> +unsigned long rounddown_pow_of_two(unsigned long n)
> +{
> +	n |= n >> 1;
> +	n |= n >> 2;
> +	n |= n >> 4;
> +	n |= n >> 8;
> +	n |= n >> 16;
> +	n |= n >> 32;
> +
> +	return(n + 1);
> +}
> +
> +static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg);
> +static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic,
> +			       struct sq_cfg_msg *sq);
> +static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf);
> +static int nic_rcv_queue_sw_sync(struct nicpf *nic);
> +
> +/* Register read/write APIs */
> +static void nic_reg_write(struct nicpf *nic, u64 offset, u64 val)
> +{
> +	writeq(val, nic->reg_base + offset);
> +}
> +
> +static u64 nic_reg_read(struct nicpf *nic, u64 offset)
> +{
> +	return readq(nic->reg_base + offset);
> +}
> +
> +static u64 nic_get_mbx_addr(int vf)
> +{
> +	return NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT);
> +}
> +
> +static void nic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx)
> +{
> +	void __iomem *mbx_addr = (void *)(nic->reg_base + nic_get_mbx_addr(vf));
> +	u64 *msg = (u64 *)mbx;
> +
> +	/* In first revision HW, mbox interrupt is triggerred
> +	 * when PF writes to MBOX(1), in next revisions when
> +	 * PF writes to MBOX(0)
> +	 */
> +	if (pass1_silicon(nic->rev_id, nic->hw->model_id)) {
> +		/* see the comment for nic_reg_write()/nic_reg_read()
> +		 * functions above
> +		 */
> +		writeq(msg[0], mbx_addr);
> +		writeq(msg[1], mbx_addr + 8);
> +	} else {
> +		writeq(msg[1], mbx_addr + 8);
> +		writeq(msg[0], mbx_addr);
> +	}
> +}
> +
> +static void nic_mbx_send_ready(struct nicpf *nic, int vf)
> +{
> +	union nic_mbx mbx = {};
> +	int bgx_idx, lmac, timeout = 5, link = -1;
> +	const u8 *mac;
> +
> +	mbx.nic_cfg.msg = NIC_MBOX_MSG_READY;
> +	mbx.nic_cfg.vf_id = vf;
> +
> +	if (nic->flags & NIC_TNS_ENABLED)
> +		mbx.nic_cfg.tns_mode = NIC_TNS_MODE;
> +	else
> +		mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE;
> +
> +	if (vf < nic->num_vf_en) {
> +		bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
> +		lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
> +
> +		mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac);
> +		if (mac)
> +			memcpy((u8 *)&mbx.nic_cfg.mac_addr, mac, 6);
> +
> +		while (timeout-- && (link <= 0)) {
> +			link = bgx_poll_for_link(nic->node, bgx_idx, lmac);
> +			debug("Link status: %d\n", link);
> +			if (link <= 0)
> +				mdelay(2000);
> +		}
> +	}
> +#ifdef VNIC_MULTI_QSET_SUPPORT
> +	mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false;
> +#endif
> +	mbx.nic_cfg.node_id = nic->node;
> +
> +	mbx.nic_cfg.loopback_supported = vf < nic->num_vf_en;
> +
> +	nic_send_msg_to_vf(nic, vf, &mbx);
> +}
> +
> +/* ACKs VF's mailbox message
> + * @vf: VF to which ACK to be sent
> + */
> +static void nic_mbx_send_ack(struct nicpf *nic, int vf)
> +{
> +	union nic_mbx mbx = {};
> +
> +	mbx.msg.msg = NIC_MBOX_MSG_ACK;
> +	nic_send_msg_to_vf(nic, vf, &mbx);
> +}
> +
> +/* NACKs VF's mailbox message that PF is not able to
> + * complete the action
> + * @vf: VF to which ACK to be sent
> + */
> +static void nic_mbx_send_nack(struct nicpf *nic, int vf)
> +{
> +	union nic_mbx mbx = {};
> +
> +	mbx.msg.msg = NIC_MBOX_MSG_NACK;
> +	nic_send_msg_to_vf(nic, vf, &mbx);
> +}
> +
> +static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
> +{
> +	int bgx_idx, lmac_idx;
> +
> +	if (lbk->vf_id > nic->num_vf_en)
> +		return -1;
> +
> +	bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
> +	lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
> +
> +	bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable);
> +
> +	return 0;
> +}
> +
> +/* Interrupt handler to handle mailbox messages from VFs */
> +void nic_handle_mbx_intr(struct nicpf *nic, int vf)
> +{
> +	union nic_mbx mbx = {};
> +	u64 *mbx_data;
> +	u64 mbx_addr;
> +	u64 reg_addr;
> +	u64 cfg;
> +	int bgx, lmac;
> +	int i;
> +	int ret = 0;
> +
> +	nic->mbx_lock[vf] = true;
> +
> +	mbx_addr = nic_get_mbx_addr(vf);
> +	mbx_data = (u64 *)&mbx;
> +
> +	for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
> +		*mbx_data = nic_reg_read(nic, mbx_addr);
> +		mbx_data++;
> +		mbx_addr += sizeof(u64);
> +	}
> +
> +	debug("%s: Mailbox msg %d from VF%d\n", __func__, mbx.msg.msg, vf);
> +	switch (mbx.msg.msg) {
> +	case NIC_MBOX_MSG_READY:
> +		nic_mbx_send_ready(nic, vf);
> +		if (vf < nic->num_vf_en) {
> +			nic->link[vf] = 0;
> +			nic->duplex[vf] = 0;
> +			nic->speed[vf] = 0;
> +		}
> +		ret = 1;
> +		break;
> +	case NIC_MBOX_MSG_QS_CFG:
> +		reg_addr = NIC_PF_QSET_0_127_CFG |
> +			   (mbx.qs.num << NIC_QS_ID_SHIFT);
> +		cfg = mbx.qs.cfg;
> +#ifdef VNIC_MULTI_QSET_SUPPORT
> +		/* Check if its a secondary Qset */
> +		if (vf >= nic->num_vf_en) {
> +			cfg = cfg & (~0x7FULL);
> +			/* Assign this Qset to primary Qset's VF */
> +			cfg |= nic->pqs_vf[vf];
> +		}
> +#endif
> +		nic_reg_write(nic, reg_addr, cfg);
> +		break;
> +	case NIC_MBOX_MSG_RQ_CFG:
> +		reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG |
> +			   (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
> +			   (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
> +		nic_reg_write(nic, reg_addr, mbx.rq.cfg);
> +		/* Enable CQE_RX2_S extension in CQE_RX descriptor.
> +		 * This gets appended by default on 81xx/83xx chips,
> +		 * for consistency enabling the same on 88xx pass2
> +		 * where this is introduced.
> +		 */
> +		if (pass2_silicon(nic->rev_id, nic->hw->model_id))
> +			nic_reg_write(nic, NIC_PF_RX_CFG, 0x01);
> +		break;
> +	case NIC_MBOX_MSG_RQ_BP_CFG:
> +		reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG |
> +			   (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
> +			   (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
> +		nic_reg_write(nic, reg_addr, mbx.rq.cfg);
> +		break;
> +	case NIC_MBOX_MSG_RQ_SW_SYNC:
> +		ret = nic_rcv_queue_sw_sync(nic);
> +		break;
> +	case NIC_MBOX_MSG_RQ_DROP_CFG:
> +		reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG |
> +			   (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
> +			   (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
> +		nic_reg_write(nic, reg_addr, mbx.rq.cfg);
> +		break;
> +	case NIC_MBOX_MSG_SQ_CFG:
> +		reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG |
> +			   (mbx.sq.qs_num << NIC_QS_ID_SHIFT) |
> +			   (mbx.sq.sq_num << NIC_Q_NUM_SHIFT);
> +		nic_reg_write(nic, reg_addr, mbx.sq.cfg);
> +		nic_tx_channel_cfg(nic, mbx.qs.num,
> +				   (struct sq_cfg_msg *)&mbx.sq);
> +		break;
> +	case NIC_MBOX_MSG_SET_MAC:
> +#ifdef VNIC_MULTI_QSET_SUPPORT
> +		if (vf >= nic->num_vf_en)
> +			break;
> +#endif
> +		lmac = mbx.mac.vf_id;
> +		bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
> +		lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
> +		bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr);
> +		break;
> +	case NIC_MBOX_MSG_SET_MAX_FRS:
> +		ret = nic_update_hw_frs(nic, mbx.frs.max_frs,
> +					mbx.frs.vf_id);
> +		break;
> +	case NIC_MBOX_MSG_CPI_CFG:
> +		nic_config_cpi(nic, &mbx.cpi_cfg);
> +		break;
> +#ifdef VNIC_RSS_SUPPORT
> +	case NIC_MBOX_MSG_RSS_SIZE:
> +		nic_send_rss_size(nic, vf);
> +		goto unlock;
> +	case NIC_MBOX_MSG_RSS_CFG:
> +	case NIC_MBOX_MSG_RSS_CFG_CONT:
> +		nic_config_rss(nic, &mbx.rss_cfg);
> +		break;
> +#endif
> +	case NIC_MBOX_MSG_CFG_DONE:
> +		/* Last message of VF config msg sequence */
> +		nic->vf_enabled[vf] = true;
> +		if (vf >= nic->lmac_cnt)
> +			goto unlock;
> +
> +		bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
> +		lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
> +
> +		bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, true);
> +		goto unlock;
> +	case NIC_MBOX_MSG_SHUTDOWN:
> +		/* First msg in VF teardown sequence */
> +		nic->vf_enabled[vf] = false;
> +#ifdef VNIC_MULTI_QSET_SUPPORT
> +		if (vf >= nic->num_vf_en)
> +			nic->sqs_used[vf - nic->num_vf_en] = false;
> +		nic->pqs_vf[vf] = 0;
> +#endif
> +		if (vf >= nic->lmac_cnt)
> +			break;
> +
> +		bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
> +		lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
> +
> +		bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, false);
> +		break;
> +#ifdef VNIC_MULTI_QSET_SUPPORT
> +	case NIC_MBOX_MSG_ALLOC_SQS:
> +		nic_alloc_sqs(nic, &mbx.sqs_alloc);
> +		goto unlock;
> +	case NIC_MBOX_MSG_NICVF_PTR:
> +		nic->nicvf[vf] = mbx.nicvf.nicvf;
> +		break;
> +	case NIC_MBOX_MSG_PNICVF_PTR:
> +		nic_send_pnicvf(nic, vf);
> +		goto unlock;
> +	case NIC_MBOX_MSG_SNICVF_PTR:
> +		nic_send_snicvf(nic, &mbx.nicvf);
> +		goto unlock;
> +#endif
> +	case NIC_MBOX_MSG_LOOPBACK:
> +		ret = nic_config_loopback(nic, &mbx.lbk);
> +		break;
> +	default:
> +		printf("Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
> +		break;
> +	}
> +
> +	if (!ret)
> +		nic_mbx_send_ack(nic, vf);
> +	else if (mbx.msg.msg != NIC_MBOX_MSG_READY)
> +		nic_mbx_send_nack(nic, vf);
> +unlock:
> +	nic->mbx_lock[vf] = false;
> +}
> +
> +static int nic_rcv_queue_sw_sync(struct nicpf *nic)
> +{
> +	int timeout = 20;
> +
> +	nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01);
> +	while (timeout) {
> +		if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1)
> +			break;
> +		udelay(2000);
> +		timeout--;
> +	}
> +	nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00);
> +	if (!timeout) {
> +		printf("Recevie queue software sync failed");
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf)
> +{
> +	u64 *pkind = (u64 *)&nic->pkind;
> +
> +	if (new_frs > NIC_HW_MAX_FRS || new_frs < NIC_HW_MIN_FRS) {
> +		printf("Invalid MTU setting from VF%d rejected,", vf);
> +		printf(" should be between %d and %d\n", NIC_HW_MIN_FRS,
> +		       NIC_HW_MAX_FRS);
> +		return 1;
> +	}
> +	new_frs += ETH_HLEN;
> +	if (new_frs <= nic->pkind.maxlen)
> +		return 0;
> +
> +	nic->pkind.maxlen = new_frs;
> +
> +	nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *pkind);
> +	return 0;
> +}
> +
> +/* Set minimum transmit packet size */
> +static void nic_set_tx_pkt_pad(struct nicpf *nic, int size)
> +{
> +	int lmac;
> +	u64 lmac_cfg;
> +	struct hw_info *hw = nic->hw;
> +	int max_lmac = nic->hw->bgx_cnt * MAX_LMAC_PER_BGX;
> +
> +	/* Max value that can be set is 60 */
> +	if (size > 52)
> +		size = 52;
> +
> +	/* CN81XX has RGX configured as FAKE BGX, adjust mac_lmac accordingly */
> +	if (hw->chans_per_rgx)
> +		max_lmac = ((nic->hw->bgx_cnt - 1) * MAX_LMAC_PER_BGX) + 1;
> +
> +	for (lmac = 0; lmac < max_lmac; lmac++) {
> +		lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3));
> +		lmac_cfg &= ~(0xF << 2);
> +		lmac_cfg |= ((size / 4) << 2);
> +		nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg);
> +	}
> +}
> +
> +/* Function to check number of LMACs present and set VF to LMAC mapping.
> + * Mapping will be used while initializing channels.
> + */
> +static void nic_set_lmac_vf_mapping(struct nicpf *nic)
> +{
> +	int bgx, bgx_count, next_bgx_lmac = 0;
> +	int lmac, lmac_cnt = 0;
> +	u64 lmac_credit;
> +
> +	nic->num_vf_en = 0;
> +	if (nic->flags & NIC_TNS_ENABLED) {
> +		nic->num_vf_en = DEFAULT_NUM_VF_ENABLED;
> +		return;
> +	}
> +
> +	bgx_get_count(nic->node, &bgx_count);
> +	debug("bgx_count: %d\n", bgx_count);
> +
> +	for (bgx = 0; bgx < nic->hw->bgx_cnt; bgx++) {
> +		if (!(bgx_count & (1 << bgx)))
> +			continue;
> +		nic->bgx_cnt++;
> +		lmac_cnt = bgx_get_lmac_count(nic->node, bgx);
> +		debug("lmac_cnt: %d for BGX%d\n", lmac_cnt, bgx);
> +		for (lmac = 0; lmac < lmac_cnt; lmac++)
> +			nic->vf_lmac_map[next_bgx_lmac++] =
> +						NIC_SET_VF_LMAC_MAP(bgx, lmac);
> +		nic->num_vf_en += lmac_cnt;
> +
> +		/* Program LMAC credits */
> +		lmac_credit = (1ull << 1); /* chennel credit enable */
> +		lmac_credit |= (0x1ff << 2);
> +		lmac_credit |= (((((48 * 1024) / lmac_cnt) -
> +				NIC_HW_MAX_FRS) / 16) << 12);
> +		lmac = bgx * MAX_LMAC_PER_BGX;
> +		for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++)
> +			nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8),
> +				      lmac_credit);
> +	}
> +}
> +
> +static void nic_get_hw_info(struct nicpf *nic)
> +{
> +	u16 sdevid;
> +	struct hw_info *hw = nic->hw;
> +
> +	dm_pci_read_config16(nic->udev, PCI_SUBSYSTEM_ID, &sdevid);
> +
> +	switch (sdevid) {
> +	case PCI_SUBSYS_DEVID_88XX_NIC_PF:
> +		hw->bgx_cnt = MAX_BGX_PER_NODE;
> +		hw->chans_per_lmac = 16;
> +		hw->chans_per_bgx = 128;
> +		hw->cpi_cnt = 2048;
> +		hw->rssi_cnt = 4096;
> +		hw->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
> +		hw->tl3_cnt = 256;
> +		hw->tl2_cnt = 64;
> +		hw->tl1_cnt = 2;
> +		hw->tl1_per_bgx = true;
> +		hw->model_id = 0x88;
> +		break;
> +	case PCI_SUBSYS_DEVID_81XX_NIC_PF:
> +		hw->bgx_cnt = MAX_BGX_PER_NODE;
> +		hw->chans_per_lmac = 8;
> +		hw->chans_per_bgx = 32;
> +		hw->chans_per_rgx = 8;
> +		hw->chans_per_lbk = 24;
> +		hw->cpi_cnt = 512;
> +		hw->rssi_cnt = 256;
> +		hw->rss_ind_tbl_size = 32; /* Max RSSI / Max interfaces */
> +		hw->tl3_cnt = 64;
> +		hw->tl2_cnt = 16;
> +		hw->tl1_cnt = 10;
> +		hw->tl1_per_bgx = false;
> +		hw->model_id = 0x81;
> +		break;
> +	case PCI_SUBSYS_DEVID_83XX_NIC_PF:
> +		hw->bgx_cnt = MAX_BGX_PER_NODE;
> +		hw->chans_per_lmac = 8;
> +		hw->chans_per_bgx = 32;
> +		hw->chans_per_lbk = 64;
> +		hw->cpi_cnt = 2048;
> +		hw->rssi_cnt = 1024;
> +		hw->rss_ind_tbl_size = 64; /* Max RSSI / Max interfaces */
> +		hw->tl3_cnt = 256;
> +		hw->tl2_cnt = 64;
> +		hw->tl1_cnt = 18;
> +		hw->tl1_per_bgx = false;
> +		hw->model_id = 0x83;
> +		break;
> +	}
> +
> +	hw->tl4_cnt = MAX_QUEUES_PER_QSET * pci_sriov_get_totalvfs(nic->udev);
> +}
> +
> +static void nic_init_hw(struct nicpf *nic)
> +{
> +	int i;
> +	u64 reg;
> +	u64 *pkind = (u64 *)&nic->pkind;
> +
> +	/* Get HW capability info */
> +	nic_get_hw_info(nic);
> +
> +	/* Enable NIC HW block */
> +	nic_reg_write(nic, NIC_PF_CFG, 0x3);
> +
> +	/* Enable backpressure */
> +	nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03);
> +	nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, (1ULL << 63) | 0x08);
> +	nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8),
> +		      (1ULL << 63) | 0x09);
> +
> +	for (i = 0; i < NIC_MAX_CHANS; i++)
> +		nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (i << 3), 1);
> +
> +	if (nic->flags & NIC_TNS_ENABLED) {
> +		reg = NIC_TNS_MODE << 7;
> +		reg |= 0x06;
> +		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, reg);
> +		reg &= ~0xFull;
> +		reg |= 0x07;
> +		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), reg);
> +	} else {
> +		/* Disable TNS mode on both interfaces */
> +		reg = NIC_TNS_BYPASS_MODE << 7;
> +		reg |= 0x08; /* Block identifier */
> +		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, reg);
> +		reg &= ~0xFull;
> +		reg |= 0x09;
> +		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), reg);
> +	}
> +
> +	/* PKIND configuration */
> +	nic->pkind.minlen = 0;
> +	nic->pkind.maxlen = NIC_HW_MAX_FRS + ETH_HLEN;
> +	nic->pkind.lenerr_en = 1;
> +	nic->pkind.rx_hdr = 0;
> +	nic->pkind.hdr_sl = 0;
> +
> +	for (i = 0; i < NIC_MAX_PKIND; i++)
> +		nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), *pkind);
> +
> +	nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS);
> +
> +	/* Timer config */
> +	nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK);
> +}
> +
> +/* Channel parse index configuration */
> +static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg)
> +{
> +	struct hw_info *hw = nic->hw;
> +	u32 vnic, bgx, lmac, chan;
> +	u32 padd, cpi_count = 0;
> +	u64 cpi_base, cpi, rssi_base, rssi;
> +	u8  qset, rq_idx = 0;
> +
> +	vnic = cfg->vf_id;
> +	bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
> +	lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
> +
> +	chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx);
> +	cpi_base = vnic * NIC_MAX_CPI_PER_LMAC;
> +	rssi_base = vnic * hw->rss_ind_tbl_size;
> +
> +	/* Rx channel configuration */
> +	nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3),
> +		      (1ull << 63) | (vnic << 0));
> +	nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3),
> +		      ((u64)cfg->cpi_alg << 62) | (cpi_base << 48));
> +
> +	if (cfg->cpi_alg == CPI_ALG_NONE)
> +		cpi_count = 1;
> +	else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */
> +		cpi_count = 8;
> +	else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */
> +		cpi_count = 16;
> +	else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */
> +		cpi_count = NIC_MAX_CPI_PER_LMAC;
> +
> +	/* RSS Qset, Qidx mapping */
> +	qset = cfg->vf_id;
> +	rssi = rssi_base;
> +	for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) {
> +		nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3),
> +			      (qset << 3) | rq_idx);
> +		rq_idx++;
> +	}
> +
> +	rssi = 0;
> +	cpi = cpi_base;
> +	for (; cpi < (cpi_base + cpi_count); cpi++) {
> +		/* Determine port to channel adder */
> +		if (cfg->cpi_alg != CPI_ALG_DIFF)
> +			padd = cpi % cpi_count;
> +		else
> +			padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */
> +
> +		/* Leave RSS_SIZE as '0' to disable RSS */
> +		if (pass1_silicon(nic->rev_id, nic->hw->model_id)) {
> +			nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3),
> +				      (vnic << 24) | (padd << 16) |
> +				      (rssi_base + rssi));
> +		} else {
> +			/* Set MPI_ALG to '0' to disable MCAM parsing */
> +			nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3),
> +				      (padd << 16));
> +			/* MPI index is same as CPI if MPI_ALG is not enabled */
> +			nic_reg_write(nic, NIC_PF_MPI_0_2047_CFG | (cpi << 3),
> +				      (vnic << 24) | (rssi_base + rssi));
> +		}
> +
> +		if ((rssi + 1) >= cfg->rq_cnt)
> +			continue;
> +
> +		if (cfg->cpi_alg == CPI_ALG_VLAN)
> +			rssi++;
> +		else if (cfg->cpi_alg == CPI_ALG_VLAN16)
> +			rssi = ((cpi - cpi_base) & 0xe) >> 1;
> +		else if (cfg->cpi_alg == CPI_ALG_DIFF)
> +			rssi = ((cpi - cpi_base) & 0x38) >> 3;
> +	}
> +	nic->cpi_base[cfg->vf_id] = cpi_base;
> +	nic->rssi_base[cfg->vf_id] = rssi_base;
> +}
> +
> +/* Transmit channel configuration (TL4 -> TL3 -> Chan)
> + * VNIC0-SQ0 -> TL4(0)  -> TL4A(0) -> TL3[0] -> BGX0/LMAC0/Chan0
> + * VNIC1-SQ0 -> TL4(8)  -> TL4A(2) -> TL3[2] -> BGX0/LMAC1/Chan0
> + * VNIC2-SQ0 -> TL4(16) -> TL4A(4) -> TL3[4] -> BGX0/LMAC2/Chan0
> + * VNIC3-SQ0 -> TL4(32) -> TL4A(6) -> TL3[6] -> BGX0/LMAC3/Chan0
> + * VNIC4-SQ0 -> TL4(512)  -> TL4A(128) -> TL3[128] -> BGX1/LMAC0/Chan0
> + * VNIC5-SQ0 -> TL4(520)  -> TL4A(130) -> TL3[130] -> BGX1/LMAC1/Chan0
> + * VNIC6-SQ0 -> TL4(528)  -> TL4A(132) -> TL3[132] -> BGX1/LMAC2/Chan0
> + * VNIC7-SQ0 -> TL4(536)  -> TL4A(134) -> TL3[134] -> BGX1/LMAC3/Chan0
> + */
> +static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic,
> +			       struct sq_cfg_msg *sq)
> +{
> +	struct hw_info *hw = nic->hw;
> +	u32 bgx, lmac, chan;
> +	u32 tl2, tl3, tl4;
> +	u32 rr_quantum;
> +	u8 sq_idx = sq->sq_num;
> +	u8 pqs_vnic = vnic;
> +	int svf;
> +	u16 sdevid;
> +
> +	dm_pci_read_config16(nic->udev, PCI_SUBSYSTEM_ID, &sdevid);
> +
> +	bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]);
> +	lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]);
> +
> +	/* 24 bytes for FCS, IPG and preamble */
> +	rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4);
> +
> +	/* For 88xx 0-511 TL4 transmits via BGX0 and
> +	 * 512-1023 TL4s transmit via BGX1.
> +	 */
> +	if (hw->tl1_per_bgx) {
> +		tl4 = bgx * (hw->tl4_cnt / hw->bgx_cnt);
> +		if (!sq->sqs_mode) {
> +			tl4 += (lmac * MAX_QUEUES_PER_QSET);
> +		} else {
> +			for (svf = 0; svf < MAX_SQS_PER_VF_SINGLE_NODE; svf++) {
> +				if (nic->vf_sqs[pqs_vnic][svf] == vnic)
> +					break;
> +			}
> +			tl4 += (MAX_LMAC_PER_BGX * MAX_QUEUES_PER_QSET);
> +			tl4 += (lmac * MAX_QUEUES_PER_QSET *
> +				MAX_SQS_PER_VF_SINGLE_NODE);
> +			tl4 += (svf * MAX_QUEUES_PER_QSET);
> +		}
> +	} else {
> +		tl4 = (vnic * MAX_QUEUES_PER_QSET);
> +	}
> +
> +	tl4 += sq_idx;
> +
> +	tl3 = tl4 / (hw->tl4_cnt / hw->tl3_cnt);
> +	nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 |
> +		      ((u64)vnic << NIC_QS_ID_SHIFT) |
> +		      ((u32)sq_idx << NIC_Q_NUM_SHIFT), tl4);
> +	nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3),
> +		      ((u64)vnic << 27) | ((u32)sq_idx << 24) | rr_quantum);
> +
> +	nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum);
> +
> +	/* On 88xx 0-127 channels are for BGX0 and
> +	 * 127-255 channels for BGX1.
> +	 *
> +	 * On 81xx/83xx TL3_CHAN reg should be configured with channel
> +	 * within LMAC i.e 0-7 and not the actual channel number like on 88xx
> +	 */
> +	chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx);
> +	if (hw->tl1_per_bgx)
> +		nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan);
> +	else
> +		nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), 0);
> +
> +	/* Enable backpressure on the channel */
> +	nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1);
> +
> +	tl2 = tl3 >> 2;
> +	nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2);
> +	nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum);
> +	/* No priorities as of now */
> +	nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00);
> +
> +	/* Unlike 88xx where TL2s 0-31 transmits to TL1 '0' and rest to TL1 '1'
> +	 * on 81xx/83xx TL2 needs to be configured to transmit to one of the
> +	 * possible LMACs.
> +	 *
> +	 * This register doesn't exist on 88xx.
> +	 */
> +	if (!hw->tl1_per_bgx)
> +		nic_reg_write(nic, NIC_PF_TL2_LMAC | (tl2 << 3),
> +			      lmac + (bgx * MAX_LMAC_PER_BGX));
> +}
> +
> +int nic_initialize(struct udevice *dev)
> +{
> +	struct nicpf *nic = dev_get_priv(dev);
> +
> +	nic->udev = dev;
> +	nic->hw = calloc(1, sizeof(struct hw_info));
> +	if (!nic->hw)
> +		return -ENOMEM;
> +
> +	/* MAP PF's configuration registers */
> +	nic->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
> +				       PCI_REGION_MEM);
> +	if (!nic->reg_base) {
> +		printf("Cannot map config register space, aborting\n");
> +		goto exit;
> +	}
> +
> +	nic->node = node_id(nic->reg_base);
> +	dm_pci_read_config8(dev, PCI_REVISION_ID, &nic->rev_id);
> +
> +	/* By default set NIC in TNS bypass mode */
> +	nic->flags &= ~NIC_TNS_ENABLED;
> +
> +	/* Initialize hardware */
> +	nic_init_hw(nic);
> +
> +	nic_set_lmac_vf_mapping(nic);
> +
> +	/* Set RSS TBL size for each VF */
> +	nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
> +
> +	nic->rss_ind_tbl_size = rounddown_pow_of_two(nic->rss_ind_tbl_size);
> +
> +	return 0;
> +exit:
> +	free(nic->hw);
> +	return -ENODEV;
> +}
> +
> +int octeontx_nic_probe(struct udevice *dev)
> +{
> +	int ret = 0;
> +	struct nicpf *nicpf = dev_get_priv(dev);
> +
> +	nicpf->udev = dev;
> +	ret = nic_initialize(dev);
> +	if (ret < 0) {
> +		printf("couldn't initialize NIC PF\n");
> +		return ret;
> +	}
> +
> +	ret = pci_sriov_init(dev, nicpf->num_vf_en);
> +	if (ret < 0)
> +		printf("enabling SRIOV failed for num VFs %d\n",
> +		       nicpf->num_vf_en);
> +
> +	return ret;
> +}
> +
> +U_BOOT_DRIVER(octeontx_nic) = {
> +	.name	= "octeontx_nic",
> +	.id	= UCLASS_MISC,
> +	.probe	= octeontx_nic_probe,
> +	.priv_auto_alloc_size = sizeof(struct nicpf),
> +};
> +
> +static struct pci_device_id octeontx_nic_supported[] = {
> +	{ PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NIC) },
> +	{}
> +};
> +
> +U_BOOT_PCI_DEVICE(octeontx_nic, octeontx_nic_supported);
> +
> diff --git a/drivers/net/octeontx/nic_reg.h b/drivers/net/octeontx/nic_reg.h
> new file mode 100644
> index 0000000000..c214ebb679
> --- /dev/null
> +++ b/drivers/net/octeontx/nic_reg.h
> @@ -0,0 +1,250 @@
> +/* SPDX-License-Identifier:    GPL-2.0
> + *
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#ifndef NIC_REG_H
> +#define NIC_REG_H
> +
> +#define   NIC_PF_REG_COUNT			29573
> +#define   NIC_VF_REG_COUNT			249
> +
> +/* Physical function register offsets */
> +#define   NIC_PF_CFG				(0x0000)
> +#define   NIC_PF_STATUS				(0x0010)
> +
> +#define   NIC_PF_INTR_TIMER_CFG			(0x0030)
> +#define   NIC_PF_BIST_STATUS			(0x0040)
> +#define   NIC_PF_SOFT_RESET			(0x0050)
> +
> +#define   NIC_PF_TCP_TIMER			(0x0060)
> +#define   NIC_PF_BP_CFG				(0x0080)
> +#define   NIC_PF_RRM_CFG			(0x0088)
> +#define   NIC_PF_CQM_CF				(0x00A0)
> +#define   NIC_PF_CNM_CF				(0x00A8)
> +#define   NIC_PF_CNM_STATUS			(0x00B0)
> +#define   NIC_PF_CQ_AVG_CFG			(0x00C0)
> +#define   NIC_PF_RRM_AVG_CFG			(0x00C8)
> +
> +#define   NIC_PF_INTF_0_1_SEND_CFG		(0x0200)
> +#define   NIC_PF_INTF_0_1_BP_CFG		(0x0208)
> +#define   NIC_PF_INTF_0_1_BP_DIS_0_1		(0x0210)
> +#define   NIC_PF_INTF_0_1_BP_SW_0_1		(0x0220)
> +#define   NIC_PF_RBDR_BP_STATE_0_3		(0x0240)
> +
> +#define   NIC_PF_MAILBOX_INT			(0x0410)
> +#define   NIC_PF_MAILBOX_INT_W1S		(0x0430)
> +#define   NIC_PF_MAILBOX_ENA_W1C		(0x0450)
> +#define   NIC_PF_MAILBOX_ENA_W1S		(0x0470)
> +
> +#define   NIC_PF_RX_ETYPE_0_7			(0x0500)
> +#define   NIC_PF_RX_CFG				(0x05D0)
> +#define   NIC_PF_PKIND_0_15_CFG			(0x0600)
> +
> +#define   NIC_PF_ECC0_FLIP0			(0x1000)
> +#define   NIC_PF_ECC1_FLIP0			(0x1008)
> +#define   NIC_PF_ECC2_FLIP0			(0x1010)
> +#define   NIC_PF_ECC3_FLIP0			(0x1018)
> +#define   NIC_PF_ECC0_FLIP1			(0x1080)
> +#define   NIC_PF_ECC1_FLIP1			(0x1088)
> +#define   NIC_PF_ECC2_FLIP1			(0x1090)
> +#define   NIC_PF_ECC3_FLIP1			(0x1098)
> +#define   NIC_PF_ECC0_CDIS			(0x1100)
> +#define   NIC_PF_ECC1_CDIS			(0x1108)
> +#define   NIC_PF_ECC2_CDIS			(0x1110)
> +#define   NIC_PF_ECC3_CDIS			(0x1118)
> +#define   NIC_PF_BIST0_STATUS			(0x1280)
> +#define   NIC_PF_BIST1_STATUS			(0x1288)
> +#define   NIC_PF_BIST2_STATUS			(0x1290)
> +#define   NIC_PF_BIST3_STATUS			(0x1298)
> +
> +#define   NIC_PF_ECC0_SBE_INT			(0x2000)
> +#define   NIC_PF_ECC0_SBE_INT_W1S		(0x2008)
> +#define   NIC_PF_ECC0_SBE_ENA_W1C		(0x2010)
> +#define   NIC_PF_ECC0_SBE_ENA_W1S		(0x2018)
> +#define   NIC_PF_ECC0_DBE_INT			(0x2100)
> +#define   NIC_PF_ECC0_DBE_INT_W1S		(0x2108)
> +#define   NIC_PF_ECC0_DBE_ENA_W1C		(0x2110)
> +#define   NIC_PF_ECC0_DBE_ENA_W1S		(0x2118)
> +
> +#define   NIC_PF_ECC1_SBE_INT			(0x2200)
> +#define   NIC_PF_ECC1_SBE_INT_W1S		(0x2208)
> +#define   NIC_PF_ECC1_SBE_ENA_W1C		(0x2210)
> +#define   NIC_PF_ECC1_SBE_ENA_W1S		(0x2218)
> +#define   NIC_PF_ECC1_DBE_INT			(0x2300)
> +#define   NIC_PF_ECC1_DBE_INT_W1S		(0x2308)
> +#define   NIC_PF_ECC1_DBE_ENA_W1C		(0x2310)
> +#define   NIC_PF_ECC1_DBE_ENA_W1S		(0x2318)
> +
> +#define   NIC_PF_ECC2_SBE_INT			(0x2400)
> +#define   NIC_PF_ECC2_SBE_INT_W1S		(0x2408)
> +#define   NIC_PF_ECC2_SBE_ENA_W1C		(0x2410)
> +#define   NIC_PF_ECC2_SBE_ENA_W1S		(0x2418)
> +#define   NIC_PF_ECC2_DBE_INT			(0x2500)
> +#define   NIC_PF_ECC2_DBE_INT_W1S		(0x2508)
> +#define   NIC_PF_ECC2_DBE_ENA_W1C		(0x2510)
> +#define   NIC_PF_ECC2_DBE_ENA_W1S		(0x2518)
> +
> +#define   NIC_PF_ECC3_SBE_INT			(0x2600)
> +#define   NIC_PF_ECC3_SBE_INT_W1S		(0x2608)
> +#define   NIC_PF_ECC3_SBE_ENA_W1C		(0x2610)
> +#define   NIC_PF_ECC3_SBE_ENA_W1S		(0x2618)
> +#define   NIC_PF_ECC3_DBE_INT			(0x2700)
> +#define   NIC_PF_ECC3_DBE_INT_W1S		(0x2708)
> +#define   NIC_PF_ECC3_DBE_ENA_W1C		(0x2710)
> +#define   NIC_PF_ECC3_DBE_ENA_W1S		(0x2718)
> +
> +#define   NIC_PF_CPI_0_2047_CFG			(0x200000)
> +#define   NIC_PF_MPI_0_2047_CFG			(0x210000)
> +#define   NIC_PF_RSSI_0_4097_RQ			(0x220000)
> +#define   NIC_PF_LMAC_0_7_CFG			(0x240000)
> +#define   NIC_PF_LMAC_0_7_SW_XOFF		(0x242000)
> +#define   NIC_PF_LMAC_0_7_CREDIT		(0x244000)
> +#define   NIC_PF_CHAN_0_255_TX_CFG		(0x400000)
> +#define   NIC_PF_CHAN_0_255_RX_CFG		(0x420000)
> +#define   NIC_PF_CHAN_0_255_SW_XOFF		(0x440000)
> +#define   NIC_PF_CHAN_0_255_CREDIT		(0x460000)
> +#define   NIC_PF_CHAN_0_255_RX_BP_CFG		(0x480000)
> +
> +#define   NIC_PF_SW_SYNC_RX			(0x490000)
> +
> +#define   NIC_PF_SW_SYNC_RX_DONE		(0x490008)
> +#define   NIC_PF_TL2_0_63_CFG			(0x500000)
> +#define   NIC_PF_TL2_0_63_PRI			(0x520000)
> +#define   NIC_PF_TL2_LMAC			(0x540000)
> +#define   NIC_PF_TL2_0_63_SH_STATUS		(0x580000)
> +#define   NIC_PF_TL3A_0_63_CFG			(0x5F0000)
> +#define   NIC_PF_TL3_0_255_CFG			(0x600000)
> +#define   NIC_PF_TL3_0_255_CHAN			(0x620000)
> +#define   NIC_PF_TL3_0_255_PIR			(0x640000)
> +#define   NIC_PF_TL3_0_255_SW_XOFF		(0x660000)
> +#define   NIC_PF_TL3_0_255_CNM_RATE		(0x680000)
> +#define   NIC_PF_TL3_0_255_SH_STATUS		(0x6A0000)
> +#define   NIC_PF_TL4A_0_255_CFG			(0x6F0000)
> +#define   NIC_PF_TL4_0_1023_CFG			(0x800000)
> +#define   NIC_PF_TL4_0_1023_SW_XOFF		(0x820000)
> +#define   NIC_PF_TL4_0_1023_SH_STATUS		(0x840000)
> +#define   NIC_PF_TL4A_0_1023_CNM_RATE		(0x880000)
> +#define   NIC_PF_TL4A_0_1023_CNM_STATUS		(0x8A0000)
> +
> +#define   NIC_PF_VF_0_127_MAILBOX_0_1		(0x20002030)
> +#define   NIC_PF_VNIC_0_127_TX_STAT_0_4		(0x20004000)
> +#define   NIC_PF_VNIC_0_127_RX_STAT_0_13	(0x20004100)
> +#define   NIC_PF_QSET_0_127_LOCK_0_15		(0x20006000)
> +#define   NIC_PF_QSET_0_127_CFG			(0x20010000)
> +#define   NIC_PF_QSET_0_127_RQ_0_7_CFG		(0x20010400)
> +#define   NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG	(0x20010420)
> +#define   NIC_PF_QSET_0_127_RQ_0_7_BP_CFG	(0x20010500)
> +#define   NIC_PF_QSET_0_127_RQ_0_7_STAT_0_1	(0x20010600)
> +#define   NIC_PF_QSET_0_127_SQ_0_7_CFG		(0x20010C00)
> +#define   NIC_PF_QSET_0_127_SQ_0_7_CFG2		(0x20010C08)
> +#define   NIC_PF_QSET_0_127_SQ_0_7_STAT_0_1	(0x20010D00)
> +
> +#define   NIC_PF_MSIX_VEC_0_18_ADDR		(0x000000)
> +#define   NIC_PF_MSIX_VEC_0_CTL			(0x000008)
> +#define   NIC_PF_MSIX_PBA_0			(0x0F0000)
> +
> +/* Virtual function register offsets */
> +#define   NIC_VNIC_CFG				(0x000020)
> +#define   NIC_VF_PF_MAILBOX_0_1			(0x000130)
> +#define   NIC_VF_INT				(0x000200)
> +#define   NIC_VF_INT_W1S			(0x000220)
> +#define   NIC_VF_ENA_W1C			(0x000240)
> +#define   NIC_VF_ENA_W1S			(0x000260)
> +
> +#define   NIC_VNIC_RSS_CFG			(0x0020E0)
> +#define   NIC_VNIC_RSS_KEY_0_4			(0x002200)
> +#define   NIC_VNIC_TX_STAT_0_4			(0x004000)
> +#define   NIC_VNIC_RX_STAT_0_13			(0x004100)
> +#define   NIC_QSET_RQ_GEN_CFG			(0x010010)
> +
> +#define   NIC_QSET_CQ_0_7_CFG			(0x010400)
> +#define   NIC_QSET_CQ_0_7_CFG2			(0x010408)
> +#define   NIC_QSET_CQ_0_7_THRESH		(0x010410)
> +#define   NIC_QSET_CQ_0_7_BASE			(0x010420)
> +#define   NIC_QSET_CQ_0_7_HEAD			(0x010428)
> +#define   NIC_QSET_CQ_0_7_TAIL			(0x010430)
> +#define   NIC_QSET_CQ_0_7_DOOR			(0x010438)
> +#define   NIC_QSET_CQ_0_7_STATUS		(0x010440)
> +#define   NIC_QSET_CQ_0_7_STATUS2		(0x010448)
> +#define   NIC_QSET_CQ_0_7_DEBUG			(0x010450)
> +
> +#define   NIC_QSET_RQ_0_7_CFG			(0x010600)
> +#define   NIC_QSET_RQ_0_7_STAT_0_1		(0x010700)
> +
> +#define   NIC_QSET_SQ_0_7_CFG			(0x010800)
> +#define   NIC_QSET_SQ_0_7_THRESH		(0x010810)
> +#define   NIC_QSET_SQ_0_7_BASE			(0x010820)
> +#define   NIC_QSET_SQ_0_7_HEAD			(0x010828)
> +#define   NIC_QSET_SQ_0_7_TAIL			(0x010830)
> +#define   NIC_QSET_SQ_0_7_DOOR			(0x010838)
> +#define   NIC_QSET_SQ_0_7_STATUS		(0x010840)
> +#define   NIC_QSET_SQ_0_7_DEBUG			(0x010848)
> +#define   NIC_QSET_SQ_0_7_CNM_CHG		(0x010860)
> +#define   NIC_QSET_SQ_0_7_STAT_0_1		(0x010900)
> +
> +#define   NIC_QSET_RBDR_0_1_CFG			(0x010C00)
> +#define   NIC_QSET_RBDR_0_1_THRESH		(0x010C10)
> +#define   NIC_QSET_RBDR_0_1_BASE		(0x010C20)
> +#define   NIC_QSET_RBDR_0_1_HEAD		(0x010C28)
> +#define   NIC_QSET_RBDR_0_1_TAIL		(0x010C30)
> +#define   NIC_QSET_RBDR_0_1_DOOR		(0x010C38)
> +#define   NIC_QSET_RBDR_0_1_STATUS0		(0x010C40)
> +#define   NIC_QSET_RBDR_0_1_STATUS1		(0x010C48)
> +#define   NIC_QSET_RBDR_0_1_PREFETCH_STATUS	(0x010C50)
> +
> +#define   NIC_VF_MSIX_VECTOR_0_19_ADDR		(0x000000)
> +#define   NIC_VF_MSIX_VECTOR_0_19_CTL		(0x000008)
> +#define   NIC_VF_MSIX_PBA			(0x0F0000)
> +
> +/* Offsets within registers */
> +#define   NIC_MSIX_VEC_SHIFT			4
> +#define   NIC_Q_NUM_SHIFT			18
> +#define   NIC_QS_ID_SHIFT			21
> +#define   NIC_VF_NUM_SHIFT			21
> +
> +/* Port kind configuration register */
> +struct pkind_cfg {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	uint64_t reserved_42_63:22;
> +	uint64_t hdr_sl:5;	/* Header skip length */
> +	uint64_t rx_hdr:3;	/* TNS Receive header present */
> +	uint64_t lenerr_en:1;	/* L2 length error check enable */
> +	uint64_t reserved_32_32:1;
> +	uint64_t maxlen:16;	/* Max frame size */
> +	uint64_t minlen:16;	/* Min frame size */
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	uint64_t minlen:16;
> +	uint64_t maxlen:16;
> +	uint64_t reserved_32_32:1;
> +	uint64_t lenerr_en:1;
> +	uint64_t rx_hdr:3;
> +	uint64_t hdr_sl:5;
> +	uint64_t reserved_42_63:22;
> +#endif
> +};
> +
> +static inline uint64_t BGXX_PF_BAR0(unsigned long param1)
> +				     __attribute__ ((pure, always_inline));
> +static inline uint64_t BGXX_PF_BAR0(unsigned long param1)
> +{
> +	assert(param1 <= 1);
> +	return 0x87E0E0000000 + (param1 << 24);
> +}
> +
> +#define BGXX_PF_BAR0_SIZE 0x400000
> +#define NIC_PF_BAR0 0x843000000000
> +#define NIC_PF_BAR0_SIZE 0x40000000
> +
> +static inline uint64_t NIC_VFX_BAR0(unsigned long param1)
> +				     __attribute__ ((pure, always_inline));
> +static inline uint64_t NIC_VFX_BAR0(unsigned long param1)
> +{
> +	assert(param1 <= 127);
> +
> +	return 0x8430A0000000 + (param1 << 21);
> +}
> +
> +#define NIC_VFX_BAR0_SIZE 0x200000
> +
> +#endif /* NIC_REG_H */
> diff --git a/drivers/net/octeontx/nicvf_main.c b/drivers/net/octeontx/nicvf_main.c
> new file mode 100644
> index 0000000000..e13c8b9556
> --- /dev/null
> +++ b/drivers/net/octeontx/nicvf_main.c
> @@ -0,0 +1,581 @@
> +// SPDX-License-Identifier:    GPL-2.0
> +/*
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#include <dm.h>
> +#include <malloc.h>
> +#include <misc.h>
> +#include <net.h>
> +#include <pci.h>
> +#include <pci_ids.h>
> +#include <phy.h>
> +#include <asm/io.h>
> +#include <linux/delay.h>
> +
> +#include "nic_reg.h"
> +#include "nic.h"
> +#include "nicvf_queues.h"
> +
> +/* Register read/write APIs */
> +void nicvf_reg_write(struct nicvf *nic, u64 offset, u64 val)
> +{
> +	writeq(val, nic->reg_base + offset);
> +}
> +
> +u64 nicvf_reg_read(struct nicvf *nic, u64 offset)
> +{
> +	return readq(nic->reg_base + offset);
> +}
> +
> +void nicvf_queue_reg_write(struct nicvf *nic, u64 offset,
> +			   u64 qidx, u64 val)
> +{
> +	void *addr = nic->reg_base + offset;
> +
> +	writeq(val, (void *)(addr + (qidx << NIC_Q_NUM_SHIFT)));
> +}
> +
> +u64 nicvf_queue_reg_read(struct nicvf *nic, u64 offset, u64 qidx)
> +{
> +	void *addr = nic->reg_base + offset;
> +
> +	return readq((void *)(addr + (qidx << NIC_Q_NUM_SHIFT)));
> +}
> +
> +static void  nicvf_handle_mbx_intr(struct nicvf *nic);
> +
> +/* VF -> PF mailbox communication */
> +static void nicvf_write_to_mbx(struct nicvf *nic, union nic_mbx *mbx)
> +{
> +	u64 *msg = (u64 *)mbx;
> +
> +	nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 0, msg[0]);
> +	nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 8, msg[1]);
> +}
> +
> +int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx)
> +{
> +	int timeout = NIC_PF_VF_MBX_TIMEOUT;
> +	int sleep = 10;
> +
> +	nic->pf_acked = false;
> +	nic->pf_nacked = false;
> +
> +	nicvf_write_to_mbx(nic, mbx);
> +
> +	nic_handle_mbx_intr(nic->nicpf, nic->vf_id);
> +
> +	/* Wait for previous message to be acked, timeout 2sec */
> +	while (!nic->pf_acked) {
> +		if (nic->pf_nacked)
> +			return -1;
> +		mdelay(sleep);
> +		nicvf_handle_mbx_intr(nic);
> +
> +		if (nic->pf_acked)
> +			break;
> +		timeout -= sleep;
> +		if (!timeout) {
> +			printf("PF didn't ack to mbox msg %d from VF%d\n",
> +			       (mbx->msg.msg & 0xFF), nic->vf_id);
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/* Checks if VF is able to comminicate with PF
> + * and also gets the VNIC number this VF is associated to.
> + */
> +static int nicvf_check_pf_ready(struct nicvf *nic)
> +{
> +	union nic_mbx mbx = {};
> +
> +	mbx.msg.msg = NIC_MBOX_MSG_READY;
> +	if (nicvf_send_msg_to_pf(nic, &mbx)) {
> +		printf("PF didn't respond to READY msg\n");
> +		return 0;
> +	}
> +
> +	return 1;
> +}
> +
> +static void  nicvf_handle_mbx_intr(struct nicvf *nic)
> +{
> +	union nic_mbx mbx = {};
> +	struct eth_pdata *pdata = dev_get_platdata(nic->dev);
> +	u64 *mbx_data;
> +	u64 mbx_addr;
> +	int i;
> +
> +	mbx_addr = NIC_VF_PF_MAILBOX_0_1;
> +	mbx_data = (u64 *)&mbx;
> +
> +	for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
> +		*mbx_data = nicvf_reg_read(nic, mbx_addr);
> +		mbx_data++;
> +		mbx_addr += sizeof(u64);
> +	}
> +
> +	debug("Mbox message: msg: 0x%x\n", mbx.msg.msg);
> +	switch (mbx.msg.msg) {
> +	case NIC_MBOX_MSG_READY:
> +		nic->pf_acked = true;
> +		nic->vf_id = mbx.nic_cfg.vf_id & 0x7F;
> +		nic->tns_mode = mbx.nic_cfg.tns_mode & 0x7F;
> +		nic->node = mbx.nic_cfg.node_id;
> +		if (!nic->set_mac_pending)
> +			memcpy(pdata->enetaddr,
> +			       mbx.nic_cfg.mac_addr, 6);
> +		nic->loopback_supported = mbx.nic_cfg.loopback_supported;
> +		nic->link_up = false;
> +		nic->duplex = 0;
> +		nic->speed = 0;
> +		break;
> +	case NIC_MBOX_MSG_ACK:
> +		nic->pf_acked = true;
> +		break;
> +	case NIC_MBOX_MSG_NACK:
> +		nic->pf_nacked = true;
> +		break;
> +	case NIC_MBOX_MSG_BGX_LINK_CHANGE:
> +		nic->pf_acked = true;
> +		nic->link_up = mbx.link_status.link_up;
> +		nic->duplex = mbx.link_status.duplex;
> +		nic->speed = mbx.link_status.speed;
> +		if (nic->link_up) {
> +			printf("%s: Link is Up %d Mbps %s\n",
> +			       nic->dev->name, nic->speed,
> +			       nic->duplex == 1 ?
> +			       "Full duplex" : "Half duplex");
> +		} else {
> +			printf("%s: Link is Down\n", nic->dev->name);
> +		}
> +		break;
> +	default:
> +		printf("Invalid message from PF, msg 0x%x\n", mbx.msg.msg);
> +		break;
> +	}
> +
> +	nicvf_clear_intr(nic, NICVF_INTR_MBOX, 0);
> +}
> +
> +static int nicvf_hw_set_mac_addr(struct nicvf *nic, struct udevice *dev)
> +{
> +	union nic_mbx mbx = {};
> +	struct eth_pdata *pdata = dev_get_platdata(dev);
> +
> +	mbx.mac.msg = NIC_MBOX_MSG_SET_MAC;
> +	mbx.mac.vf_id = nic->vf_id;
> +	memcpy(mbx.mac.mac_addr, pdata->enetaddr, 6);
> +
> +	return nicvf_send_msg_to_pf(nic, &mbx);
> +}
> +
> +static void nicvf_config_cpi(struct nicvf *nic)
> +{
> +	union nic_mbx mbx = {};
> +
> +	mbx.cpi_cfg.msg = NIC_MBOX_MSG_CPI_CFG;
> +	mbx.cpi_cfg.vf_id = nic->vf_id;
> +	mbx.cpi_cfg.cpi_alg = nic->cpi_alg;
> +	mbx.cpi_cfg.rq_cnt = nic->qs->rq_cnt;
> +
> +	nicvf_send_msg_to_pf(nic, &mbx);
> +}
> +
> +static int nicvf_init_resources(struct nicvf *nic)
> +{
> +	int err;
> +
> +	nic->num_qs = 1;
> +
> +	/* Enable Qset */
> +	nicvf_qset_config(nic, true);
> +
> +	/* Initialize queues and HW for data transfer */
> +	err = nicvf_config_data_transfer(nic, true);
> +
> +	if (err) {
> +		printf("Failed to alloc/config VF's QSet resources\n");
> +		return err;
> +	}
> +	return 0;
> +}
> +
> +static void nicvf_snd_pkt_handler(struct nicvf *nic,
> +				  struct cmp_queue *cq,
> +				  void *cq_desc, int cqe_type)
> +{
> +	struct cqe_send_t *cqe_tx;
> +	struct snd_queue *sq;
> +	struct sq_hdr_subdesc *hdr;
> +
> +	cqe_tx = (struct cqe_send_t *)cq_desc;
> +	sq = &nic->qs->sq[cqe_tx->sq_idx];
> +
> +	hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, cqe_tx->sqe_ptr);
> +	if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER)
> +		return;
> +
> +	nicvf_check_cqe_tx_errs(nic, cq, cq_desc);
> +	nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
> +}
> +
> +static int nicvf_rcv_pkt_handler(struct nicvf *nic,
> +				 struct cmp_queue *cq, void *cq_desc,
> +				 void **ppkt, int cqe_type)
> +{
> +	void *pkt;
> +
> +	size_t pkt_len;
> +	struct cqe_rx_t *cqe_rx = (struct cqe_rx_t *)cq_desc;
> +	int err = 0;
> +
> +	/* Check for errors */
> +	err = nicvf_check_cqe_rx_errs(nic, cq, cq_desc);
> +	if (err && !cqe_rx->rb_cnt)
> +		return -1;
> +
> +	pkt = nicvf_get_rcv_pkt(nic, cq_desc, &pkt_len);
> +	if (!pkt) {
> +		debug("Packet not received\n");
> +		return -1;
> +	}
> +
> +	if (pkt)
> +		*ppkt = pkt;
> +
> +	return pkt_len;
> +}
> +
> +int nicvf_cq_handler(struct nicvf *nic, void **ppkt, int *pkt_len)
> +{
> +	int cq_qnum = 0;
> +	int processed_sq_cqe = 0;
> +	int processed_rq_cqe = 0;
> +	int processed_cqe = 0;
> +
> +	unsigned long cqe_count, cqe_head;
> +	struct queue_set *qs = nic->qs;
> +	struct cmp_queue *cq = &qs->cq[cq_qnum];
> +	struct cqe_rx_t *cq_desc;
> +
> +	/* Get num of valid CQ entries expect next one to be SQ completion */
> +	cqe_count = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, cq_qnum);
> +	cqe_count &= 0xFFFF;
> +	if (!cqe_count)
> +		return 0;
> +
> +	/* Get head of the valid CQ entries */
> +	cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_qnum);
> +	cqe_head >>= 9;
> +	cqe_head &= 0xFFFF;
> +
> +	if (cqe_count) {
> +		/* Get the CQ descriptor */
> +		cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head);
> +		cqe_head++;
> +		cqe_head &= (cq->dmem.q_len - 1);
> +		/* Initiate prefetch for next descriptor */
> +		prefetch((struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head));
> +
> +		switch (cq_desc->cqe_type) {
> +		case CQE_TYPE_RX:
> +			debug("%s: Got Rx CQE\n", nic->dev->name);
> +			*pkt_len = nicvf_rcv_pkt_handler(nic, cq, cq_desc,
> +							 ppkt, CQE_TYPE_RX);
> +			processed_rq_cqe++;
> +			break;
> +		case CQE_TYPE_SEND:
> +			debug("%s: Got Tx CQE\n", nic->dev->name);
> +			nicvf_snd_pkt_handler(nic, cq, cq_desc, CQE_TYPE_SEND);
> +			processed_sq_cqe++;
> +			break;
> +		default:
> +			debug("%s: Got CQ type %u\n", nic->dev->name,
> +			      cq_desc->cqe_type);
> +			break;
> +		}
> +		processed_cqe++;
> +	}
> +
> +	/* Dequeue CQE */
> +	nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR,
> +			      cq_qnum, processed_cqe);
> +
> +	asm volatile ("dsb sy");
> +
> +	return (processed_sq_cqe | processed_rq_cqe);
> +}
> +
> +/* Qset error interrupt handler
> + *
> + * As of now only CQ errors are handled
> + */
> +void nicvf_handle_qs_err(struct nicvf *nic)
> +{
> +	struct queue_set *qs = nic->qs;
> +	int qidx;
> +	u64 status;
> +
> +	/* Check if it is CQ err */
> +	for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
> +		status = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS,
> +					      qidx);
> +		if (!(status & CQ_ERR_MASK))
> +			continue;
> +		/* Process already queued CQEs and reconfig CQ */
> +		nicvf_sq_disable(nic, qidx);
> +		nicvf_cmp_queue_config(nic, qs, qidx, true);
> +		nicvf_sq_free_used_descs(nic->dev, &qs->sq[qidx], qidx);
> +		nicvf_sq_enable(nic, &qs->sq[qidx], qidx);
> +	}
> +}
> +
> +static int nicvf_free_pkt(struct udevice *dev, uchar *pkt, int pkt_len)
> +{
> +	struct nicvf *nic = dev_get_priv(dev);
> +
> +	if (pkt && pkt_len)
> +		free(pkt);
> +	nicvf_refill_rbdr(nic);
> +	return 0;
> +}
> +
> +static int nicvf_xmit(struct udevice *dev, void *pkt, int pkt_len)
> +{
> +	struct nicvf *nic = dev_get_priv(dev);
> +	int ret = 0;
> +	int rcv_len = 0;
> +	unsigned int timeout = 5000;
> +	void *rpkt = NULL;
> +
> +	if (!nicvf_sq_append_pkt(nic, pkt, pkt_len)) {
> +		printf("VF%d: TX ring full\n", nic->vf_id);
> +		return -1;
> +	}
> +
> +	/* check and update CQ for pkt sent */
> +	while (!ret && timeout--) {
> +		ret = nicvf_cq_handler(nic, &rpkt, &rcv_len);
> +		if (!ret) {
> +			debug("%s: %d, Not sent\n", __func__, __LINE__);
> +			udelay(10);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int nicvf_recv(struct udevice *dev, int flags, uchar **packetp)
> +{
> +	struct nicvf *nic = dev_get_priv(dev);
> +	void *pkt;
> +	int pkt_len = 0;
> +#ifdef DEBUG
> +	u8 *dpkt;
> +	int i, j;
> +#endif
> +
> +	nicvf_cq_handler(nic, &pkt, &pkt_len);
> +
> +	if (pkt_len) {
> +#ifdef DEBUG
> +		dpkt = pkt;
> +		printf("RX packet contents:\n");
> +		for (i = 0; i < 8; i++) {
> +			puts("\t");
> +			for (j = 0; j < 10; j++)
> +				printf("%02x ", dpkt[i * 10 + j]);
> +			puts("\n");
> +		}
> +#endif
> +		*packetp = pkt;
> +	}
> +
> +	return pkt_len;
> +}
> +
> +void nicvf_stop(struct udevice *dev)
> +{
> +	struct nicvf *nic = dev_get_priv(dev);
> +
> +	if (!nic->open)
> +		return;
> +
> +	/* Free resources */
> +	nicvf_config_data_transfer(nic, false);
> +
> +	/* Disable HW Qset */
> +	nicvf_qset_config(nic, false);
> +
> +	nic->open = false;
> +}
> +
> +int nicvf_open(struct udevice *dev)
> +{
> +	int err;
> +	struct nicvf *nic = dev_get_priv(dev);
> +
> +	nicvf_hw_set_mac_addr(nic, dev);
> +
> +	/* Configure CPI alorithm */
> +	nic->cpi_alg = CPI_ALG_NONE;
> +	nicvf_config_cpi(nic);
> +
> +	/* Initialize the queues */
> +	err = nicvf_init_resources(nic);
> +	if (err)
> +		return -1;
> +
> +	if (!nicvf_check_pf_ready(nic))
> +		return -1;
> +
> +	nic->open = true;
> +
> +	/* Make sure queue initialization is written */
> +	asm volatile("dsb sy");
> +
> +	return 0;
> +}
> +
> +int nicvf_write_hwaddr(struct udevice *dev)
> +{
> +	unsigned char ethaddr[ARP_HLEN];
> +	struct eth_pdata *pdata = dev_get_platdata(dev);
> +	struct nicvf *nic = dev_get_priv(dev);
> +
> +	/* If lower level firmware fails to set proper MAC
> +	 * u-boot framework updates MAC to random address.
> +	 * Use this hook to update mac address in environment.
> +	 */
> +	if (!eth_env_get_enetaddr_by_index("eth", dev->seq, ethaddr)) {
> +		eth_env_set_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
> +		debug("%s: pMAC %pM\n", __func__, pdata->enetaddr);
> +	}
> +	eth_env_get_enetaddr_by_index("eth", dev->seq, ethaddr);
> +	if (memcmp(ethaddr, pdata->enetaddr, ARP_HLEN)) {
> +		debug("%s: pMAC %pM\n", __func__, pdata->enetaddr);
> +		nicvf_hw_set_mac_addr(nic, dev);
> +	}
> +	return 0;
> +}
> +
> +static void nicvf_probe_mdio_devices(void)
> +{
> +	struct udevice *pdev;
> +	int err;
> +	static int probed;
> +
> +	if (probed)
> +		return;
> +
> +	err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
> +				 PCI_DEVICE_ID_CAVIUM_SMI, 0,
> +				 &pdev);
> +	if (err)
> +		debug("%s couldn't find SMI device\n", __func__);
> +	probed = 1;
> +}
> +
> +int nicvf_initialize(struct udevice *dev)
> +{
> +	struct nicvf *nicvf = dev_get_priv(dev);
> +	struct eth_pdata *pdata = dev_get_platdata(dev);
> +	int    ret = 0, bgx, lmac;
> +	char   name[16];
> +	unsigned char ethaddr[ARP_HLEN];
> +	struct udevice *pfdev;
> +	struct nicpf *pf;
> +	static int vfid;
> +
> +	if (dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
> +			       PCI_DEVICE_ID_CAVIUM_NIC, 0, &pfdev)) {
> +		printf("%s NIC PF device not found..VF probe failed\n",
> +		       __func__);
> +		return -1;
> +	}
> +	pf = dev_get_priv(pfdev);
> +	nicvf->vf_id = vfid++;
> +	nicvf->dev = dev;
> +	nicvf->nicpf = pf;
> +
> +	nicvf_probe_mdio_devices();
> +
> +	/* Enable TSO support */
> +	nicvf->hw_tso = true;
> +
> +	nicvf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
> +					 PCI_REGION_MEM);
> +
> +	debug("nicvf->reg_base: %p\n", nicvf->reg_base);
> +
> +	if (!nicvf->reg_base) {
> +		printf("Cannot map config register space, aborting\n");
> +		ret = -1;
> +		goto fail;
> +	}
> +
> +	ret = nicvf_set_qset_resources(nicvf);
> +	if (ret)
> +		return -1;
> +
> +	sprintf(name, "vnic%u", nicvf->vf_id);
> +	debug("%s name %s\n", __func__, name);
> +	device_set_name(dev, name);
> +
> +	bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]);
> +	lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]);
> +	debug("%s VF %d BGX %d LMAC %d\n", __func__, nicvf->vf_id, bgx, lmac);
> +	debug("%s PF %p pfdev %p VF %p vfdev %p vf->pdata %p\n",
> +	      __func__, nicvf->nicpf, nicvf->nicpf->udev, nicvf, nicvf->dev,
> +	      pdata);
> +
> +	fdt_board_get_ethaddr(bgx, lmac, ethaddr);
> +
> +	debug("%s bgx %d lmac %d ethaddr %pM\n", __func__, bgx, lmac, ethaddr);
> +
> +	if (is_valid_ethaddr(ethaddr)) {
> +		memcpy(pdata->enetaddr, ethaddr, ARP_HLEN);
> +		eth_env_set_enetaddr_by_index("eth", dev->seq, ethaddr);
> +	}
> +	debug("%s enetaddr %pM ethaddr %pM\n", __func__,
> +	      pdata->enetaddr, ethaddr);
> +
> +fail:
> +	return ret;
> +}
> +
> +int octeontx_vnic_probe(struct udevice *dev)
> +{
> +	return nicvf_initialize(dev);
> +}
> +
> +static const struct eth_ops octeontx_vnic_ops = {
> +	.start = nicvf_open,
> +	.stop  = nicvf_stop,
> +	.send  = nicvf_xmit,
> +	.recv  = nicvf_recv,
> +	.free_pkt = nicvf_free_pkt,
> +	.write_hwaddr = nicvf_write_hwaddr,
> +};
> +
> +U_BOOT_DRIVER(octeontx_vnic) = {
> +	.name	= "vnic",
> +	.id	= UCLASS_ETH,
> +	.probe	= octeontx_vnic_probe,
> +	.ops	= &octeontx_vnic_ops,
> +	.priv_auto_alloc_size = sizeof(struct nicvf),
> +	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
> +};
> +
> +static struct pci_device_id octeontx_vnic_supported[] = {
> +	{ PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF) },
> +	{ PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF_1) },
> +	{}
> +};
> +
> +U_BOOT_PCI_DEVICE(octeontx_vnic, octeontx_vnic_supported);
> diff --git a/drivers/net/octeontx/nicvf_queues.c b/drivers/net/octeontx/nicvf_queues.c
> new file mode 100644
> index 0000000000..c7f262f440
> --- /dev/null
> +++ b/drivers/net/octeontx/nicvf_queues.c
> @@ -0,0 +1,1140 @@
> +// SPDX-License-Identifier:    GPL-2.0
> +/*
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#include <cpu_func.h>
> +#include <dm/device.h>
> +#include <malloc.h>
> +#include <net.h>
> +#include <phy.h>
> +#include <linux/delay.h>
> +
> +#include "nic_reg.h"
> +#include "nic.h"
> +#include "q_struct.h"
> +#include "nicvf_queues.h"
> +
> +static int nicvf_poll_reg(struct nicvf *nic, int qidx,
> +			  u64 reg, int bit_pos, int bits, int val)
> +{
> +	u64 bit_mask;
> +	u64 reg_val;
> +	int timeout = 10;
> +
> +	bit_mask = (1ULL << bits) - 1;
> +	bit_mask = (bit_mask << bit_pos);
> +
> +	while (timeout) {
> +		reg_val = nicvf_queue_reg_read(nic, reg, qidx);
> +		if (((reg_val & bit_mask) >> bit_pos) == val)
> +			return 0;
> +		udelay(2000);
> +		timeout--;
> +	}
> +	printf("Poll on reg 0x%llx failed\n", reg);
> +	return 1;
> +}
> +
> +static int nicvf_alloc_q_desc_mem(struct nicvf *nic, struct q_desc_mem *dmem,
> +				  int q_len, int desc_size, int align_bytes)
> +{
> +	dmem->q_len = q_len;
> +	dmem->size = (desc_size * q_len) + align_bytes;
> +	/* Save address, need it while freeing */
> +	dmem->unalign_base = calloc(1, dmem->size);
> +	dmem->dma = (uintptr_t)dmem->unalign_base;
> +
> +	if (!dmem->unalign_base)
> +		return -1;
> +
> +	/* Align memory address for 'align_bytes' */
> +	dmem->phys_base = NICVF_ALIGNED_ADDR((u64)dmem->dma, align_bytes);
> +	dmem->base = dmem->unalign_base + (dmem->phys_base - dmem->dma);
> +
> +	return 0;
> +}
> +
> +static void nicvf_free_q_desc_mem(struct nicvf *nic, struct q_desc_mem *dmem)
> +{
> +	if (!dmem)
> +		return;
> +
> +	free(dmem->unalign_base);
> +
> +	dmem->unalign_base = NULL;
> +	dmem->base = NULL;
> +}
> +
> +static void *nicvf_rb_ptr_to_pkt(struct nicvf *nic, uintptr_t rb_ptr)
> +{
> +	return (void *)rb_ptr;
> +}
> +
> +static int nicvf_init_rbdr(struct nicvf *nic, struct rbdr *rbdr,
> +			   int ring_len, int buf_size)
> +{
> +	int idx;
> +	uintptr_t rbuf;
> +	struct rbdr_entry_t *desc;
> +
> +	if (nicvf_alloc_q_desc_mem(nic, &rbdr->dmem, ring_len,
> +				   sizeof(struct rbdr_entry_t),
> +				   NICVF_RCV_BUF_ALIGN_BYTES)) {
> +		printf("Unable to allocate memory for rcv buffer ring\n");
> +		return -1;
> +	}
> +
> +	rbdr->desc = rbdr->dmem.base;
> +	/* Buffer size has to be in multiples of 128 bytes */
> +	rbdr->dma_size = buf_size;
> +	rbdr->enable = true;
> +	rbdr->thresh = RBDR_THRESH;
> +
> +	debug("%s: %d: allocating %lld bytes for rcv buffers\n",
> +	      __func__, __LINE__,
> +	      ring_len * buf_size + NICVF_RCV_BUF_ALIGN_BYTES);
> +	rbdr->buf_mem = (uintptr_t)calloc(1, ring_len * buf_size
> +						+ NICVF_RCV_BUF_ALIGN_BYTES);
> +
> +	if (!rbdr->buf_mem) {
> +		printf("Unable to allocate memory for rcv buffers\n");
> +		return -1;
> +	}
> +
> +	rbdr->buffers = NICVF_ALIGNED_ADDR(rbdr->buf_mem,
> +					   NICVF_RCV_BUF_ALIGN_BYTES);
> +
> +	debug("%s: %d: rbdr->buf_mem: %lx, rbdr->buffers: %lx\n",
> +	      __func__, __LINE__, rbdr->buf_mem, rbdr->buffers);
> +
> +	for (idx = 0; idx < ring_len; idx++) {
> +		rbuf = rbdr->buffers + DMA_BUFFER_LEN * idx;
> +		desc = GET_RBDR_DESC(rbdr, idx);
> +		desc->buf_addr = rbuf >> NICVF_RCV_BUF_ALIGN;
> +		flush_dcache_range((uintptr_t)desc,
> +				   (uintptr_t)desc + sizeof(desc));
> +	}
> +	return 0;
> +}
> +
> +static void nicvf_free_rbdr(struct nicvf *nic, struct rbdr *rbdr)
> +{
> +	if (!rbdr)
> +		return;
> +
> +	rbdr->enable = false;
> +	if (!rbdr->dmem.base)
> +		return;
> +
> +	debug("%s: %d: rbdr->buf_mem: %p\n", __func__,
> +	      __LINE__, (void *)rbdr->buf_mem);
> +	free((void *)rbdr->buf_mem);
> +
> +	/* Free RBDR ring */
> +	nicvf_free_q_desc_mem(nic, &rbdr->dmem);
> +}
> +
> +/* Refill receive buffer descriptors with new buffers.
> + * This runs in softirq context .
> + */
> +void nicvf_refill_rbdr(struct nicvf *nic)
> +{
> +	struct queue_set *qs = nic->qs;
> +	int rbdr_idx = qs->rbdr_cnt;
> +	unsigned long qcount, head, tail, rb_cnt;
> +	struct rbdr *rbdr;
> +
> +	if (!rbdr_idx)
> +		return;
> +	rbdr_idx--;
> +	rbdr = &qs->rbdr[rbdr_idx];
> +	/* Check if it's enabled */
> +	if (!rbdr->enable) {
> +		printf("Receive queue %d is disabled\n", rbdr_idx);
> +		return;
> +	}
> +
> +	/* check if valid descs reached or crossed threshold level */
> +	qcount = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_STATUS0, rbdr_idx);
> +	head = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_HEAD, rbdr_idx);
> +	tail = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_TAIL, rbdr_idx);
> +
> +	qcount &= 0x7FFFF;
> +
> +	rb_cnt = qs->rbdr_len - qcount - 1;
> +
> +	debug("%s: %d: qcount: %lu, head: %lx, tail: %lx, rb_cnt: %lu\n",
> +	      __func__, __LINE__, qcount, head, tail, rb_cnt);
> +
> +	/* Notify HW */
> +	nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_DOOR, rbdr_idx, rb_cnt);
> +
> +	asm volatile ("dsb sy");
> +}
> +
> +/* TBD: how to handle full packets received in CQ
> + * i.e conversion of buffers into SKBs
> + */
> +static int nicvf_init_cmp_queue(struct nicvf *nic,
> +				struct cmp_queue *cq, int q_len)
> +{
> +	if (nicvf_alloc_q_desc_mem(nic, &cq->dmem, q_len,
> +				   CMP_QUEUE_DESC_SIZE,
> +				   NICVF_CQ_BASE_ALIGN_BYTES)) {
> +		printf("Unable to allocate memory for completion queue\n");
> +		return -1;
> +	}
> +	cq->desc = cq->dmem.base;
> +	if (!pass1_silicon(nic->rev_id, nic->nicpf->hw->model_id))
> +		cq->thresh = CMP_QUEUE_CQE_THRESH;
> +	else
> +		cq->thresh = 0;
> +	cq->intr_timer_thresh = CMP_QUEUE_TIMER_THRESH;
> +
> +	return 0;
> +}
> +
> +static void nicvf_free_cmp_queue(struct nicvf *nic, struct cmp_queue *cq)
> +{
> +	if (!cq)
> +		return;
> +	if (!cq->dmem.base)
> +		return;
> +
> +	nicvf_free_q_desc_mem(nic, &cq->dmem);
> +}
> +
> +static int nicvf_init_snd_queue(struct nicvf *nic,
> +				struct snd_queue *sq, int q_len)
> +{
> +	if (nicvf_alloc_q_desc_mem(nic, &sq->dmem, q_len,
> +				   SND_QUEUE_DESC_SIZE,
> +				   NICVF_SQ_BASE_ALIGN_BYTES)) {
> +		printf("Unable to allocate memory for send queue\n");
> +		return -1;
> +	}
> +
> +	sq->desc = sq->dmem.base;
> +	sq->skbuff = calloc(q_len, sizeof(u64));
> +	sq->head = 0;
> +	sq->tail = 0;
> +	sq->free_cnt = q_len - 1;
> +	sq->thresh = SND_QUEUE_THRESH;
> +
> +	return 0;
> +}
> +
> +static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq)
> +{
> +	if (!sq)
> +		return;
> +	if (!sq->dmem.base)
> +		return;
> +
> +	debug("%s: %d\n", __func__, __LINE__);
> +	free(sq->skbuff);
> +
> +	nicvf_free_q_desc_mem(nic, &sq->dmem);
> +}
> +
> +static void nicvf_reclaim_snd_queue(struct nicvf *nic,
> +				    struct queue_set *qs, int qidx)
> +{
> +	/* Disable send queue */
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, 0);
> +	/* Check if SQ is stopped */
> +	if (nicvf_poll_reg(nic, qidx, NIC_QSET_SQ_0_7_STATUS, 21, 1, 0x01))
> +		return;
> +	/* Reset send queue */
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, NICVF_SQ_RESET);
> +}
> +
> +static void nicvf_reclaim_rcv_queue(struct nicvf *nic,
> +				    struct queue_set *qs, int qidx)
> +{
> +	union nic_mbx mbx = {};
> +
> +	/* Make sure all packets in the pipeline are written back into mem */
> +	mbx.msg.msg = NIC_MBOX_MSG_RQ_SW_SYNC;
> +	nicvf_send_msg_to_pf(nic, &mbx);
> +}
> +
> +static void nicvf_reclaim_cmp_queue(struct nicvf *nic,
> +				    struct queue_set *qs, int qidx)
> +{
> +	/* Disable timer threshold (doesn't get reset upon CQ reset */
> +	nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2, qidx, 0);
> +	/* Disable completion queue */
> +	nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, 0);
> +	/* Reset completion queue */
> +	nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, NICVF_CQ_RESET);
> +}
> +
> +static void nicvf_reclaim_rbdr(struct nicvf *nic,
> +			       struct rbdr *rbdr, int qidx)
> +{
> +	u64 tmp, fifo_state;
> +	int timeout = 10;
> +
> +	/* Save head and tail pointers for feeing up buffers */
> +	rbdr->head = nicvf_queue_reg_read(nic,
> +					  NIC_QSET_RBDR_0_1_HEAD,
> +					  qidx) >> 3;
> +	rbdr->tail = nicvf_queue_reg_read(nic,
> +					  NIC_QSET_RBDR_0_1_TAIL,
> +					  qidx) >> 3;
> +
> +	/* If RBDR FIFO is in 'FAIL' state then do a reset first
> +	 * before relaiming.
> +	 */
> +	fifo_state = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_STATUS0, qidx);
> +	if (((fifo_state >> 62) & 0x03) == 0x3)
> +		nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG,
> +				      qidx, NICVF_RBDR_RESET);
> +
> +	/* Disable RBDR */
> +	nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 0);
> +	if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x00))
> +		return;
> +	while (1) {
> +		tmp = nicvf_queue_reg_read(nic,
> +					   NIC_QSET_RBDR_0_1_PREFETCH_STATUS,
> +					   qidx);
> +		if ((tmp & 0xFFFFFFFF) == ((tmp >> 32) & 0xFFFFFFFF))
> +			break;
> +		mdelay(2000);
> +		timeout--;
> +		if (!timeout) {
> +			printf("Failed polling on prefetch status\n");
> +			return;
> +		}
> +	}
> +	nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG,
> +			      qidx, NICVF_RBDR_RESET);
> +
> +	if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x02))
> +		return;
> +	nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 0x00);
> +	if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x00))
> +		return;
> +}
> +
> +/* Configures receive queue */
> +static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs,
> +				   int qidx, bool enable)
> +{
> +	union nic_mbx mbx = {};
> +	struct rcv_queue *rq;
> +	union {
> +		struct rq_cfg s;
> +		u64    u;
> +	} rq_cfg;
> +
> +	rq = &qs->rq[qidx];
> +	rq->enable = enable;
> +
> +	/* Disable receive queue */
> +	nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, 0);
> +
> +	if (!rq->enable) {
> +		nicvf_reclaim_rcv_queue(nic, qs, qidx);
> +		return;
> +	}
> +
> +	rq->cq_qs = qs->vnic_id;
> +	rq->cq_idx = qidx;
> +	rq->start_rbdr_qs = qs->vnic_id;
> +	rq->start_qs_rbdr_idx = qs->rbdr_cnt - 1;
> +	rq->cont_rbdr_qs = qs->vnic_id;
> +	rq->cont_qs_rbdr_idx = qs->rbdr_cnt - 1;
> +	/* all writes of RBDR data to be loaded into L2 Cache as well*/
> +	rq->caching = 1;
> +
> +	/* Send a mailbox msg to PF to config RQ */
> +	mbx.rq.msg = NIC_MBOX_MSG_RQ_CFG;
> +	mbx.rq.qs_num = qs->vnic_id;
> +	mbx.rq.rq_num = qidx;
> +	mbx.rq.cfg = (rq->caching << 26) | (rq->cq_qs << 19) |
> +			  (rq->cq_idx << 16) | (rq->cont_rbdr_qs << 9) |
> +			  (rq->cont_qs_rbdr_idx << 8) |
> +			  (rq->start_rbdr_qs << 1) | (rq->start_qs_rbdr_idx);
> +	nicvf_send_msg_to_pf(nic, &mbx);
> +
> +	mbx.rq.msg = NIC_MBOX_MSG_RQ_BP_CFG;
> +	mbx.rq.cfg = (1ULL << 63) | (1ULL << 62) | (qs->vnic_id << 0);
> +	nicvf_send_msg_to_pf(nic, &mbx);
> +
> +	/* RQ drop config
> +	 * Enable CQ drop to reserve sufficient CQEs for all tx packets
> +	 */
> +	mbx.rq.msg = NIC_MBOX_MSG_RQ_DROP_CFG;
> +	mbx.rq.cfg = (1ULL << 62) | (RQ_CQ_DROP << 8);
> +	nicvf_send_msg_to_pf(nic, &mbx);
> +	nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0, 0x00);
> +
> +	/* Enable Receive queue */
> +	rq_cfg.s.ena = 1;
> +	rq_cfg.s.tcp_ena = 0;
> +	nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, rq_cfg.u);
> +}
> +
> +void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs,
> +			    int qidx, bool enable)
> +{
> +	struct cmp_queue *cq;
> +	union {
> +		u64 u;
> +		struct cq_cfg s;
> +	} cq_cfg;
> +
> +	cq = &qs->cq[qidx];
> +	cq->enable = enable;
> +
> +	if (!cq->enable) {
> +		nicvf_reclaim_cmp_queue(nic, qs, qidx);
> +		return;
> +	}
> +
> +	/* Reset completion queue */
> +	nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, NICVF_CQ_RESET);
> +
> +	if (!cq->enable)
> +		return;
> +
> +	/* Set completion queue base address */
> +	nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_BASE,
> +			      qidx, (u64)(cq->dmem.phys_base));
> +
> +	/* Enable Completion queue */
> +	cq_cfg.s.ena = 1;
> +	cq_cfg.s.reset = 0;
> +	cq_cfg.s.caching = 0;
> +	cq_cfg.s.qsize = CMP_QSIZE;
> +	cq_cfg.s.avg_con = 0;
> +	nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, cq_cfg.u);
> +
> +	/* Set threshold value for interrupt generation */
> +	nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_THRESH, qidx, cq->thresh);
> +	nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2, qidx,
> +			      cq->intr_timer_thresh);
> +}
> +
> +/* Configures transmit queue */
> +static void nicvf_snd_queue_config(struct nicvf *nic, struct queue_set *qs,
> +				   int qidx, bool enable)
> +{
> +	union nic_mbx mbx = {};
> +	struct snd_queue *sq;
> +
> +	union {
> +		struct sq_cfg s;
> +		u64 u;
> +	} sq_cfg;
> +
> +	sq = &qs->sq[qidx];
> +	sq->enable = enable;
> +
> +	if (!sq->enable) {
> +		nicvf_reclaim_snd_queue(nic, qs, qidx);
> +		return;
> +	}
> +
> +	/* Reset send queue */
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, NICVF_SQ_RESET);
> +
> +	sq->cq_qs = qs->vnic_id;
> +	sq->cq_idx = qidx;
> +
> +	/* Send a mailbox msg to PF to config SQ */
> +	mbx.sq.msg = NIC_MBOX_MSG_SQ_CFG;
> +	mbx.sq.qs_num = qs->vnic_id;
> +	mbx.sq.sq_num = qidx;
> +	mbx.sq.sqs_mode = nic->sqs_mode;
> +	mbx.sq.cfg = (sq->cq_qs << 3) | sq->cq_idx;
> +	nicvf_send_msg_to_pf(nic, &mbx);
> +
> +	/* Set queue base address */
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_BASE,
> +			      qidx, (u64)(sq->dmem.phys_base));
> +
> +	/* Enable send queue  & set queue size */
> +	sq_cfg.s.ena = 1;
> +	sq_cfg.s.reset = 0;
> +	sq_cfg.s.ldwb = 0;
> +	sq_cfg.s.qsize = SND_QSIZE;
> +	sq_cfg.s.tstmp_bgx_intf = 0;
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg.u);
> +
> +	/* Set threshold value for interrupt generation */
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_THRESH, qidx, sq->thresh);
> +}
> +
> +/* Configures receive buffer descriptor ring */
> +static void nicvf_rbdr_config(struct nicvf *nic, struct queue_set *qs,
> +			      int qidx, bool enable)
> +{
> +	struct rbdr *rbdr;
> +	union {
> +		struct rbdr_cfg s;
> +		u64 u;
> +	} rbdr_cfg;
> +
> +	rbdr = &qs->rbdr[qidx];
> +	nicvf_reclaim_rbdr(nic, rbdr, qidx);
> +	if (!enable)
> +		return;
> +
> +	/* Set descriptor base address */
> +	nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_BASE,
> +			      qidx, (u64)(rbdr->dmem.phys_base));
> +
> +	/* Enable RBDR  & set queue size */
> +	/* Buffer size should be in multiples of 128 bytes */
> +	rbdr_cfg.s.ena = 1;
> +	rbdr_cfg.s.reset = 0;
> +	rbdr_cfg.s.ldwb = 0;
> +	rbdr_cfg.s.qsize = RBDR_SIZE;
> +	rbdr_cfg.s.avg_con = 0;
> +	rbdr_cfg.s.lines = rbdr->dma_size / 128;
> +	nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG,
> +			      qidx, rbdr_cfg.u);
> +
> +	/* Notify HW */
> +	nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_DOOR,
> +			      qidx, qs->rbdr_len - 1);
> +
> +	/* Set threshold value for interrupt generation */
> +	nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_THRESH,
> +			      qidx, rbdr->thresh - 1);
> +}
> +
> +/* Requests PF to assign and enable Qset */
> +void nicvf_qset_config(struct nicvf *nic, bool enable)
> +{
> +	union nic_mbx mbx = {};
> +	struct queue_set *qs = nic->qs;
> +	struct qs_cfg *qs_cfg;
> +
> +	if (!qs) {
> +		printf("Qset is still not allocated, don't init queues\n");
> +		return;
> +	}
> +
> +	qs->enable = enable;
> +	qs->vnic_id = nic->vf_id;
> +
> +	/* Send a mailbox msg to PF to config Qset */
> +	mbx.qs.msg = NIC_MBOX_MSG_QS_CFG;
> +	mbx.qs.num = qs->vnic_id;
> +#ifdef VNIC_MULTI_QSET_SUPPORT
> +	mbx.qs.sqs_count = nic->sqs_count;
> +#endif
> +
> +	mbx.qs.cfg = 0;
> +	qs_cfg = (struct qs_cfg *)&mbx.qs.cfg;
> +	if (qs->enable) {
> +		qs_cfg->ena = 1;
> +#ifdef __BIG_ENDIAN
> +		qs_cfg->be = 1;
> +#endif
> +		qs_cfg->vnic = qs->vnic_id;
> +	}
> +	nicvf_send_msg_to_pf(nic, &mbx);
> +}
> +
> +static void nicvf_free_resources(struct nicvf *nic)
> +{
> +	int qidx;
> +	struct queue_set *qs = nic->qs;
> +
> +	/* Free receive buffer descriptor ring */
> +	for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
> +		nicvf_free_rbdr(nic, &qs->rbdr[qidx]);
> +
> +	/* Free completion queue */
> +	for (qidx = 0; qidx < qs->cq_cnt; qidx++)
> +		nicvf_free_cmp_queue(nic, &qs->cq[qidx]);
> +
> +	/* Free send queue */
> +	for (qidx = 0; qidx < qs->sq_cnt; qidx++)
> +		nicvf_free_snd_queue(nic, &qs->sq[qidx]);
> +}
> +
> +static int nicvf_alloc_resources(struct nicvf *nic)
> +{
> +	int qidx;
> +	struct queue_set *qs = nic->qs;
> +
> +	/* Alloc receive buffer descriptor ring */
> +	for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) {
> +		if (nicvf_init_rbdr(nic, &qs->rbdr[qidx], qs->rbdr_len,
> +				    DMA_BUFFER_LEN))
> +			goto alloc_fail;
> +	}
> +
> +	/* Alloc send queue */
> +	for (qidx = 0; qidx < qs->sq_cnt; qidx++) {
> +		if (nicvf_init_snd_queue(nic, &qs->sq[qidx], qs->sq_len))
> +			goto alloc_fail;
> +	}
> +
> +	/* Alloc completion queue */
> +	for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
> +		if (nicvf_init_cmp_queue(nic, &qs->cq[qidx], qs->cq_len))
> +			goto alloc_fail;
> +	}
> +
> +	return 0;
> +alloc_fail:
> +	nicvf_free_resources(nic);
> +	return -1;
> +}
> +
> +int nicvf_set_qset_resources(struct nicvf *nic)
> +{
> +	struct queue_set *qs;
> +
> +	qs = calloc(1, sizeof(struct queue_set));
> +	if (!qs)
> +		return -1;
> +	nic->qs = qs;
> +
> +	/* Set count of each queue */
> +	qs->rbdr_cnt = RBDR_CNT;
> +	qs->rq_cnt = 1;
> +	qs->sq_cnt = SND_QUEUE_CNT;
> +	qs->cq_cnt = CMP_QUEUE_CNT;
> +
> +	/* Set queue lengths */
> +	qs->rbdr_len = RCV_BUF_COUNT;
> +	qs->sq_len = SND_QUEUE_LEN;
> +	qs->cq_len = CMP_QUEUE_LEN;
> +
> +	nic->rx_queues = qs->rq_cnt;
> +	nic->tx_queues = qs->sq_cnt;
> +
> +	return 0;
> +}
> +
> +int nicvf_config_data_transfer(struct nicvf *nic, bool enable)
> +{
> +	bool disable = false;
> +	struct queue_set *qs = nic->qs;
> +	int qidx;
> +
> +	if (!qs)
> +		return 0;
> +
> +	if (enable) {
> +		if (nicvf_alloc_resources(nic))
> +			return -1;
> +
> +		for (qidx = 0; qidx < qs->sq_cnt; qidx++)
> +			nicvf_snd_queue_config(nic, qs, qidx, enable);
> +		for (qidx = 0; qidx < qs->cq_cnt; qidx++)
> +			nicvf_cmp_queue_config(nic, qs, qidx, enable);
> +		for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
> +			nicvf_rbdr_config(nic, qs, qidx, enable);
> +		for (qidx = 0; qidx < qs->rq_cnt; qidx++)
> +			nicvf_rcv_queue_config(nic, qs, qidx, enable);
> +	} else {
> +		for (qidx = 0; qidx < qs->rq_cnt; qidx++)
> +			nicvf_rcv_queue_config(nic, qs, qidx, disable);
> +		for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
> +			nicvf_rbdr_config(nic, qs, qidx, disable);
> +		for (qidx = 0; qidx < qs->sq_cnt; qidx++)
> +			nicvf_snd_queue_config(nic, qs, qidx, disable);
> +		for (qidx = 0; qidx < qs->cq_cnt; qidx++)
> +			nicvf_cmp_queue_config(nic, qs, qidx, disable);
> +
> +		nicvf_free_resources(nic);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Get a free desc from SQ
> + * returns descriptor ponter & descriptor number
> + */
> +static int nicvf_get_sq_desc(struct snd_queue *sq, int desc_cnt)
> +{
> +	int qentry;
> +
> +	qentry = sq->tail;
> +	sq->free_cnt -= desc_cnt;
> +	sq->tail += desc_cnt;
> +	sq->tail &= (sq->dmem.q_len - 1);
> +
> +	return qentry;
> +}
> +
> +/* Free descriptor back to SQ for future use */
> +void nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt)
> +{
> +	sq->free_cnt += desc_cnt;
> +	sq->head += desc_cnt;
> +	sq->head &= (sq->dmem.q_len - 1);
> +}
> +
> +static int nicvf_get_nxt_sqentry(struct snd_queue *sq, int qentry)
> +{
> +	qentry++;
> +	qentry &= (sq->dmem.q_len - 1);
> +	return qentry;
> +}
> +
> +void nicvf_sq_enable(struct nicvf *nic, struct snd_queue *sq, int qidx)
> +{
> +	u64 sq_cfg;
> +
> +	sq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, qidx);
> +	sq_cfg |= NICVF_SQ_EN;
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg);
> +	/* Ring doorbell so that H/W restarts processing SQEs */
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR, qidx, 0);
> +}
> +
> +void nicvf_sq_disable(struct nicvf *nic, int qidx)
> +{
> +	u64 sq_cfg;
> +
> +	sq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, qidx);
> +	sq_cfg &= ~NICVF_SQ_EN;
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg);
> +}
> +
> +void nicvf_sq_free_used_descs(struct udevice *dev, struct snd_queue *sq,
> +			      int qidx)
> +{
> +	u64 head;
> +	struct nicvf *nic = dev_get_priv(dev);
> +	struct sq_hdr_subdesc *hdr;
> +
> +	head = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_HEAD, qidx) >> 4;
> +
> +	while (sq->head != head) {
> +		hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, sq->head);
> +		if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER) {
> +			nicvf_put_sq_desc(sq, 1);
> +			continue;
> +		}
> +		nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
> +	}
> +}
> +
> +/* Get the number of SQ descriptors needed to xmit this skb */
> +static int nicvf_sq_subdesc_required(struct nicvf *nic)
> +{
> +	int subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT;
> +
> +	return subdesc_cnt;
> +}
> +
> +/* Add SQ HEADER subdescriptor.
> + * First subdescriptor for every send descriptor.
> + */
> +static inline void
> +nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry,
> +			 int subdesc_cnt, void *pkt, size_t pkt_len)
> +{
> +	struct sq_hdr_subdesc *hdr;
> +
> +	hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, qentry);
> +	sq->skbuff[qentry] = (uintptr_t)pkt;
> +
> +	memset(hdr, 0, SND_QUEUE_DESC_SIZE);
> +	hdr->subdesc_type = SQ_DESC_TYPE_HEADER;
> +	/* Enable notification via CQE after processing SQE */
> +	hdr->post_cqe = 1;
> +	/* No of subdescriptors following this */
> +	hdr->subdesc_cnt = subdesc_cnt;
> +	hdr->tot_len = pkt_len;
> +
> +	flush_dcache_range((uintptr_t)hdr,
> +			   (uintptr_t)hdr + sizeof(struct sq_hdr_subdesc));
> +}
> +
> +/* SQ GATHER subdescriptor
> + * Must follow HDR descriptor
> + */
> +static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry,
> +					       size_t size, uintptr_t data)
> +{
> +	struct sq_gather_subdesc *gather;
> +
> +	qentry &= (sq->dmem.q_len - 1);
> +	gather = (struct sq_gather_subdesc *)GET_SQ_DESC(sq, qentry);
> +
> +	memset(gather, 0, SND_QUEUE_DESC_SIZE);
> +	gather->subdesc_type = SQ_DESC_TYPE_GATHER;
> +	gather->ld_type = NIC_SEND_LD_TYPE_E_LDD;
> +	gather->size = size;
> +	gather->addr = data;
> +
> +	flush_dcache_range((uintptr_t)gather,
> +			   (uintptr_t)gather + sizeof(struct sq_hdr_subdesc));
> +}
> +
> +/* Append an skb to a SQ for packet transfer. */
> +int nicvf_sq_append_pkt(struct nicvf *nic, void *pkt, size_t pkt_size)
> +{
> +	int subdesc_cnt;
> +	int sq_num = 0, qentry;
> +	struct queue_set *qs;
> +	struct snd_queue *sq;
> +
> +	qs = nic->qs;
> +	sq = &qs->sq[sq_num];
> +
> +	subdesc_cnt = nicvf_sq_subdesc_required(nic);
> +	if (subdesc_cnt > sq->free_cnt)
> +		goto append_fail;
> +
> +	qentry = nicvf_get_sq_desc(sq, subdesc_cnt);
> +
> +	/* Add SQ header subdesc */
> +	nicvf_sq_add_hdr_subdesc(nic, sq, qentry, subdesc_cnt - 1,
> +				 pkt, pkt_size);
> +
> +	/* Add SQ gather subdescs */
> +	qentry = nicvf_get_nxt_sqentry(sq, qentry);
> +	nicvf_sq_add_gather_subdesc(sq, qentry, pkt_size, (uintptr_t)(pkt));
> +
> +	flush_dcache_range((uintptr_t)pkt,
> +			   (uintptr_t)pkt + pkt_size);
> +
> +	/* make sure all memory stores are done before ringing doorbell */
> +	asm volatile ("dsb sy");
> +
> +	/* Inform HW to xmit new packet */
> +	nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR,
> +			      sq_num, subdesc_cnt);
> +	return 1;
> +
> +append_fail:
> +	printf("Not enough SQ descriptors to xmit pkt\n");
> +	return 0;
> +}
> +
> +static unsigned int frag_num(unsigned int i)
> +{
> +#ifdef __BIG_ENDIAN
> +	return (i & ~3) + 3 - (i & 3);
> +#else
> +	return i;
> +#endif
> +}
> +
> +void *nicvf_get_rcv_pkt(struct nicvf *nic, void *cq_desc, size_t *pkt_len)
> +{
> +	int frag;
> +	int payload_len = 0, tot_len;
> +	void *pkt = NULL, *pkt_buf = NULL, *buffer;
> +	struct cqe_rx_t *cqe_rx;
> +	struct rbdr *rbdr;
> +	struct rcv_queue *rq;
> +	struct queue_set *qs = nic->qs;
> +	u16 *rb_lens = NULL;
> +	u64 *rb_ptrs = NULL;
> +
> +	cqe_rx = (struct cqe_rx_t *)cq_desc;
> +
> +	rq = &qs->rq[cqe_rx->rq_idx];
> +	rbdr = &qs->rbdr[rq->start_qs_rbdr_idx];
> +	rb_lens = cq_desc + (3 * sizeof(u64)); /* Use offsetof */
> +	/* Except 88xx pass1 on all other chips CQE_RX2_S is added to
> +	 * CQE_RX at word6, hence buffer pointers move by word
> +	 *
> +	 * Use existing 'hw_tso' flag which will be set for all chips
> +	 * except 88xx pass1 instead of a additional cache line
> +	 * access (or miss) by using pci dev's revision.
> +	 */
> +	if (!nic->hw_tso)
> +		rb_ptrs = (void *)cqe_rx + (6 * sizeof(u64));
> +	else
> +		rb_ptrs = (void *)cqe_rx + (7 * sizeof(u64));
> +
> +	/*
> +	 * Figure out packet length to create packet buffer
> +	 */
> +	for (frag = 0; frag < cqe_rx->rb_cnt; frag++)
> +		payload_len += rb_lens[frag_num(frag)];
> +	*pkt_len = payload_len;
> +	/* round up size to 8 byte multiple */
> +	tot_len = (payload_len & (~0x7)) + 8;
> +	buffer = calloc(1, tot_len);
> +	if (!buffer) {
> +		printf("%s - Failed to allocate packet buffer\n", __func__);
> +		return NULL;
> +	}
> +	pkt_buf = buffer;
> +	debug("total pkt buf %p len %ld tot_len %d\n", pkt_buf, *pkt_len,
> +	      tot_len);
> +	for (frag = 0; frag < cqe_rx->rb_cnt; frag++) {
> +		payload_len = rb_lens[frag_num(frag)];
> +
> +		invalidate_dcache_range((uintptr_t)(*rb_ptrs),
> +					(uintptr_t)(*rb_ptrs) + rbdr->dma_size);
> +
> +		/* First fragment */
> +		*rb_ptrs = *rb_ptrs - cqe_rx->align_pad;
> +
> +		pkt = nicvf_rb_ptr_to_pkt(nic, *rb_ptrs);
> +
> +		invalidate_dcache_range((uintptr_t)pkt,
> +					(uintptr_t)pkt + payload_len);
> +
> +		if (cqe_rx->align_pad)
> +			pkt += cqe_rx->align_pad;
> +		debug("pkt_buf %p, pkt %p payload_len %d\n", pkt_buf, pkt,
> +		      payload_len);
> +		memcpy(buffer, pkt, payload_len);
> +		buffer += payload_len;
> +		/* Next buffer pointer */
> +		rb_ptrs++;
> +	}
> +	return pkt_buf;
> +}
> +
> +/* Clear interrupt */
> +void nicvf_clear_intr(struct nicvf *nic, int int_type, int q_idx)
> +{
> +	u64 reg_val = 0;
> +
> +	switch (int_type) {
> +	case NICVF_INTR_CQ:
> +		reg_val = ((1ULL << q_idx) << NICVF_INTR_CQ_SHIFT);
> +	break;
> +	case NICVF_INTR_SQ:
> +		reg_val = ((1ULL << q_idx) << NICVF_INTR_SQ_SHIFT);
> +	break;
> +	case NICVF_INTR_RBDR:
> +		reg_val = ((1ULL << q_idx) << NICVF_INTR_RBDR_SHIFT);
> +	break;
> +	case NICVF_INTR_PKT_DROP:
> +		reg_val = (1ULL << NICVF_INTR_PKT_DROP_SHIFT);
> +	break;
> +	case NICVF_INTR_TCP_TIMER:
> +		reg_val = (1ULL << NICVF_INTR_TCP_TIMER_SHIFT);
> +	break;
> +	case NICVF_INTR_MBOX:
> +		reg_val = (1ULL << NICVF_INTR_MBOX_SHIFT);
> +	break;
> +	case NICVF_INTR_QS_ERR:
> +		reg_val |= (1ULL << NICVF_INTR_QS_ERR_SHIFT);
> +	break;
> +	default:
> +		printf("Failed to clear interrupt: unknown type\n");
> +	break;
> +	}
> +
> +	nicvf_reg_write(nic, NIC_VF_INT, reg_val);
> +}
> +
> +void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx)
> +{
> +	struct rcv_queue *rq;
> +
> +#define GET_RQ_STATS(reg) \
> +	nicvf_reg_read(nic, NIC_QSET_RQ_0_7_STAT_0_1 |\
> +			    (rq_idx << NIC_Q_NUM_SHIFT) | ((reg) << 3))
> +
> +	rq = &nic->qs->rq[rq_idx];
> +	rq->stats.bytes = GET_RQ_STATS(RQ_SQ_STATS_OCTS);
> +	rq->stats.pkts = GET_RQ_STATS(RQ_SQ_STATS_PKTS);
> +}
> +
> +void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx)
> +{
> +	struct snd_queue *sq;
> +
> +#define GET_SQ_STATS(reg) \
> +	nicvf_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1 |\
> +			    (sq_idx << NIC_Q_NUM_SHIFT) | ((reg) << 3))
> +
> +	sq = &nic->qs->sq[sq_idx];
> +	sq->stats.bytes = GET_SQ_STATS(RQ_SQ_STATS_OCTS);
> +	sq->stats.pkts = GET_SQ_STATS(RQ_SQ_STATS_PKTS);
> +}
> +
> +/* Check for errors in the receive cmp.queue entry */
> +int nicvf_check_cqe_rx_errs(struct nicvf *nic,
> +			    struct cmp_queue *cq, void *cq_desc)
> +{
> +	struct cqe_rx_t *cqe_rx;
> +	struct cmp_queue_stats *stats = &cq->stats;
> +
> +	cqe_rx = (struct cqe_rx_t *)cq_desc;
> +	if (!cqe_rx->err_level && !cqe_rx->err_opcode) {
> +		stats->rx.errop.good++;
> +		return 0;
> +	}
> +
> +	switch (cqe_rx->err_level) {
> +	case CQ_ERRLVL_MAC:
> +		stats->rx.errlvl.mac_errs++;
> +	break;
> +	case CQ_ERRLVL_L2:
> +		stats->rx.errlvl.l2_errs++;
> +	break;
> +	case CQ_ERRLVL_L3:
> +		stats->rx.errlvl.l3_errs++;
> +	break;
> +	case CQ_ERRLVL_L4:
> +		stats->rx.errlvl.l4_errs++;
> +	break;
> +	}
> +
> +	switch (cqe_rx->err_opcode) {
> +	case CQ_RX_ERROP_RE_PARTIAL:
> +		stats->rx.errop.partial_pkts++;
> +	break;
> +	case CQ_RX_ERROP_RE_JABBER:
> +		stats->rx.errop.jabber_errs++;
> +	break;
> +	case CQ_RX_ERROP_RE_FCS:
> +		stats->rx.errop.fcs_errs++;
> +	break;
> +	case CQ_RX_ERROP_RE_TERMINATE:
> +		stats->rx.errop.terminate_errs++;
> +	break;
> +	case CQ_RX_ERROP_RE_RX_CTL:
> +		stats->rx.errop.bgx_rx_errs++;
> +	break;
> +	case CQ_RX_ERROP_PREL2_ERR:
> +		stats->rx.errop.prel2_errs++;
> +	break;
> +	case CQ_RX_ERROP_L2_FRAGMENT:
> +		stats->rx.errop.l2_frags++;
> +	break;
> +	case CQ_RX_ERROP_L2_OVERRUN:
> +		stats->rx.errop.l2_overruns++;
> +	break;
> +	case CQ_RX_ERROP_L2_PFCS:
> +		stats->rx.errop.l2_pfcs++;
> +	break;
> +	case CQ_RX_ERROP_L2_PUNY:
> +		stats->rx.errop.l2_puny++;
> +	break;
> +	case CQ_RX_ERROP_L2_MAL:
> +		stats->rx.errop.l2_hdr_malformed++;
> +	break;
> +	case CQ_RX_ERROP_L2_OVERSIZE:
> +		stats->rx.errop.l2_oversize++;
> +	break;
> +	case CQ_RX_ERROP_L2_UNDERSIZE:
> +		stats->rx.errop.l2_undersize++;
> +	break;
> +	case CQ_RX_ERROP_L2_LENMISM:
> +		stats->rx.errop.l2_len_mismatch++;
> +	break;
> +	case CQ_RX_ERROP_L2_PCLP:
> +		stats->rx.errop.l2_pclp++;
> +	break;
> +	case CQ_RX_ERROP_IP_NOT:
> +		stats->rx.errop.non_ip++;
> +	break;
> +	case CQ_RX_ERROP_IP_CSUM_ERR:
> +		stats->rx.errop.ip_csum_err++;
> +	break;
> +	case CQ_RX_ERROP_IP_MAL:
> +		stats->rx.errop.ip_hdr_malformed++;
> +	break;
> +	case CQ_RX_ERROP_IP_MALD:
> +		stats->rx.errop.ip_payload_malformed++;
> +	break;
> +	case CQ_RX_ERROP_IP_HOP:
> +		stats->rx.errop.ip_hop_errs++;
> +	break;
> +	case CQ_RX_ERROP_L3_ICRC:
> +		stats->rx.errop.l3_icrc_errs++;
> +	break;
> +	case CQ_RX_ERROP_L3_PCLP:
> +		stats->rx.errop.l3_pclp++;
> +	break;
> +	case CQ_RX_ERROP_L4_MAL:
> +		stats->rx.errop.l4_malformed++;
> +	break;
> +	case CQ_RX_ERROP_L4_CHK:
> +		stats->rx.errop.l4_csum_errs++;
> +	break;
> +	case CQ_RX_ERROP_UDP_LEN:
> +		stats->rx.errop.udp_len_err++;
> +	break;
> +	case CQ_RX_ERROP_L4_PORT:
> +		stats->rx.errop.bad_l4_port++;
> +	break;
> +	case CQ_RX_ERROP_TCP_FLAG:
> +		stats->rx.errop.bad_tcp_flag++;
> +	break;
> +	case CQ_RX_ERROP_TCP_OFFSET:
> +		stats->rx.errop.tcp_offset_errs++;
> +	break;
> +	case CQ_RX_ERROP_L4_PCLP:
> +		stats->rx.errop.l4_pclp++;
> +	break;
> +	case CQ_RX_ERROP_RBDR_TRUNC:
> +		stats->rx.errop.pkt_truncated++;
> +	break;
> +	}
> +
> +	return 1;
> +}
> +
> +/* Check for errors in the send cmp.queue entry */
> +int nicvf_check_cqe_tx_errs(struct nicvf *nic,
> +			    struct cmp_queue *cq, void *cq_desc)
> +{
> +	struct cqe_send_t *cqe_tx;
> +	struct cmp_queue_stats *stats = &cq->stats;
> +
> +	cqe_tx = (struct cqe_send_t *)cq_desc;
> +	switch (cqe_tx->send_status) {
> +	case CQ_TX_ERROP_GOOD:
> +		stats->tx.good++;
> +		return 0;
> +	break;
> +	case CQ_TX_ERROP_DESC_FAULT:
> +		stats->tx.desc_fault++;
> +	break;
> +	case CQ_TX_ERROP_HDR_CONS_ERR:
> +		stats->tx.hdr_cons_err++;
> +	break;
> +	case CQ_TX_ERROP_SUBDC_ERR:
> +		stats->tx.subdesc_err++;
> +	break;
> +	case CQ_TX_ERROP_IMM_SIZE_OFLOW:
> +		stats->tx.imm_size_oflow++;
> +	break;
> +	case CQ_TX_ERROP_DATA_SEQUENCE_ERR:
> +		stats->tx.data_seq_err++;
> +	break;
> +	case CQ_TX_ERROP_MEM_SEQUENCE_ERR:
> +		stats->tx.mem_seq_err++;
> +	break;
> +	case CQ_TX_ERROP_LOCK_VIOL:
> +		stats->tx.lock_viol++;
> +	break;
> +	case CQ_TX_ERROP_DATA_FAULT:
> +		stats->tx.data_fault++;
> +	break;
> +	case CQ_TX_ERROP_TSTMP_CONFLICT:
> +		stats->tx.tstmp_conflict++;
> +	break;
> +	case CQ_TX_ERROP_TSTMP_TIMEOUT:
> +		stats->tx.tstmp_timeout++;
> +	break;
> +	case CQ_TX_ERROP_MEM_FAULT:
> +		stats->tx.mem_fault++;
> +	break;
> +	case CQ_TX_ERROP_CK_OVERLAP:
> +		stats->tx.csum_overlap++;
> +	break;
> +	case CQ_TX_ERROP_CK_OFLOW:
> +		stats->tx.csum_overflow++;
> +	break;
> +	}
> +
> +	return 1;
> +}
> diff --git a/drivers/net/octeontx/nicvf_queues.h b/drivers/net/octeontx/nicvf_queues.h
> new file mode 100644
> index 0000000000..833b2a1dd4
> --- /dev/null
> +++ b/drivers/net/octeontx/nicvf_queues.h
> @@ -0,0 +1,353 @@
> +/* SPDX-License-Identifier:    GPL-2.0
> + *
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#ifndef NICVF_QUEUES_H
> +#define NICVF_QUEUES_H
> +
> +#include "q_struct.h"
> +
> +#define MAX_QUEUE_SET			128
> +#define MAX_RCV_QUEUES_PER_QS		8
> +#define MAX_RCV_BUF_DESC_RINGS_PER_QS	2
> +#define MAX_SND_QUEUES_PER_QS		8
> +#define MAX_CMP_QUEUES_PER_QS		8
> +
> +/* VF's queue interrupt ranges */
> +#define	NICVF_INTR_ID_CQ		0
> +#define	NICVF_INTR_ID_SQ		8
> +#define	NICVF_INTR_ID_RBDR		16
> +#define	NICVF_INTR_ID_MISC		18
> +#define	NICVF_INTR_ID_QS_ERR		19
> +
> +#define RBDR_SIZE0		0ULL /* 8K entries */
> +#define RBDR_SIZE1		1ULL /* 16K entries */
> +#define RBDR_SIZE2		2ULL /* 32K entries */
> +#define RBDR_SIZE3		3ULL /* 64K entries */
> +#define RBDR_SIZE4		4ULL /* 126K entries */
> +#define RBDR_SIZE5		5ULL /* 256K entries */
> +#define RBDR_SIZE6		6ULL /* 512K entries */
> +
> +#define SND_QUEUE_SIZE0		0ULL /* 1K entries */
> +#define SND_QUEUE_SIZE1		1ULL /* 2K entries */
> +#define SND_QUEUE_SIZE2		2ULL /* 4K entries */
> +#define SND_QUEUE_SIZE3		3ULL /* 8K entries */
> +#define SND_QUEUE_SIZE4		4ULL /* 16K entries */
> +#define SND_QUEUE_SIZE5		5ULL /* 32K entries */
> +#define SND_QUEUE_SIZE6		6ULL /* 64K entries */
> +
> +#define CMP_QUEUE_SIZE0		0ULL /* 1K entries */
> +#define CMP_QUEUE_SIZE1		1ULL /* 2K entries */
> +#define CMP_QUEUE_SIZE2		2ULL /* 4K entries */
> +#define CMP_QUEUE_SIZE3		3ULL /* 8K entries */
> +#define CMP_QUEUE_SIZE4		4ULL /* 16K entries */
> +#define CMP_QUEUE_SIZE5		5ULL /* 32K entries */
> +#define CMP_QUEUE_SIZE6		6ULL /* 64K entries */
> +
> +/* Default queue count per QS, its lengths and threshold values */
> +#define RBDR_CNT			1
> +#define RCV_QUEUE_CNT		1
> +#define SND_QUEUE_CNT		1
> +#define CMP_QUEUE_CNT		1 /* Max of RCV and SND qcount */
> +
> +#define SND_QSIZE		SND_QUEUE_SIZE0
> +#define SND_QUEUE_LEN		BIT_ULL((SND_QSIZE + 10))
> +#define SND_QUEUE_THRESH	2ULL
> +#define MIN_SQ_DESC_PER_PKT_XMIT	2
> +#define MAX_CQE_PER_PKT_XMIT		2
> +
> +#define CMP_QSIZE		CMP_QUEUE_SIZE0
> +#define CMP_QUEUE_LEN		BIT_ULL((CMP_QSIZE + 10))
> +#define CMP_QUEUE_CQE_THRESH	0
> +#define CMP_QUEUE_TIMER_THRESH	1 /* 1 ms */
> +
> +#define RBDR_SIZE		RBDR_SIZE0
> +#define RCV_BUF_COUNT		BIT_ULL((RBDR_SIZE + 13))
> +#define RBDR_THRESH		(RCV_BUF_COUNT / 2)
> +#define DMA_BUFFER_LEN		2048 /* In multiples of 128bytes */
> +#define RCV_FRAG_LEN		DMA_BUFFER_LEN
> +
> +#define MAX_CQES_FOR_TX		((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) *\
> +				 MAX_CQE_PER_PKT_XMIT)
> +#define RQ_CQ_DROP		((CMP_QUEUE_LEN - MAX_CQES_FOR_TX) / 256)
> +
> +/* Descriptor size */
> +#define SND_QUEUE_DESC_SIZE	16   /* 128 bits */
> +#define CMP_QUEUE_DESC_SIZE	512
> +
> +/* Buffer / descriptor alignments */
> +#define NICVF_RCV_BUF_ALIGN		7
> +#define NICVF_RCV_BUF_ALIGN_BYTES	BIT_ULL(NICVF_RCV_BUF_ALIGN)
> +#define NICVF_CQ_BASE_ALIGN_BYTES	512  /* 9 bits */
> +#define NICVF_SQ_BASE_ALIGN_BYTES	128  /* 7 bits */
> +
> +#define NICVF_ALIGNED_ADDR(ADDR, ALIGN_BYTES)	ALIGN(ADDR, ALIGN_BYTES)
> +
> +/* Queue enable/disable */
> +#define NICVF_SQ_EN            BIT_ULL(19)
> +
> +/* Queue reset */
> +#define NICVF_CQ_RESET		BIT_ULL(41)
> +#define NICVF_SQ_RESET		BIT_ULL(17)
> +#define NICVF_RBDR_RESET	BIT_ULL(43)
> +
> +enum CQ_RX_ERRLVL_E {
> +	CQ_ERRLVL_MAC,
> +	CQ_ERRLVL_L2,
> +	CQ_ERRLVL_L3,
> +	CQ_ERRLVL_L4,
> +};
> +
> +enum CQ_RX_ERROP_E {
> +	CQ_RX_ERROP_RE_NONE = 0x0,
> +	CQ_RX_ERROP_RE_PARTIAL = 0x1,
> +	CQ_RX_ERROP_RE_JABBER = 0x2,
> +	CQ_RX_ERROP_RE_FCS = 0x7,
> +	CQ_RX_ERROP_RE_TERMINATE = 0x9,
> +	CQ_RX_ERROP_RE_RX_CTL = 0xb,
> +	CQ_RX_ERROP_PREL2_ERR = 0x1f,
> +	CQ_RX_ERROP_L2_FRAGMENT = 0x20,
> +	CQ_RX_ERROP_L2_OVERRUN = 0x21,
> +	CQ_RX_ERROP_L2_PFCS = 0x22,
> +	CQ_RX_ERROP_L2_PUNY = 0x23,
> +	CQ_RX_ERROP_L2_MAL = 0x24,
> +	CQ_RX_ERROP_L2_OVERSIZE = 0x25,
> +	CQ_RX_ERROP_L2_UNDERSIZE = 0x26,
> +	CQ_RX_ERROP_L2_LENMISM = 0x27,
> +	CQ_RX_ERROP_L2_PCLP = 0x28,
> +	CQ_RX_ERROP_IP_NOT = 0x41,
> +	CQ_RX_ERROP_IP_CSUM_ERR = 0x42,
> +	CQ_RX_ERROP_IP_MAL = 0x43,
> +	CQ_RX_ERROP_IP_MALD = 0x44,
> +	CQ_RX_ERROP_IP_HOP = 0x45,
> +	CQ_RX_ERROP_L3_ICRC = 0x46,
> +	CQ_RX_ERROP_L3_PCLP = 0x47,
> +	CQ_RX_ERROP_L4_MAL = 0x61,
> +	CQ_RX_ERROP_L4_CHK = 0x62,
> +	CQ_RX_ERROP_UDP_LEN = 0x63,
> +	CQ_RX_ERROP_L4_PORT = 0x64,
> +	CQ_RX_ERROP_TCP_FLAG = 0x65,
> +	CQ_RX_ERROP_TCP_OFFSET = 0x66,
> +	CQ_RX_ERROP_L4_PCLP = 0x67,
> +	CQ_RX_ERROP_RBDR_TRUNC = 0x70,
> +};
> +
> +enum CQ_TX_ERROP_E {
> +	CQ_TX_ERROP_GOOD = 0x0,
> +	CQ_TX_ERROP_DESC_FAULT = 0x10,
> +	CQ_TX_ERROP_HDR_CONS_ERR = 0x11,
> +	CQ_TX_ERROP_SUBDC_ERR = 0x12,
> +	CQ_TX_ERROP_IMM_SIZE_OFLOW = 0x80,
> +	CQ_TX_ERROP_DATA_SEQUENCE_ERR = 0x81,
> +	CQ_TX_ERROP_MEM_SEQUENCE_ERR = 0x82,
> +	CQ_TX_ERROP_LOCK_VIOL = 0x83,
> +	CQ_TX_ERROP_DATA_FAULT = 0x84,
> +	CQ_TX_ERROP_TSTMP_CONFLICT = 0x85,
> +	CQ_TX_ERROP_TSTMP_TIMEOUT = 0x86,
> +	CQ_TX_ERROP_MEM_FAULT = 0x87,
> +	CQ_TX_ERROP_CK_OVERLAP = 0x88,
> +	CQ_TX_ERROP_CK_OFLOW = 0x89,
> +	CQ_TX_ERROP_ENUM_LAST = 0x8a,
> +};
> +
> +struct cmp_queue_stats {
> +	struct rx_stats {
> +		struct {
> +			u64 mac_errs;
> +			u64 l2_errs;
> +			u64 l3_errs;
> +			u64 l4_errs;
> +		} errlvl;
> +		struct {
> +			u64 good;
> +			u64 partial_pkts;
> +			u64 jabber_errs;
> +			u64 fcs_errs;
> +			u64 terminate_errs;
> +			u64 bgx_rx_errs;
> +			u64 prel2_errs;
> +			u64 l2_frags;
> +			u64 l2_overruns;
> +			u64 l2_pfcs;
> +			u64 l2_puny;
> +			u64 l2_hdr_malformed;
> +			u64 l2_oversize;
> +			u64 l2_undersize;
> +			u64 l2_len_mismatch;
> +			u64 l2_pclp;
> +			u64 non_ip;
> +			u64 ip_csum_err;
> +			u64 ip_hdr_malformed;
> +			u64 ip_payload_malformed;
> +			u64 ip_hop_errs;
> +			u64 l3_icrc_errs;
> +			u64 l3_pclp;
> +			u64 l4_malformed;
> +			u64 l4_csum_errs;
> +			u64 udp_len_err;
> +			u64 bad_l4_port;
> +			u64 bad_tcp_flag;
> +			u64 tcp_offset_errs;
> +			u64 l4_pclp;
> +			u64 pkt_truncated;
> +		} errop;
> +	} rx;
> +	struct tx_stats {
> +		u64 good;
> +		u64 desc_fault;
> +		u64 hdr_cons_err;
> +		u64 subdesc_err;
> +		u64 imm_size_oflow;
> +		u64 data_seq_err;
> +		u64 mem_seq_err;
> +		u64 lock_viol;
> +		u64 data_fault;
> +		u64 tstmp_conflict;
> +		u64 tstmp_timeout;
> +		u64 mem_fault;
> +		u64 csum_overlap;
> +		u64 csum_overflow;
> +	} tx;
> +};
> +
> +enum RQ_SQ_STATS {
> +	RQ_SQ_STATS_OCTS,
> +	RQ_SQ_STATS_PKTS,
> +};
> +
> +struct rx_tx_queue_stats {
> +	u64	bytes;
> +	u64	pkts;
> +};
> +
> +struct q_desc_mem {
> +	uintptr_t	dma;
> +	u64	size;
> +	u16	q_len;
> +	uintptr_t	phys_base;
> +	void		*base;
> +	void		*unalign_base;
> +	bool		allocated;
> +};
> +
> +struct rbdr {
> +	bool		enable;
> +	u32	dma_size;
> +	u32	thresh;      /* Threshold level for interrupt */
> +	void		*desc;
> +	u32	head;
> +	u32	tail;
> +	struct		q_desc_mem   dmem;
> +	uintptr_t	buf_mem;
> +	uintptr_t	buffers;
> +};
> +
> +struct rcv_queue {
> +	bool		enable;
> +	struct	rbdr	*rbdr_start;
> +	struct	rbdr	*rbdr_cont;
> +	bool		en_tcp_reassembly;
> +	u8		cq_qs;  /* CQ's QS to which this RQ is assigned */
> +	u8		cq_idx; /* CQ index (0 to 7) in the QS */
> +	u8		cont_rbdr_qs;      /* Continue buffer ptrs - QS num */
> +	u8		cont_qs_rbdr_idx;  /* RBDR idx in the cont QS */
> +	u8		start_rbdr_qs;     /* First buffer ptrs - QS num */
> +	u8		start_qs_rbdr_idx; /* RBDR idx in the above QS */
> +	u8         caching;
> +	struct		rx_tx_queue_stats stats;
> +};
> +
> +struct cmp_queue {
> +	bool		enable;
> +	u16	intr_timer_thresh;
> +	u16	thresh;
> +	void		*desc;
> +	struct q_desc_mem   dmem;
> +	struct cmp_queue_stats	stats;
> +};
> +
> +struct snd_queue {
> +	bool		enable;
> +	u8		cq_qs;  /* CQ's QS to which this SQ is pointing */
> +	u8		cq_idx; /* CQ index (0 to 7) in the above QS */
> +	u16	thresh;
> +	u32	free_cnt;
> +	u32	head;
> +	u32	tail;
> +	u64	*skbuff;
> +	void		*desc;
> +	struct q_desc_mem   dmem;
> +	struct rx_tx_queue_stats stats;
> +};
> +
> +struct queue_set {
> +	bool		enable;
> +	bool		be_en;
> +	u8		vnic_id;
> +	u8		rq_cnt;
> +	u8		cq_cnt;
> +	u64	cq_len;
> +	u8		sq_cnt;
> +	u64	sq_len;
> +	u8		rbdr_cnt;
> +	u64	rbdr_len;
> +	struct	rcv_queue	rq[MAX_RCV_QUEUES_PER_QS];
> +	struct	cmp_queue	cq[MAX_CMP_QUEUES_PER_QS];
> +	struct	snd_queue	sq[MAX_SND_QUEUES_PER_QS];
> +	struct	rbdr		rbdr[MAX_RCV_BUF_DESC_RINGS_PER_QS];
> +};
> +
> +#define GET_RBDR_DESC(RING, idx)\
> +		(&(((struct rbdr_entry_t *)((RING)->desc))[idx]))
> +#define GET_SQ_DESC(RING, idx)\
> +		(&(((struct sq_hdr_subdesc *)((RING)->desc))[idx]))
> +#define GET_CQ_DESC(RING, idx)\
> +		(&(((union cq_desc_t *)((RING)->desc))[idx]))
> +
> +/* CQ status bits */
> +#define	CQ_WR_FULL	BIT(26)
> +#define	CQ_WR_DISABLE	BIT(25)
> +#define	CQ_WR_FAULT	BIT(24)
> +#define	CQ_CQE_COUNT	(0xFFFF << 0)
> +
> +#define	CQ_ERR_MASK	(CQ_WR_FULL | CQ_WR_DISABLE | CQ_WR_FAULT)
> +
> +int nicvf_set_qset_resources(struct nicvf *nic);
> +int nicvf_config_data_transfer(struct nicvf *nic, bool enable);
> +void nicvf_qset_config(struct nicvf *nic, bool enable);
> +void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs,
> +			    int qidx, bool enable);
> +
> +void nicvf_sq_enable(struct nicvf *nic, struct snd_queue *sq, int qidx);
> +void nicvf_sq_disable(struct nicvf *nic, int qidx);
> +void nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt);
> +void nicvf_sq_free_used_descs(struct udevice *dev,
> +			      struct snd_queue *sq, int qidx);
> +int nicvf_sq_append_pkt(struct nicvf *nic, void *pkt, size_t pkt_len);
> +
> +void *nicvf_get_rcv_pkt(struct nicvf *nic, void *cq_desc, size_t *pkt_len);
> +void nicvf_refill_rbdr(struct nicvf *nic);
> +
> +void nicvf_enable_intr(struct nicvf *nic, int int_type, int q_idx);
> +void nicvf_disable_intr(struct nicvf *nic, int int_type, int q_idx);
> +void nicvf_clear_intr(struct nicvf *nic, int int_type, int q_idx);
> +int nicvf_is_intr_enabled(struct nicvf *nic, int int_type, int q_idx);
> +
> +/* Register access APIs */
> +void nicvf_reg_write(struct nicvf *nic, u64 offset, u64 val);
> +u64 nicvf_reg_read(struct nicvf *nic, u64 offset);
> +void nicvf_qset_reg_write(struct nicvf *nic, u64 offset, u64 val);
> +u64 nicvf_qset_reg_read(struct nicvf *nic, u64 offset);
> +void nicvf_queue_reg_write(struct nicvf *nic, u64 offset,
> +			   u64 qidx, u64 val);
> +u64 nicvf_queue_reg_read(struct nicvf *nic, u64 offset, u64 qidx);
> +
> +/* Stats */
> +void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx);
> +void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx);
> +int nicvf_check_cqe_rx_errs(struct nicvf *nic,
> +			    struct cmp_queue *cq, void *cq_desc);
> +int nicvf_check_cqe_tx_errs(struct nicvf *nic,
> +			    struct cmp_queue *cq, void *cq_desc);
> +#endif /* NICVF_QUEUES_H */
> diff --git a/drivers/net/octeontx/q_struct.h b/drivers/net/octeontx/q_struct.h
> new file mode 100644
> index 0000000000..87abb132f5
> --- /dev/null
> +++ b/drivers/net/octeontx/q_struct.h
> @@ -0,0 +1,695 @@
> +/* SPDX-License-Identifier:    GPL-2.0
> + *
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#ifndef Q_STRUCT_H
> +#define Q_STRUCT_H
> +
> +/* Load transaction types for reading segment bytes specified by
> + * NIC_SEND_GATHER_S[LD_TYPE].
> + */
> +enum nic_send_ld_type_e {
> +	NIC_SEND_LD_TYPE_E_LDD = 0x0,
> +	NIC_SEND_LD_TYPE_E_LDT = 0x1,
> +	NIC_SEND_LD_TYPE_E_LDWB = 0x2,
> +	NIC_SEND_LD_TYPE_E_ENUM_LAST = 0x3,
> +};
> +
> +enum ether_type_algorithm {
> +	ETYPE_ALG_NONE = 0x0,
> +	ETYPE_ALG_SKIP = 0x1,
> +	ETYPE_ALG_ENDPARSE = 0x2,
> +	ETYPE_ALG_VLAN = 0x3,
> +	ETYPE_ALG_VLAN_STRIP = 0x4,
> +};
> +
> +enum layer3_type {
> +	L3TYPE_NONE = 0x00,
> +	L3TYPE_GRH = 0x01,
> +	L3TYPE_IPV4 = 0x04,
> +	L3TYPE_IPV4_OPTIONS = 0x05,
> +	L3TYPE_IPV6 = 0x06,
> +	L3TYPE_IPV6_OPTIONS = 0x07,
> +	L3TYPE_ET_STOP = 0x0D,
> +	L3TYPE_OTHER = 0x0E,
> +};
> +
> +enum layer4_type {
> +	L4TYPE_NONE = 0x00,
> +	L4TYPE_IPSEC_ESP = 0x01,
> +	L4TYPE_IPFRAG = 0x02,
> +	L4TYPE_IPCOMP = 0x03,
> +	L4TYPE_TCP = 0x04,
> +	L4TYPE_UDP = 0x05,
> +	L4TYPE_SCTP = 0x06,
> +	L4TYPE_GRE = 0x07,
> +	L4TYPE_ROCE_BTH = 0x08,
> +	L4TYPE_OTHER = 0x0E,
> +};
> +
> +/* CPI and RSSI configuration */
> +enum cpi_algorithm_type {
> +	CPI_ALG_NONE = 0x0,
> +	CPI_ALG_VLAN = 0x1,
> +	CPI_ALG_VLAN16 = 0x2,
> +	CPI_ALG_DIFF = 0x3,
> +};
> +
> +enum rss_algorithm_type {
> +	RSS_ALG_NONE = 0x00,
> +	RSS_ALG_PORT = 0x01,
> +	RSS_ALG_IP = 0x02,
> +	RSS_ALG_TCP_IP = 0x03,
> +	RSS_ALG_UDP_IP = 0x04,
> +	RSS_ALG_SCTP_IP = 0x05,
> +	RSS_ALG_GRE_IP = 0x06,
> +	RSS_ALG_ROCE = 0x07,
> +};
> +
> +enum rss_hash_cfg {
> +	RSS_HASH_L2ETC = 0x00,
> +	RSS_HASH_IP = 0x01,
> +	RSS_HASH_TCP = 0x02,
> +	RSS_TCP_SYN_DIS = 0x03,
> +	RSS_HASH_UDP = 0x04,
> +	RSS_HASH_L4ETC = 0x05,
> +	RSS_HASH_ROCE = 0x06,
> +	RSS_L3_BIDI = 0x07,
> +	RSS_L4_BIDI = 0x08,
> +};
> +
> +/* Completion queue entry types */
> +enum cqe_type {
> +	CQE_TYPE_INVALID = 0x0,
> +	CQE_TYPE_RX = 0x2,
> +	CQE_TYPE_RX_SPLIT = 0x3,
> +	CQE_TYPE_RX_TCP = 0x4,
> +	CQE_TYPE_SEND = 0x8,
> +	CQE_TYPE_SEND_PTP = 0x9,
> +};
> +
> +enum cqe_rx_tcp_status {
> +	CQE_RX_STATUS_VALID_TCP_CNXT = 0x00,
> +	CQE_RX_STATUS_INVALID_TCP_CNXT = 0x0F,
> +};
> +
> +enum cqe_send_status {
> +	CQE_SEND_STATUS_GOOD = 0x00,
> +	CQE_SEND_STATUS_DESC_FAULT = 0x01,
> +	CQE_SEND_STATUS_HDR_CONS_ERR = 0x11,
> +	CQE_SEND_STATUS_SUBDESC_ERR = 0x12,
> +	CQE_SEND_STATUS_IMM_SIZE_OFLOW = 0x80,
> +	CQE_SEND_STATUS_CRC_SEQ_ERR = 0x81,
> +	CQE_SEND_STATUS_DATA_SEQ_ERR = 0x82,
> +	CQE_SEND_STATUS_MEM_SEQ_ERR = 0x83,
> +	CQE_SEND_STATUS_LOCK_VIOL = 0x84,
> +	CQE_SEND_STATUS_LOCK_UFLOW = 0x85,
> +	CQE_SEND_STATUS_DATA_FAULT = 0x86,
> +	CQE_SEND_STATUS_TSTMP_CONFLICT = 0x87,
> +	CQE_SEND_STATUS_TSTMP_TIMEOUT = 0x88,
> +	CQE_SEND_STATUS_MEM_FAULT = 0x89,
> +	CQE_SEND_STATUS_CSUM_OVERLAP = 0x8A,
> +	CQE_SEND_STATUS_CSUM_OVERFLOW = 0x8B,
> +};
> +
> +enum cqe_rx_tcp_end_reason {
> +	CQE_RX_TCP_END_FIN_FLAG_DET = 0,
> +	CQE_RX_TCP_END_INVALID_FLAG = 1,
> +	CQE_RX_TCP_END_TIMEOUT = 2,
> +	CQE_RX_TCP_END_OUT_OF_SEQ = 3,
> +	CQE_RX_TCP_END_PKT_ERR = 4,
> +	CQE_RX_TCP_END_QS_DISABLED = 0x0F,
> +};
> +
> +/* Packet protocol level error enumeration */
> +enum cqe_rx_err_level {
> +	CQE_RX_ERRLVL_RE = 0x0,
> +	CQE_RX_ERRLVL_L2 = 0x1,
> +	CQE_RX_ERRLVL_L3 = 0x2,
> +	CQE_RX_ERRLVL_L4 = 0x3,
> +};
> +
> +/* Packet protocol level error type enumeration */
> +enum cqe_rx_err_opcode {
> +	CQE_RX_ERR_RE_NONE = 0x0,
> +	CQE_RX_ERR_RE_PARTIAL = 0x1,
> +	CQE_RX_ERR_RE_JABBER = 0x2,
> +	CQE_RX_ERR_RE_FCS = 0x7,
> +	CQE_RX_ERR_RE_TERMINATE = 0x9,
> +	CQE_RX_ERR_RE_RX_CTL = 0xb,
> +	CQE_RX_ERR_PREL2_ERR = 0x1f,
> +	CQE_RX_ERR_L2_FRAGMENT = 0x20,
> +	CQE_RX_ERR_L2_OVERRUN = 0x21,
> +	CQE_RX_ERR_L2_PFCS = 0x22,
> +	CQE_RX_ERR_L2_PUNY = 0x23,
> +	CQE_RX_ERR_L2_MAL = 0x24,
> +	CQE_RX_ERR_L2_OVERSIZE = 0x25,
> +	CQE_RX_ERR_L2_UNDERSIZE = 0x26,
> +	CQE_RX_ERR_L2_LENMISM = 0x27,
> +	CQE_RX_ERR_L2_PCLP = 0x28,
> +	CQE_RX_ERR_IP_NOT = 0x41,
> +	CQE_RX_ERR_IP_CHK = 0x42,
> +	CQE_RX_ERR_IP_MAL = 0x43,
> +	CQE_RX_ERR_IP_MALD = 0x44,
> +	CQE_RX_ERR_IP_HOP = 0x45,
> +	CQE_RX_ERR_L3_ICRC = 0x46,
> +	CQE_RX_ERR_L3_PCLP = 0x47,
> +	CQE_RX_ERR_L4_MAL = 0x61,
> +	CQE_RX_ERR_L4_CHK = 0x62,
> +	CQE_RX_ERR_UDP_LEN = 0x63,
> +	CQE_RX_ERR_L4_PORT = 0x64,
> +	CQE_RX_ERR_TCP_FLAG = 0x65,
> +	CQE_RX_ERR_TCP_OFFSET = 0x66,
> +	CQE_RX_ERR_L4_PCLP = 0x67,
> +	CQE_RX_ERR_RBDR_TRUNC = 0x70,
> +};
> +
> +struct cqe_rx_t {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64   cqe_type:4; /* W0 */
> +	u64   stdn_fault:1;
> +	u64   rsvd0:1;
> +	u64   rq_qs:7;
> +	u64   rq_idx:3;
> +	u64   rsvd1:12;
> +	u64   rss_alg:4;
> +	u64   rsvd2:4;
> +	u64   rb_cnt:4;
> +	u64   vlan_found:1;
> +	u64   vlan_stripped:1;
> +	u64   vlan2_found:1;
> +	u64   vlan2_stripped:1;
> +	u64   l4_type:4;
> +	u64   l3_type:4;
> +	u64   l2_present:1;
> +	u64   err_level:3;
> +	u64   err_opcode:8;
> +
> +	u64   pkt_len:16; /* W1 */
> +	u64   l2_ptr:8;
> +	u64   l3_ptr:8;
> +	u64   l4_ptr:8;
> +	u64   cq_pkt_len:8;
> +	u64   align_pad:3;
> +	u64   rsvd3:1;
> +	u64   chan:12;
> +
> +	u64   rss_tag:32; /* W2 */
> +	u64   vlan_tci:16;
> +	u64   vlan_ptr:8;
> +	u64   vlan2_ptr:8;
> +
> +	u64   rb3_sz:16; /* W3 */
> +	u64   rb2_sz:16;
> +	u64   rb1_sz:16;
> +	u64   rb0_sz:16;
> +
> +	u64   rb7_sz:16; /* W4 */
> +	u64   rb6_sz:16;
> +	u64   rb5_sz:16;
> +	u64   rb4_sz:16;
> +
> +	u64   rb11_sz:16; /* W5 */
> +	u64   rb10_sz:16;
> +	u64   rb9_sz:16;
> +	u64   rb8_sz:16;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64   err_opcode:8;
> +	u64   err_level:3;
> +	u64   l2_present:1;
> +	u64   l3_type:4;
> +	u64   l4_type:4;
> +	u64   vlan2_stripped:1;
> +	u64   vlan2_found:1;
> +	u64   vlan_stripped:1;
> +	u64   vlan_found:1;
> +	u64   rb_cnt:4;
> +	u64   rsvd2:4;
> +	u64   rss_alg:4;
> +	u64   rsvd1:12;
> +	u64   rq_idx:3;
> +	u64   rq_qs:7;
> +	u64   rsvd0:1;
> +	u64   stdn_fault:1;
> +	u64   cqe_type:4; /* W0 */
> +	u64   chan:12;
> +	u64   rsvd3:1;
> +	u64   align_pad:3;
> +	u64   cq_pkt_len:8;
> +	u64   l4_ptr:8;
> +	u64   l3_ptr:8;
> +	u64   l2_ptr:8;
> +	u64   pkt_len:16; /* W1 */
> +	u64   vlan2_ptr:8;
> +	u64   vlan_ptr:8;
> +	u64   vlan_tci:16;
> +	u64   rss_tag:32; /* W2 */
> +	u64   rb0_sz:16;
> +	u64   rb1_sz:16;
> +	u64   rb2_sz:16;
> +	u64   rb3_sz:16; /* W3 */
> +	u64   rb4_sz:16;
> +	u64   rb5_sz:16;
> +	u64   rb6_sz:16;
> +	u64   rb7_sz:16; /* W4 */
> +	u64   rb8_sz:16;
> +	u64   rb9_sz:16;
> +	u64   rb10_sz:16;
> +	u64   rb11_sz:16; /* W5 */
> +#endif
> +	u64   rb0_ptr:64;
> +	u64   rb1_ptr:64;
> +	u64   rb2_ptr:64;
> +	u64   rb3_ptr:64;
> +	u64   rb4_ptr:64;
> +	u64   rb5_ptr:64;
> +	u64   rb6_ptr:64;
> +	u64   rb7_ptr:64;
> +	u64   rb8_ptr:64;
> +	u64   rb9_ptr:64;
> +	u64   rb10_ptr:64;
> +	u64   rb11_ptr:64;
> +};
> +
> +struct cqe_rx_tcp_err_t {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64   cqe_type:4; /* W0 */
> +	u64   rsvd0:60;
> +
> +	u64   rsvd1:4; /* W1 */
> +	u64   partial_first:1;
> +	u64   rsvd2:27;
> +	u64   rbdr_bytes:8;
> +	u64   rsvd3:24;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64   rsvd0:60;
> +	u64   cqe_type:4;
> +
> +	u64   rsvd3:24;
> +	u64   rbdr_bytes:8;
> +	u64   rsvd2:27;
> +	u64   partial_first:1;
> +	u64   rsvd1:4;
> +#endif
> +};
> +
> +struct cqe_rx_tcp_t {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64   cqe_type:4; /* W0 */
> +	u64   rsvd0:52;
> +	u64   cq_tcp_status:8;
> +
> +	u64   rsvd1:32; /* W1 */
> +	u64   tcp_cntx_bytes:8;
> +	u64   rsvd2:8;
> +	u64   tcp_err_bytes:16;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64   cq_tcp_status:8;
> +	u64   rsvd0:52;
> +	u64   cqe_type:4; /* W0 */
> +
> +	u64   tcp_err_bytes:16;
> +	u64   rsvd2:8;
> +	u64   tcp_cntx_bytes:8;
> +	u64   rsvd1:32; /* W1 */
> +#endif
> +};
> +
> +struct cqe_send_t {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64   cqe_type:4; /* W0 */
> +	u64   rsvd0:4;
> +	u64   sqe_ptr:16;
> +	u64   rsvd1:4;
> +	u64   rsvd2:10;
> +	u64   sq_qs:7;
> +	u64   sq_idx:3;
> +	u64   rsvd3:8;
> +	u64   send_status:8;
> +
> +	u64   ptp_timestamp:64; /* W1 */
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64   send_status:8;
> +	u64   rsvd3:8;
> +	u64   sq_idx:3;
> +	u64   sq_qs:7;
> +	u64   rsvd2:10;
> +	u64   rsvd1:4;
> +	u64   sqe_ptr:16;
> +	u64   rsvd0:4;
> +	u64   cqe_type:4; /* W0 */
> +
> +	u64   ptp_timestamp:64; /* W1 */
> +#endif
> +};
> +
> +union cq_desc_t {
> +	u64 u[64];
> +	struct cqe_send_t snd_hdr;
> +	struct cqe_rx_t rx_hdr;
> +	struct cqe_rx_tcp_t rx_tcp_hdr;
> +	struct cqe_rx_tcp_err_t rx_tcp_err_hdr;
> +};
> +
> +struct rbdr_entry_t {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64   rsvd0:15;
> +	u64   buf_addr:42;
> +	u64   cache_align:7;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64   cache_align:7;
> +	u64   buf_addr:42;
> +	u64   rsvd0:15;
> +#endif
> +};
> +
> +/* TCP reassembly context */
> +struct rbe_tcp_cnxt_t {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64   tcp_pkt_cnt:12;
> +	u64   rsvd1:4;
> +	u64   align_hdr_bytes:4;
> +	u64   align_ptr_bytes:4;
> +	u64   ptr_bytes:16;
> +	u64   rsvd2:24;
> +	u64   cqe_type:4;
> +	u64   rsvd0:54;
> +	u64   tcp_end_reason:2;
> +	u64   tcp_status:4;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64   tcp_status:4;
> +	u64   tcp_end_reason:2;
> +	u64   rsvd0:54;
> +	u64   cqe_type:4;
> +	u64   rsvd2:24;
> +	u64   ptr_bytes:16;
> +	u64   align_ptr_bytes:4;
> +	u64   align_hdr_bytes:4;
> +	u64   rsvd1:4;
> +	u64   tcp_pkt_cnt:12;
> +#endif
> +};
> +
> +/* Always Big endian */
> +struct rx_hdr_t {
> +	u64   opaque:32;
> +	u64   rss_flow:8;
> +	u64   skip_length:6;
> +	u64   disable_rss:1;
> +	u64   disable_tcp_reassembly:1;
> +	u64   nodrop:1;
> +	u64   dest_alg:2;
> +	u64   rsvd0:2;
> +	u64   dest_rq:11;
> +};
> +
> +enum send_l4_csum_type {
> +	SEND_L4_CSUM_DISABLE = 0x00,
> +	SEND_L4_CSUM_UDP = 0x01,
> +	SEND_L4_CSUM_TCP = 0x02,
> +	SEND_L4_CSUM_SCTP = 0x03,
> +};
> +
> +enum send_crc_alg {
> +	SEND_CRCALG_CRC32 = 0x00,
> +	SEND_CRCALG_CRC32C = 0x01,
> +	SEND_CRCALG_ICRC = 0x02,
> +};
> +
> +enum send_load_type {
> +	SEND_LD_TYPE_LDD = 0x00,
> +	SEND_LD_TYPE_LDT = 0x01,
> +	SEND_LD_TYPE_LDWB = 0x02,
> +};
> +
> +enum send_mem_alg_type {
> +	SEND_MEMALG_SET = 0x00,
> +	SEND_MEMALG_ADD = 0x08,
> +	SEND_MEMALG_SUB = 0x09,
> +	SEND_MEMALG_ADDLEN = 0x0A,
> +	SEND_MEMALG_SUBLEN = 0x0B,
> +};
> +
> +enum send_mem_dsz_type {
> +	SEND_MEMDSZ_B64 = 0x00,
> +	SEND_MEMDSZ_B32 = 0x01,
> +	SEND_MEMDSZ_B8 = 0x03,
> +};
> +
> +enum sq_subdesc_type {
> +	SQ_DESC_TYPE_INVALID = 0x00,
> +	SQ_DESC_TYPE_HEADER = 0x01,
> +	SQ_DESC_TYPE_CRC = 0x02,
> +	SQ_DESC_TYPE_IMMEDIATE = 0x03,
> +	SQ_DESC_TYPE_GATHER = 0x04,
> +	SQ_DESC_TYPE_MEMORY = 0x05,
> +};
> +
> +struct sq_crc_subdesc {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64    rsvd1:32;
> +	u64    crc_ival:32;
> +	u64    subdesc_type:4;
> +	u64    crc_alg:2;
> +	u64    rsvd0:10;
> +	u64    crc_insert_pos:16;
> +	u64    hdr_start:16;
> +	u64    crc_len:16;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64    crc_len:16;
> +	u64    hdr_start:16;
> +	u64    crc_insert_pos:16;
> +	u64    rsvd0:10;
> +	u64    crc_alg:2;
> +	u64    subdesc_type:4;
> +	u64    crc_ival:32;
> +	u64    rsvd1:32;
> +#endif
> +};
> +
> +struct sq_gather_subdesc {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64    subdesc_type:4; /* W0 */
> +	u64    ld_type:2;
> +	u64    rsvd0:42;
> +	u64    size:16;
> +
> +	u64    rsvd1:15; /* W1 */
> +	u64    addr:49;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64    size:16;
> +	u64    rsvd0:42;
> +	u64    ld_type:2;
> +	u64    subdesc_type:4; /* W0 */
> +
> +	u64    addr:49;
> +	u64    rsvd1:15; /* W1 */
> +#endif
> +};
> +
> +/* SQ immediate subdescriptor */
> +struct sq_imm_subdesc {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64    subdesc_type:4; /* W0 */
> +	u64    rsvd0:46;
> +	u64    len:14;
> +
> +	u64    data:64; /* W1 */
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64    len:14;
> +	u64    rsvd0:46;
> +	u64    subdesc_type:4; /* W0 */
> +
> +	u64    data:64; /* W1 */
> +#endif
> +};
> +
> +struct sq_mem_subdesc {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64    subdesc_type:4; /* W0 */
> +	u64    mem_alg:4;
> +	u64    mem_dsz:2;
> +	u64    wmem:1;
> +	u64    rsvd0:21;
> +	u64    offset:32;
> +
> +	u64    rsvd1:15; /* W1 */
> +	u64    addr:49;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64    offset:32;
> +	u64    rsvd0:21;
> +	u64    wmem:1;
> +	u64    mem_dsz:2;
> +	u64    mem_alg:4;
> +	u64    subdesc_type:4; /* W0 */
> +
> +	u64    addr:49;
> +	u64    rsvd1:15; /* W1 */
> +#endif
> +};
> +
> +struct sq_hdr_subdesc {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64    subdesc_type:4;
> +	u64    tso:1;
> +	u64    post_cqe:1; /* Post CQE on no error also */
> +	u64    dont_send:1;
> +	u64    tstmp:1;
> +	u64    subdesc_cnt:8;
> +	u64    csum_l4:2;
> +	u64    csum_l3:1;
> +	u64    rsvd0:5;
> +	u64    l4_offset:8;
> +	u64    l3_offset:8;
> +	u64    rsvd1:4;
> +	u64    tot_len:20; /* W0 */
> +
> +	u64    tso_sdc_cont:8;
> +	u64    tso_sdc_first:8;
> +	u64    tso_l4_offset:8;
> +	u64    tso_flags_last:12;
> +	u64    tso_flags_first:12;
> +	u64    rsvd2:2;
> +	u64    tso_max_paysize:14; /* W1 */
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64    tot_len:20;
> +	u64    rsvd1:4;
> +	u64    l3_offset:8;
> +	u64    l4_offset:8;
> +	u64    rsvd0:5;
> +	u64    csum_l3:1;
> +	u64    csum_l4:2;
> +	u64    subdesc_cnt:8;
> +	u64    tstmp:1;
> +	u64    dont_send:1;
> +	u64    post_cqe:1; /* Post CQE on no error also */
> +	u64    tso:1;
> +	u64    subdesc_type:4; /* W0 */
> +
> +	u64    tso_max_paysize:14;
> +	u64    rsvd2:2;
> +	u64    tso_flags_first:12;
> +	u64    tso_flags_last:12;
> +	u64    tso_l4_offset:8;
> +	u64    tso_sdc_first:8;
> +	u64    tso_sdc_cont:8; /* W1 */
> +#endif
> +};
> +
> +/* Queue config register formats */
> +struct rq_cfg {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64 reserved_2_63:62;
> +	u64 ena:1;
> +	u64 tcp_ena:1;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64 tcp_ena:1;
> +	u64 ena:1;
> +	u64 reserved_2_63:62;
> +#endif
> +};
> +
> +struct cq_cfg {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64 reserved_43_63:21;
> +	u64 ena:1;
> +	u64 reset:1;
> +	u64 caching:1;
> +	u64 reserved_35_39:5;
> +	u64 qsize:3;
> +	u64 reserved_25_31:7;
> +	u64 avg_con:9;
> +	u64 reserved_0_15:16;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64 reserved_0_15:16;
> +	u64 avg_con:9;
> +	u64 reserved_25_31:7;
> +	u64 qsize:3;
> +	u64 reserved_35_39:5;
> +	u64 caching:1;
> +	u64 reset:1;
> +	u64 ena:1;
> +	u64 reserved_43_63:21;
> +#endif
> +};
> +
> +struct sq_cfg {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64 reserved_20_63:44;
> +	u64 ena:1;
> +	u64 reserved_18_18:1;
> +	u64 reset:1;
> +	u64 ldwb:1;
> +	u64 reserved_11_15:5;
> +	u64 qsize:3;
> +	u64 reserved_3_7:5;
> +	u64 tstmp_bgx_intf:3;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64 tstmp_bgx_intf:3;
> +	u64 reserved_3_7:5;
> +	u64 qsize:3;
> +	u64 reserved_11_15:5;
> +	u64 ldwb:1;
> +	u64 reset:1;
> +	u64 reserved_18_18:1;
> +	u64 ena:1;
> +	u64 reserved_20_63:44;
> +#endif
> +};
> +
> +struct rbdr_cfg {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64 reserved_45_63:19;
> +	u64 ena:1;
> +	u64 reset:1;
> +	u64 ldwb:1;
> +	u64 reserved_36_41:6;
> +	u64 qsize:4;
> +	u64 reserved_25_31:7;
> +	u64 avg_con:9;
> +	u64 reserved_12_15:4;
> +	u64 lines:12;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64 lines:12;
> +	u64 reserved_12_15:4;
> +	u64 avg_con:9;
> +	u64 reserved_25_31:7;
> +	u64 qsize:4;
> +	u64 reserved_36_41:6;
> +	u64 ldwb:1;
> +	u64 reset:1;
> +	u64 ena: 1;
> +	u64 reserved_45_63:19;
> +#endif
> +};
> +
> +struct qs_cfg {
> +#if defined(__BIG_ENDIAN_BITFIELD)
> +	u64 reserved_32_63:32;
> +	u64 ena:1;
> +	u64 reserved_27_30:4;
> +	u64 sq_ins_ena:1;
> +	u64 sq_ins_pos:6;
> +	u64 lock_ena:1;
> +	u64 lock_viol_cqe_ena:1;
> +	u64 send_tstmp_ena:1;
> +	u64 be:1;
> +	u64 reserved_7_15:9;
> +	u64 vnic:7;
> +#elif defined(__LITTLE_ENDIAN_BITFIELD)
> +	u64 vnic:7;
> +	u64 reserved_7_15:9;
> +	u64 be:1;
> +	u64 send_tstmp_ena:1;
> +	u64 lock_viol_cqe_ena:1;
> +	u64 lock_ena:1;
> +	u64 sq_ins_pos:6;
> +	u64 sq_ins_ena:1;
> +	u64 reserved_27_30:4;
> +	u64 ena:1;
> +	u64 reserved_32_63:32;
> +#endif
> +};
> +
> +#endif /* Q_STRUCT_H */
> diff --git a/drivers/net/octeontx/smi.c b/drivers/net/octeontx/smi.c
> new file mode 100644
> index 0000000000..8e2c3ca5a3
> --- /dev/null
> +++ b/drivers/net/octeontx/smi.c
> @@ -0,0 +1,380 @@
> +// SPDX-License-Identifier:    GPL-2.0
> +/*
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#include <dm.h>
> +#include <malloc.h>
> +#include <miiphy.h>
> +#include <misc.h>
> +#include <pci.h>
> +#include <pci_ids.h>
> +#include <phy.h>
> +#include <asm/io.h>
> +#include <linux/ctype.h>
> +#include <linux/delay.h>
> +
> +#define PCI_DEVICE_ID_OCTEONTX_SMI 0xA02B
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +enum octeontx_smi_mode {
> +	CLAUSE22 = 0,
> +	CLAUSE45 = 1,
> +};
> +
> +enum {
> +	SMI_OP_C22_WRITE = 0,
> +	SMI_OP_C22_READ = 1,
> +
> +	SMI_OP_C45_ADDR = 0,
> +	SMI_OP_C45_WRITE = 1,
> +	SMI_OP_C45_PRIA = 2,
> +	SMI_OP_C45_READ = 3,
> +};
> +
> +union smi_x_clk {
> +	u64 u;
> +	struct smi_x_clk_s {
> +		int phase:8;
> +		int sample:4;
> +		int preamble:1;
> +		int clk_idle:1;
> +		int reserved_14_14:1;
> +		int sample_mode:1;
> +		int sample_hi:5;
> +		int reserved_21_23:3;
> +		int mode:1;
> +	} s;
> +};
> +
> +union smi_x_cmd {
> +	u64 u;
> +	struct smi_x_cmd_s {
> +		int reg_adr:5;
> +		int reserved_5_7:3;
> +		int phy_adr:5;
> +		int reserved_13_15:3;
> +		int phy_op:2;
> +	} s;
> +};
> +
> +union smi_x_wr_dat {
> +	u64 u;
> +	struct smi_x_wr_dat_s {
> +		unsigned int dat:16;
> +		int val:1;
> +		int pending:1;
> +	} s;
> +};
> +
> +union smi_x_rd_dat {
> +	u64 u;
> +	struct smi_x_rd_dat_s {
> +		unsigned int dat:16;
> +		int val:1;
> +		int pending:1;
> +	} s;
> +};
> +
> +union smi_x_en {
> +	u64 u;
> +	struct smi_x_en_s {
> +		int en:1;
> +	} s;
> +};
> +
> +#define SMI_X_RD_DAT	0x10ull
> +#define SMI_X_WR_DAT	0x08ull
> +#define SMI_X_CMD	0x00ull
> +#define SMI_X_CLK	0x18ull
> +#define SMI_X_EN	0x20ull
> +
> +struct octeontx_smi_priv {
> +	void __iomem *baseaddr;
> +	enum octeontx_smi_mode mode;
> +};
> +
> +#define MDIO_TIMEOUT 10000
> +
> +void octeontx_smi_setmode(struct mii_dev *bus, enum octeontx_smi_mode mode)
> +{
> +	struct octeontx_smi_priv *priv = bus->priv;
> +	union smi_x_clk smix_clk;
> +
> +	smix_clk.u = readq(priv->baseaddr + SMI_X_CLK);
> +	smix_clk.s.mode = mode;
> +	smix_clk.s.preamble = mode == CLAUSE45;
> +	writeq(smix_clk.u, priv->baseaddr + SMI_X_CLK);
> +
> +	priv->mode = mode;
> +}
> +
> +int octeontx_c45_addr(struct mii_dev *bus, int addr, int devad, int regnum)
> +{
> +	struct octeontx_smi_priv *priv = bus->priv;
> +
> +	union smi_x_cmd smix_cmd;
> +	union smi_x_wr_dat smix_wr_dat;
> +	unsigned long timeout = MDIO_TIMEOUT;
> +
> +	smix_wr_dat.u = 0;
> +	smix_wr_dat.s.dat = regnum;
> +
> +	writeq(smix_wr_dat.u, priv->baseaddr + SMI_X_WR_DAT);
> +
> +	smix_cmd.u = 0;
> +	smix_cmd.s.phy_op = SMI_OP_C45_ADDR;
> +	smix_cmd.s.phy_adr = addr;
> +	smix_cmd.s.reg_adr = devad;
> +
> +	writeq(smix_cmd.u, priv->baseaddr + SMI_X_CMD);
> +
> +	do {
> +		smix_wr_dat.u = readq(priv->baseaddr + SMI_X_WR_DAT);
> +		udelay(100);
> +		timeout--;
> +	} while (smix_wr_dat.s.pending && timeout);
> +
> +	return timeout == 0;
> +}
> +
> +int octeontx_phy_read(struct mii_dev *bus, int addr, int devad, int regnum)
> +{
> +	struct octeontx_smi_priv *priv = bus->priv;
> +	union smi_x_cmd smix_cmd;
> +	union smi_x_rd_dat smix_rd_dat;
> +	unsigned long timeout = MDIO_TIMEOUT;
> +	int ret;
> +
> +	enum octeontx_smi_mode mode = (devad < 0) ? CLAUSE22 : CLAUSE45;
> +
> +	debug("RD: Mode: %u, baseaddr: %p, addr: %d, devad: %d, reg: %d\n",
> +	      mode, priv->baseaddr, addr, devad, regnum);
> +
> +	octeontx_smi_setmode(bus, mode);
> +
> +	if (mode == CLAUSE45) {
> +		ret = octeontx_c45_addr(bus, addr, devad, regnum);
> +
> +		debug("RD: ret: %u\n", ret);
> +
> +		if (ret)
> +			return 0;
> +	}
> +
> +	smix_cmd.u = 0;
> +	smix_cmd.s.phy_adr = addr;
> +
> +	if (mode == CLAUSE45) {
> +		smix_cmd.s.reg_adr = devad;
> +		smix_cmd.s.phy_op = SMI_OP_C45_READ;
> +	} else {
> +		smix_cmd.s.reg_adr = regnum;
> +		smix_cmd.s.phy_op = SMI_OP_C22_READ;
> +	}
> +
> +	writeq(smix_cmd.u, priv->baseaddr + SMI_X_CMD);
> +
> +	do {
> +		smix_rd_dat.u = readq(priv->baseaddr + SMI_X_RD_DAT);
> +		udelay(10);
> +		timeout--;
> +	} while (smix_rd_dat.s.pending && timeout);
> +
> +	debug("SMIX_RD_DAT: %lx\n", (unsigned long)smix_rd_dat.u);
> +
> +	return smix_rd_dat.s.dat;
> +}
> +
> +int octeontx_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
> +		       u16 value)
> +{
> +	struct octeontx_smi_priv *priv = bus->priv;
> +	union smi_x_cmd smix_cmd;
> +	union smi_x_wr_dat smix_wr_dat;
> +	unsigned long timeout = MDIO_TIMEOUT;
> +	int ret;
> +
> +	enum octeontx_smi_mode mode = (devad < 0) ? CLAUSE22 : CLAUSE45;
> +
> +	debug("WR: Mode: %u, baseaddr: %p, addr: %d, devad: %d, reg: %d\n",
> +	      mode, priv->baseaddr, addr, devad, regnum);
> +
> +	if (mode == CLAUSE45) {
> +		ret = octeontx_c45_addr(bus, addr, devad, regnum);
> +
> +		debug("WR: ret: %u\n", ret);
> +
> +		if (ret)
> +			return ret;
> +	}
> +
> +	smix_wr_dat.u = 0;
> +	smix_wr_dat.s.dat = value;
> +
> +	writeq(smix_wr_dat.u, priv->baseaddr + SMI_X_WR_DAT);
> +
> +	smix_cmd.u = 0;
> +	smix_cmd.s.phy_adr = addr;
> +
> +	if (mode == CLAUSE45) {
> +		smix_cmd.s.reg_adr = devad;
> +		smix_cmd.s.phy_op = SMI_OP_C45_WRITE;
> +	} else {
> +		smix_cmd.s.reg_adr = regnum;
> +		smix_cmd.s.phy_op = SMI_OP_C22_WRITE;
> +	}
> +
> +	writeq(smix_cmd.u, priv->baseaddr + SMI_X_CMD);
> +
> +	do {
> +		smix_wr_dat.u = readq(priv->baseaddr + SMI_X_WR_DAT);
> +		udelay(10);
> +		timeout--;
> +	} while (smix_wr_dat.s.pending && timeout);
> +
> +	debug("SMIX_WR_DAT: %lx\n", (unsigned long)smix_wr_dat.u);
> +
> +	return timeout == 0;
> +}
> +
> +int octeontx_smi_reset(struct mii_dev *bus)
> +{
> +	struct octeontx_smi_priv *priv = bus->priv;
> +
> +	union smi_x_en smi_en;
> +
> +	smi_en.s.en = 0;
> +	writeq(smi_en.u, priv->baseaddr + SMI_X_EN);
> +
> +	smi_en.s.en = 1;
> +	writeq(smi_en.u, priv->baseaddr + SMI_X_EN);
> +
> +	octeontx_smi_setmode(bus, CLAUSE22);
> +
> +	return 0;
> +}
> +
> +/* PHY XS initialization, primarily for RXAUI
> + *
> + */
> +int rxaui_phy_xs_init(struct mii_dev *bus, int phy_addr)
> +{
> +	int reg;
> +	ulong start_time;
> +	int phy_id1, phy_id2;
> +	int oui, model_number;
> +
> +	phy_id1 = octeontx_phy_read(bus, phy_addr, 1, 0x2);
> +	phy_id2 = octeontx_phy_read(bus, phy_addr, 1, 0x3);
> +	model_number = (phy_id2 >> 4) & 0x3F;
> +	debug("%s model %x\n", __func__, model_number);
> +	oui = phy_id1;
> +	oui <<= 6;
> +	oui |= (phy_id2 >> 10) & 0x3F;
> +	debug("%s oui %x\n", __func__, oui);
> +	switch (oui) {
> +	case 0x5016:
> +		if (model_number == 9) {
> +			debug("%s +\n", __func__);
> +			/* Perform hardware reset in XGXS control */
> +			reg = octeontx_phy_read(bus, phy_addr, 4, 0x0);
> +			if ((reg & 0xffff) < 0)
> +				goto read_error;
> +			reg |= 0x8000;
> +			octeontx_phy_write(bus, phy_addr, 4, 0x0, reg);
> +
> +			start_time = get_timer(0);
> +			do {
> +				reg = octeontx_phy_read(bus, phy_addr, 4, 0x0);
> +				if ((reg & 0xffff) < 0)
> +					goto read_error;
> +			} while ((reg & 0x8000) && get_timer(start_time) < 500);
> +			if (reg & 0x8000) {
> +				printf("HW reset for M88X3120 PHY failed");
> +				printf("MII_BMCR: 0x%x\n", reg);
> +				return -1;
> +			}
> +			/* program 4.49155 with 0x5 */
> +			octeontx_phy_write(bus, phy_addr, 4, 0xc003, 0x5);
> +		}
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +
> +read_error:
> +	debug("M88X3120 PHY config read failed\n");
> +	return -1;
> +}
> +
> +int octeontx_smi_probe(struct udevice *dev)
> +{
> +	int ret, subnode, cnt = 0, node = dev->node.of_offset;
> +	struct mii_dev *bus;
> +	struct octeontx_smi_priv *priv;
> +	pci_dev_t bdf = dm_pci_get_bdf(dev);
> +
> +	debug("SMI PCI device: %x\n", bdf);
> +	dev->req_seq = PCI_FUNC(bdf);
> +	if (!dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM)) {
> +		printf("Failed to map PCI region for bdf %x\n", bdf);
> +		return -1;
> +	}
> +
> +	fdt_for_each_subnode(subnode, gd->fdt_blob, node) {
> +		ret = fdt_node_check_compatible(gd->fdt_blob, subnode,
> +						"cavium,thunder-8890-mdio");
> +		if (ret)
> +			continue;
> +
> +		bus = mdio_alloc();
> +		priv = malloc(sizeof(*priv));
> +		if (!bus || !priv) {
> +			printf("Failed to allocate OcteonTX MDIO bus # %u\n",
> +			       dev->seq);
> +			return -1;
> +		}
> +
> +		bus->read = octeontx_phy_read;
> +		bus->write = octeontx_phy_write;
> +		bus->reset = octeontx_smi_reset;
> +		bus->priv = priv;
> +
> +		priv->mode = CLAUSE22;
> +		priv->baseaddr = (void __iomem *)fdtdec_get_addr(gd->fdt_blob,
> +								 subnode,
> +								 "reg");
> +		debug("mdio base addr %p\n", priv->baseaddr);
> +
> +		/* use given name or generate its own unique name */
> +		snprintf(bus->name, MDIO_NAME_LEN, "smi%d", cnt++);
> +
> +		ret = mdio_register(bus);
> +		if (ret)
> +			return ret;
> +	}
> +	return 0;
> +}
> +
> +static const struct udevice_id octeontx_smi_ids[] = {
> +	{ .compatible = "cavium,thunder-8890-mdio-nexus" },
> +	{}
> +};
> +
> +U_BOOT_DRIVER(octeontx_smi) = {
> +	.name	= "octeontx_smi",
> +	.id	= UCLASS_MISC,
> +	.probe	= octeontx_smi_probe,
> +	.of_match = octeontx_smi_ids,
> +};
> +
> +static struct pci_device_id octeontx_smi_supported[] = {
> +	{ PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_SMI) },
> +	{}
> +};
> +
> +U_BOOT_PCI_DEVICE(octeontx_smi, octeontx_smi_supported);
> diff --git a/drivers/net/octeontx/xcv.c b/drivers/net/octeontx/xcv.c
> new file mode 100644
> index 0000000000..8dd558b1bf
> --- /dev/null
> +++ b/drivers/net/octeontx/xcv.c
> @@ -0,0 +1,124 @@
> +// SPDX-License-Identifier:    GPL-2.0
> +/*
> + * Copyright (C) 2018 Marvell International Ltd.
> + */
> +
> +#include <config.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <fdt_support.h>
> +#include <pci.h>
> +#include <malloc.h>
> +#include <miiphy.h>
> +#include <misc.h>
> +#include <net.h>
> +#include <netdev.h>
> +#include <asm/io.h>
> +#include <linux/delay.h>
> +#include <linux/libfdt.h>
> +
> +#include <asm/arch/csrs/csrs-xcv.h>
> +
> +#define XCVX_BASE		0x87E0DB000000ULL
> +
> +/* Initialize XCV block */
> +void xcv_init_hw(void)
> +{
> +	union xcvx_reset reset;
> +	union xcvx_dll_ctl xcv_dll_ctl;
> +
> +	/* Take the DLL out of reset */
> +	reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +	reset.s.dllrst = 0;
> +	writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
> +
> +	/* Take the clock tree out of reset */
> +	reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +	reset.s.clkrst = 0;
> +	writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
> +
> +	/* Once the 125MHz ref clock is stable, wait 10us for DLL to lock */
> +	udelay(10);
> +
> +	/* Optionally, bypass the DLL setting */
> +	xcv_dll_ctl.u = readq(XCVX_BASE + XCVX_DLL_CTL(0));
> +	xcv_dll_ctl.s.clkrx_set = 0;
> +	xcv_dll_ctl.s.clkrx_byp = 1;
> +	xcv_dll_ctl.s.clktx_byp = 0;
> +	writeq(xcv_dll_ctl.u, XCVX_BASE + XCVX_DLL_CTL(0));
> +
> +	/* Enable the compensation controller */
> +	reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +	reset.s.comp = 1;
> +	writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
> +	reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +
> +	/* Wait for 1040 reference clock cycles for the compensation state
> +	 * machine lock.
> +	 */
> +	udelay(100);
> +
> +	/* Enable the XCV block */
> +	reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +	reset.s.enable = 1;
> +	writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
> +
> +	/* set XCV(0)_RESET[CLKRST] to 1 */
> +	reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +	reset.s.clkrst = 1;
> +	writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
> +}
> +
> +/*
> + * Configure XCV link based on the speed
> + * link_up   : Set to 1 when link is up otherwise 0
> + * link_speed: The speed of the link.
> + */
> +void xcv_setup_link(bool link_up, int link_speed)
> +{
> +	union xcvx_ctl xcv_ctl;
> +	union xcvx_reset reset;
> +	union xcvx_batch_crd_ret xcv_crd_ret;
> +	int speed = 2;
> +
> +	/* Check RGMII link */
> +	if (link_speed == 100)
> +		speed = 1;
> +	else if (link_speed == 10)
> +		speed = 0;
> +
> +	if (link_up) {
> +		/* Set operating speed */
> +		xcv_ctl.u = readq(XCVX_BASE + XCVX_CTL(0));
> +		xcv_ctl.s.speed = speed;
> +		writeq(xcv_ctl.u, XCVX_BASE + XCVX_CTL(0));
> +
> +		/* Datapaths come out of reset
> +		 * - The datapath resets will disengage BGX from the
> +		 *   RGMII interface
> +		 * - XCV will continue to return TX credits for each tick
> +		 *   that is sent on the TX data path
> +		 */
> +		reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +		reset.s.tx_dat_rst_n = 1;
> +		reset.s.rx_dat_rst_n = 1;
> +		writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
> +
> +		/* Enable packet flow */
> +		reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +		reset.s.tx_pkt_rst_n = 1;
> +		reset.s.rx_pkt_rst_n = 1;
> +		writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
> +
> +		xcv_crd_ret.u = readq(XCVX_BASE + XCVX_BATCH_CRD_RET(0));
> +		xcv_crd_ret.s.crd_ret = 1;
> +		writeq(xcv_crd_ret.u, XCVX_BASE + XCVX_BATCH_CRD_RET(0));
> +	} else {
> +		/* Enable packet flow */
> +		reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +		reset.s.tx_pkt_rst_n = 0;
> +		reset.s.rx_pkt_rst_n = 0;
> +		writeq(reset.u, XCVX_BASE + XCVX_RESET(0));
> +		reset.u = readq(XCVX_BASE + XCVX_RESET(0));
> +	}
> +}
> 


Viele Grüße,
Stefan

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de



More information about the U-Boot mailing list