/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * This file contain content copied from Synopsis driver,
 * provided under the license below
 */
/* =========================================================================
 * The Synopsys DWC ETHER QOS Software Driver and documentation (hereinafter
 * "Software") is an unsupported proprietary work of Synopsys, Inc. unless
 * otherwise expressly agreed to in writing between Synopsys and you.
 *
 * The Software IS NOT an item of Licensed Software or Licensed Product under
 * any End User Software License Agreement or Agreement for Licensed Product
 * with Synopsys or any supplement thereto.  Permission is hereby granted,
 * free of charge, to any person obtaining a copy of this software annotated
 * with this license and the Software, to deal in the Software without
 * restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 * =========================================================================
 */

/*!@file: DWC_ETH_QOS_dev.c
 * @brief: Driver functions.
 */
#include "DWC_ETH_QOS_yheader.h"
#include "DWC_ETH_QOS_yapphdr.h"

extern ULONG dwc_eth_qos_base_addr;

#include "DWC_ETH_QOS_yregacc.h"

#ifdef DWC_ETH_QOS_CONFIG_PGTEST

static INT prepare_dev_pktgen(struct DWC_ETH_QOS_prv_data *pdata)
{
	UINT QINX = 0;

	/* set MAC loop back mode */
	MAC_MCR_LM_UDFWR(0x1);

	/* Do not strip received VLAN tag */
	MAC_VLANTR_EVLS_UDFWR(0x0);

	/* set promiscuous mode */
	MAC_MPFR_PR_UDFWR(0x1);

	/* disable autopad or CRC stripping */
	MAC_MCR_ACS_UDFWR(0);

	/* enable drop tx status */
	MTL_OMR_DTXSTS_UDFWR(0x1);

	for (QINX = 0; QINX < DWC_ETH_QOS_TX_QUEUE_CNT; QINX++) {
		/* enable avg bits per slot interrupt */
		MTL_QECR_ABPSSIE_UDFWR(QINX, 0x1);

		/* enable OSF mode */
		DMA_TCR_OSP_UDFWR(QINX, 0x1);

		/* disable slot checks */
		DMA_SFCSR_RGWR(QINX, 0);
	}

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure slot count The software
 * can program the number of slots(of duration 125us) over which the
 * average transmitted bits per slot need to be computed for
 * channel 1 to 7 when CBS alogorithm is enabled.
 * \param[in] QINX
 * \param[in] slot_count
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_slot_count(UINT QINX,
			  UCHAR slot_count)
{
	if (slot_count == 1)
		MTL_QECR_SLC_UDFWR(QINX, 0);
	else if (slot_count == 2)
		MTL_QECR_SLC_UDFWR(QINX, 0x1);
	else if (slot_count == 4)
		MTL_QECR_SLC_UDFWR(QINX, 0x3);
	else if (slot_count == 8)
		MTL_QECR_SLC_UDFWR(QINX, 0x4);
	else if (slot_count == 16)
		MTL_QECR_SLC_UDFWR(QINX, 0x5);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to enable/disable slot interrupt:
 * When this bit is set,the MAC asserts an interrupt when the average
 * bits per slot status is updated for channel 1 to 7.
 * \param[in] QINX
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_slot_interrupt(UINT QINX, UCHAR slot_int)
{
	MTL_QECR_ABPSSIE_UDFWR(QINX, slot_int);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure DMA Tx:Rx/Rx:Tx
 * Priority Ratio These bits control the priority ratio in WRR
 * arbitration between the TX and RX DAM.
 * \param[in] prio_ratio
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_tx_rx_prio_ratio(UCHAR prio_ratio)
{
	DMA_BMR_PR_UDFWR(prio_ratio);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure DMA Transmit Arbitration algorithm
 * \param[in] arb_algo
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_dma_tx_arb_algorithm(UCHAR arb_algo)
{
	DMA_BMR_TAA_UDFWR(arb_algo);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure DMA Tx Priority When this
 * bit is set, it indicates that the TX DMA has higher priority than
 * the RX DMA during arbitration for the system-side bus.
 * \param[in] prio
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_tx_rx_prio(UCHAR prio)
{
	DMA_BMR_TXPR_UDFWR(prio);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure DMA Tx/Rx Arbitration Scheme
 * This bit specifies the arbitration scheme between the Tx and Rx paths
 * of all channels.
 * \param[in] prio_policy
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_tx_rx_prio_policy(UCHAR prio_policy)
{
	DMA_BMR_DA_UDFWR(prio_policy);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure TX Channel Weight
 * \param[in] QINX
 * \param[in] weight
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_ch_arb_weights(UINT QINX,
			      UCHAR weight)
{
	if (weight == 1)
		DMA_TCR_TCW_UDFWR(QINX, 0);
	else if (weight == 2)
		DMA_TCR_TCW_UDFWR(QINX, 0x1);
	else if (weight == 3)
		DMA_TCR_TCW_UDFWR(QINX, 0x2);
	else if (weight == 4)
		DMA_TCR_TCW_UDFWR(QINX, 0x3);
	else if (weight == 5)
		DMA_TCR_TCW_UDFWR(QINX, 0x4);
	else if (weight == 6)
		DMA_TCR_TCW_UDFWR(QINX, 0x5);
	else if (weight == 7)
		DMA_TCR_TCW_UDFWR(QINX, 0x6);
	else if (weight == 8)
		DMA_TCR_TCW_UDFWR(QINX, 0x7);
	return Y_SUCCESS;
}
#endif /* end of DWC_ETH_QOS_CONFIG_PGTEST */

/*!
 * \brief This sequence is used to enable/disable MAC loopback mode
 * \param[in] enb_dis
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_mac_loopback_mode(UINT enb_dis)
{
	MAC_MCR_LM_UDFWR(enb_dis);

	return Y_SUCCESS;
}

/* enable/disable PFC(Priority Based Flow Control) */
static void config_pfc(int enb_dis)
{
	MAC_RFCR_PFCE_UDFWR(enb_dis);
}

/*!
 * \brief This sequence is used to configure mac double vlan processing feature.
 * \param[in] enb_dis
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_tx_outer_vlan(UINT op_type, UINT outer_vlt)
{
	EMACDBG("--> config_tx_outer_vlan()\n");

	MAC_VLANTIRR_VLTI_UDFWR(0x0);
	MAC_VLANTIRR_VLT_UDFWR(outer_vlt);
	MAC_VLANTIRR_VLP_UDFWR(0x1);
	MAC_VLANTIRR_VLC_UDFWR(op_type);

	if (op_type == DWC_ETH_QOS_DVLAN_NONE) {
		MAC_VLANTIRR_VLP_UDFWR(0x0);
		MAC_VLANTIRR_VLT_UDFWR(0x0);
	}

	EMACDBG("<-- config_tx_outer_vlan()\n");

	return Y_SUCCESS;
}

static INT config_tx_inner_vlan(UINT op_type, UINT inner_vlt)
{
	EMACDBG("--> config_tx_inner_vlan()\n");

	MAC_IVLANTIRR_VLTI_UDFWR(0x0);
	MAC_IVLANTIRR_VLT_UDFWR(inner_vlt);
	MAC_IVLANTIRR_VLP_UDFWR(0x1);
	MAC_IVLANTIRR_VLC_UDFWR(op_type);

	if (op_type == DWC_ETH_QOS_DVLAN_NONE) {
		MAC_IVLANTIRR_VLP_UDFWR(0x0);
		MAC_IVLANTIRR_VLT_UDFWR(0x0);
	}

	EMACDBG("<-- config_tx_inner_vlan()\n");

	return Y_SUCCESS;
}

static INT config_svlan(UINT flags)
{
	INT ret = Y_SUCCESS;

	EMACDBG("--> config_svlan()\n");

	MAC_VLANTR_ESVL_UDFWR(1);
	if (flags == DWC_ETH_QOS_DVLAN_NONE) {
		MAC_VLANTR_ESVL_UDFWR(0);
		MAC_IVLANTIRR_CSVL_UDFWR(0);
		MAC_VLANTIRR_CSVL_UDFWR(0);
	} else if (flags == DWC_ETH_QOS_DVLAN_INNER) {
		MAC_IVLANTIRR_CSVL_UDFWR(1);
	} else if (flags == DWC_ETH_QOS_DVLAN_OUTER) {
		MAC_VLANTIRR_CSVL_UDFWR(1);
	} else if (flags == DWC_ETH_QOS_DVLAN_BOTH) {
		MAC_IVLANTIRR_CSVL_UDFWR(1);
		MAC_VLANTIRR_CSVL_UDFWR(1);
	} else {
		EMACERR("ERROR : double VLAN enable SVLAN configuration - Invalid argument");
		ret = Y_FAILURE;
	}

	EMACDBG("<-- config_svlan()\n");

	return ret;
}

static VOID config_dvlan(bool enb_dis)
{
	MAC_VLANTR_EDVLP_UDFWR(enb_dis);
}

/*!
 * \brief This sequence is used to enable/disable ARP offload
 * \param[in] enb_dis
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int config_arp_offload(int enb_dis)
{
	MAC_MCR_ARPEN_UDFWR(enb_dis);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to update the IP addr into MAC ARP Add reg,
 * which is used by MAC for replying to ARP packets
 * \param[in] addr
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int update_arp_offload_ip_addr(UCHAR addr[])
{
	MAC_ARPA_RGWR(
		(addr[3] | (addr[2] << 8) | (addr[1] << 16) |
		addr[0] << 24));

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to get the status of LPI/EEE mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static u32 get_lpi_status(void)
{
	u32 varmac_lps;

	MAC_LPS_RGRD(varmac_lps);

	return varmac_lps;
}

/*!
 * \brief This sequence is used to enable EEE mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int set_eee_mode(void)
{
	MAC_LPS_LPIEN_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to disable EEE mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int reset_eee_mode(void)
{
	MAC_LPS_LPITXA_UDFWR(0);
	MAC_LPS_LPIEN_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to set PLS bit
 * \param[in] phy_link
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int set_eee_pls(int phy_link)
{
	if (phy_link == 1)
		MAC_LPS_PLS_UDFWR(0x1);
	else
		MAC_LPS_PLS_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to set EEE timer values
 * \param[in] lpi_lst
 * \param[in] lpi_twt
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int set_eee_timer(int lpi_lst,
			 int lpi_twt)
{
	/* mim time(us) for which the MAC waits after it stops
	 * transmitting
	 * the LPI pattern to the PHY and before it resumes the
	 * normal transmission.
	 */
	MAC_LPC_TWT_UDFWR(lpi_twt);
	/* mim time(ms) for which the link status from the PHY
	 * should be Up before
	 * the LPI pattern can be transmitted to the PHY.
	 */
	MAC_LPC_TLPIEX_UDFWR(lpi_lst);

	return Y_SUCCESS;
}

static int set_lpi_tx_automate(void)
{
	MAC_LPS_LPITXA_UDFWR(0x1);

	return Y_SUCCESS;
}

static int set_lpi_tx_auto_entry_timer_en(void)
{
	MAC_LPS_LPIATE_UDFWR(0x1);

	return Y_SUCCESS;
}

static int set_lpi_tx_auto_entry_timer(u32 data)
{
	MAC_LPET_LPIET_UDFWR(data);

	return Y_SUCCESS;
}

static int set_lpi_us_tic_counter(u32 data)
{
	MAC_1USTICK_CNTR_UDFWR(data);

	return Y_SUCCESS;
}


/*!
 * \brief This sequence is used to enable/disable Auto-Negotiation
 * and restart the autonegotiation
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int control_an(bool enable, bool restart)
{
	MAC_ANC_ANE_UDFWR(enable);
	MAC_ANC_RAN_UDFWR(restart);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to get Auto-Negotiation advertisment
 * pause parameter
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int get_an_adv_pause_param(void)
{
	unsigned long varmac_aad;

	MAC_AAD_RGRD(varmac_aad);

	return GET_VALUE(varmac_aad, MAC_AAD_PSE_LPOS, MAC_AAD_PSE_HPOS);
}

/*!
 * \brief This sequence is used to get Auto-Negotiation advertisment
 * duplex parameter. Returns one if Full duplex mode is selected
 * else returns zero
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int get_an_adv_duplex_param(void)
{
	unsigned long varmac_aad;

	MAC_AAD_RGRD(varmac_aad);
	if (GET_VALUE(varmac_aad, MAC_AAD_FD_LPOS, MAC_AAD_FD_HPOS) == 1)
		return 1;
	else
		return 0;
}

/*!
 * \brief This sequence is used to get Link partner Auto-Negotiation
 * advertisment pause parameter
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int get_lp_an_adv_pause_param(void)
{
	unsigned long varmac_alpa;

	MAC_ALPA_RGRD(varmac_alpa);

	return GET_VALUE(varmac_alpa, MAC_ALPA_PSE_LPOS, MAC_ALPA_PSE_HPOS);
}

/*!
 * \brief This sequence is used to get Link partner Auto-Negotiation
 * advertisment duplex parameter. Returns one if Full duplex mode
 * is selected else returns zero
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int get_lp_an_adv_duplex_param(void)
{
	unsigned long varmac_alpa;

	MAC_ALPA_RGRD(varmac_alpa);
	if (GET_VALUE(varmac_alpa, MAC_ALPA_FD_LPOS, MAC_ALPA_FD_HPOS) == 1)
		return 1;
	else
		return 0;
}

static UINT get_vlan_tag_comparison(void)
{
	UINT etv;

	MAC_VLANTR_ETV_UDFRD(etv);

	return etv;
}

/*!
 * \brief This sequence is used to update the
 * EMAC_MAC_VLAN_TAG_DATA VLAN register with
 * VLAN tag, offset and 12-bit comparison enable/disable info
 * \param[in] VLAN tag
 * \param[in] offset value
 * \param[in] 12-bit comparison enable/disable
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_vlan_tag_data(UINT vlan_tag,
		INT vlan_reg_offset,
		bool enable_12_bit_vlan_tag_comparison)
{
	ULONG RETRYCOUNT = 1000;
	ULONG current_cnt = 0;
	volatile int op_busy;
	int reg_val = 0;

	EMACDBG("Enter\n");

	while (1) {
		if (current_cnt > RETRYCOUNT)
			return -Y_FAILURE;
		MAC_VLANTR_OB_UDFRD(op_busy);
		if (op_busy == 0)
			break;
		current_cnt++;
		mdelay(1);
	}

	EMACDBG("Write to MAC_VLAN_TAG_DATA reg as OB bit = %d\n", op_busy);
	/* Write the VLAN tag data */
	MAC_VLAN_TAG_DATA_15_0_UDFWR(vlan_tag);
	MAC_VLAN_TAG_DATA_16_UDFWR(0x1);
	MAC_VLAN_TAG_DATA_17_UDFWR(enable_12_bit_vlan_tag_comparison);
	MAC_VLAN_TAG_DATA_18_UDFWR(0x1);

	MAC_VLANTR_OFS_UDFWR(vlan_reg_offset);
	MAC_VLANTR_CT_UDFWR(0x0);
	MAC_VLANTR_OB_UDFWR(0x1);

	while (1) {
		if (current_cnt > RETRYCOUNT)
			return -Y_FAILURE;
		MAC_VLANTR_OB_UDFRD(op_busy);
		if (op_busy == 0)
			break;
		current_cnt++;
		mdelay(1);
	}

	MAC_VLANTR_OFS_UDFWR(vlan_reg_offset);
	MAC_VLANTR_CT_UDFWR(0x1);
	MAC_VLANTR_OB_UDFWR(0x1);

	while (1) {
		if (current_cnt > RETRYCOUNT)
			return -Y_FAILURE;
		MAC_VLANTR_OB_UDFRD(op_busy);
		if (op_busy == 0)
			break;
		current_cnt++;
		mdelay(1);
	}

	MAC_VLAN_TAG_DATA_RGRD(reg_val);
	EMACDBG("Read from MAC_VLAN_TAG_DATA reg (0x%p) for offset %d = %#x\n",
			MAC_VLAN_TAG_DATA_RGOFFADDR, vlan_reg_offset, reg_val);

	EMACDBG("Exit\n");
	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to enable/disable VLAN filtering and
 * also selects VLAN filtering mode- perfect/hash
 * \param[in] filter_enb_dis
 * \param[in] perfect_hash
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_vlan_filtering(INT filter_enb_dis,
				 INT perfect_hash_filtering,
				 INT perfect_inverse_match)
{
	MAC_MPFR_VTFE_UDFWR(filter_enb_dis);
	MAC_VLANTR_VTIM_UDFWR(perfect_inverse_match);
	MAC_VLANTR_VTHM_UDFWR(perfect_hash_filtering);
	/* To enable only HASH filtering then VL/VID
	 * should be > zero. Hence we are writing 1 into VL.
	 * It also means that MAC will always receive VLAN pkt with
	 * VID = 1 if inverse march is not set.
	 */
	if (perfect_hash_filtering)
		MAC_VLANTR_VL_UDFWR(0x1);

	/* By default enable MAC to calculate vlan hash on
	 * only 12-bits of received VLAN tag (ie only on
	 * VLAN id and ignore priority and other fields)
	 */
	if (perfect_hash_filtering)
		MAC_VLANTR_ETV_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to update the VLAN ID for perfect filtering
 * \param[in] vid
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_vlan_id(USHORT vid)
{
	MAC_VLANTR_VL_UDFWR(vid);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to update the VLAN Hash Table reg
 * with new VLAN ID
 * \param[in] data
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_vlan_hash_table_reg(USHORT data)
{
	MAC_VLANHTR_VLHT_UDFWR(data);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to get the content of VLAN Hash Table reg
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT get_vlan_hash_table_reg(void)
{
	ULONG VARMAC_VLANHTR;

	MAC_VLANHTR_RGRD(VARMAC_VLANHTR);

	return GET_VALUE(
		VARMAC_VLANHTR, MAC_VLANHTR_VLHT_LPOS,
		MAC_VLANHTR_VLHT_HPOS);
}

/*!
 * \brief This sequence is used to update Destination Port Number for
 * L4(TCP/UDP) layer filtering
 * \param[in] filter_no
 * \param[in] port_no
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_l4_da_port_no(INT filter_no,
				USHORT port_no)
{
	MAC_L4AR_L4DP0_UDFWR(filter_no, port_no);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to update Source Port Number for
 * L4(TCP/UDP) layer filtering
 * \param[in] filter_no
 * \param[in] port_no
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_l4_sa_port_no(INT filter_no,
				USHORT port_no)
{
	MAC_L4AR_L4SP0_UDFWR(filter_no, port_no);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure L4(TCP/UDP) filters for
 * SA and DA Port Number matching
 * \param[in] filter_no
 * \param[in] tcp_udp_match
 * \param[in] src_dst_port_match
 * \param[in] perfect_inverse_match
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_l4_filters(INT filter_no,
			     INT enb_dis,
			     INT tcp_udp_match,
			     INT src_dst_port_match,
			     INT perfect_inverse_match)
{
	MAC_L3L4CR_L4PEN0_UDFWR(filter_no, tcp_udp_match);

	if (src_dst_port_match == 0) {
		if (enb_dis == 1) {
			/* Enable L4 filters for SOURCE Port No matching */
			MAC_L3L4CR_L4SPM0_UDFWR(filter_no, 0x1);
			MAC_L3L4CR_L4SPIM0_UDFWR(
				filter_no, perfect_inverse_match);
		} else {
			/* Disable L4 filters for SOURCE Port No matching */
			MAC_L3L4CR_L4SPM0_UDFWR(filter_no, 0x0);
			MAC_L3L4CR_L4SPIM0_UDFWR(filter_no, 0x0);
		}
	} else {
		if (enb_dis == 1) {
			/* Enable L4 filters for DESTINATION port No matching */
			MAC_L3L4CR_L4DPM0_UDFWR(filter_no, 0x1);
			MAC_L3L4CR_L4DPIM0_UDFWR(
				filter_no, perfect_inverse_match);
		} else {
			/* Disable L4 filters for DESTINATION port
			 * No matching
			 */
			MAC_L3L4CR_L4DPM0_UDFWR(filter_no, 0x0);
			MAC_L3L4CR_L4DPIM0_UDFWR(filter_no, 0x0);
		}
	}

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to update IPv6 source/destination
 * Address for L3 layer filtering
 * \param[in] filter_no
 * \param[in] addr
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_ip6_addr(INT filter_no,
			   USHORT addr[])
{
	/* update Bits[31:0] of 128-bit IP addr */
	MAC_L3A0R_RGWR(filter_no, (addr[7] | (addr[6] << 16)));
	/* update Bits[63:32] of 128-bit IP addr */
	MAC_L3A1R_RGWR(filter_no, (addr[5] | (addr[4] << 16)));
	/* update Bits[95:64] of 128-bit IP addr */
	MAC_L3A2R_RGWR(filter_no, (addr[3] | (addr[2] << 16)));
	/* update Bits[127:96] of 128-bit IP addr */
	MAC_L3A3R_RGWR(filter_no, (addr[1] | (addr[0] << 16)));

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to update IPv4 destination
 * Address for L3 layer filtering
 * \param[in] filter_no
 * \param[in] addr
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_ip4_addr1(INT filter_no,
			    UCHAR addr[])
{
	MAC_L3A1R_RGWR(
		filter_no, (addr[3] | (addr[2] << 8) | (addr[1] << 16) |
		(addr[0] << 24)));

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to update IPv4 source
 * Address for L3 layer filtering
 * \param[in] filter_no
 * \param[in] addr
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_ip4_addr0(INT filter_no,
			    UCHAR addr[])
{
	MAC_L3A0R_RGWR(
		filter_no, (addr[3] | (addr[2] << 8) | (addr[1] << 16) |
		(addr[0] << 24)));

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure L3(IPv4/IPv6) filters
 * for SA/DA Address matching
 * \param[in] filter_no
 * \param[in] ipv4_ipv6_match
 * \param[in] src_dst_addr_match
 * \param[in] perfect_inverse_match
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_l3_filters(INT filter_no,
			     INT enb_dis,
			     INT ipv4_ipv6_match,
			     INT src_dst_addr_match,
			     INT perfect_inverse_match)
{
	MAC_L3L4CR_L3PEN0_UDFWR(filter_no, ipv4_ipv6_match);

	/* For IPv6 either SA/DA can be checked, not both */
	if (ipv4_ipv6_match == 1) {
		if (enb_dis == 1) {
			if (src_dst_addr_match == 0) {
				/* Enable L3 filters for IPv6 SOURCE addr
				 * matching
				 */
				MAC_L3L4CR_L3SAM0_UDFWR(filter_no, 0x1);
				MAC_L3L4CR_L3SAIM0_UDFWR(
					filter_no, perfect_inverse_match);
				MAC_L3L4CR_L3DAM0_UDFWR(filter_no, 0x0);
				MAC_L3L4CR_L3DAIM0_UDFWR(filter_no, 0x0);
			} else {
				/* Enable L3 filters for IPv6 DESTINATION addr
				 * matching
				 */
				MAC_L3L4CR_L3SAM0_UDFWR(filter_no, 0x0);
				MAC_L3L4CR_L3SAIM0_UDFWR(filter_no, 0x0);
				MAC_L3L4CR_L3DAM0_UDFWR(filter_no, 0x1);
				MAC_L3L4CR_L3DAIM0_UDFWR(
					filter_no, perfect_inverse_match);
			}
		} else {
			/* Disable L3 filters for IPv6 SOURCE/DESTINATION addr
			 * matching
			 */
			MAC_L3L4CR_L3PEN0_UDFWR(filter_no, 0x0);
			MAC_L3L4CR_L3SAM0_UDFWR(filter_no, 0x0);
			MAC_L3L4CR_L3SAIM0_UDFWR(filter_no, 0x0);
			MAC_L3L4CR_L3DAM0_UDFWR(filter_no, 0x0);
			MAC_L3L4CR_L3DAIM0_UDFWR(filter_no, 0x0);
		}
	} else {
		if (src_dst_addr_match == 0) {
			if (enb_dis == 1) {
				/* Enable L3 filters for IPv4 SOURCE addr
				 * matching
				 */
				MAC_L3L4CR_L3SAM0_UDFWR(filter_no, 0x1);
				MAC_L3L4CR_L3SAIM0_UDFWR(
					filter_no, perfect_inverse_match);
			} else {
				/* Disable L3 filters for IPv4 SOURCE addr
				 * matching
				 */
				MAC_L3L4CR_L3SAM0_UDFWR(filter_no, 0x0);
				MAC_L3L4CR_L3SAIM0_UDFWR(filter_no, 0x0);
			}
		} else {
			if (enb_dis == 1) {
				/* Enable L3 filters for IPv4 DESTINATION addr
				 * matching
				 */
				MAC_L3L4CR_L3DAM0_UDFWR(filter_no, 0x1);
				MAC_L3L4CR_L3DAIM0_UDFWR(
					filter_no, perfect_inverse_match);
			} else {
				/* Disable L3 filters for IPv4 DESTINATION addr
				 * matching
				 */
				MAC_L3L4CR_L3DAM0_UDFWR(filter_no, 0x0);
				MAC_L3L4CR_L3DAIM0_UDFWR(filter_no, 0x0);
			}
		}
	}
	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure MAC in differnet pkt processing
 * modes like promiscuous, multicast, unicast, hash unicast/multicast.
 * \param[in] pr_mode
 * \param[in] huc_mode
 * \param[in] hmc_mode
 * \param[in] pm_mode
 * \param[in] hpf_mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_mac_pkt_filter_reg(UCHAR pr_mode,
				     UCHAR huc_mode,
				     UCHAR hmc_mode,
				     UCHAR pm_mode,
				     UCHAR hpf_mode)
{
	ULONG VARMAC_MPFR;

	/* configure device in differnet modes */
	/* promiscuous, hash unicast, hash multicast, */
	/* all multicast and perfect/hash filtering mode. */
	MAC_MPFR_RGRD(VARMAC_MPFR);
	VARMAC_MPFR = VARMAC_MPFR & (ULONG)(0x803103e8);
	VARMAC_MPFR = VARMAC_MPFR | ((pr_mode) << 0) |
		((huc_mode) << 1) | ((hmc_mode) << 2) |
		((pm_mode) << 4) | ((hpf_mode) << 10);
	MAC_MPFR_RGWR(VARMAC_MPFR);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to enable/disable L3 and L4 filtering
 * \param[in] filter_enb_dis
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_l3_l4_filter_enable(INT filter_enb_dis)
{
	MAC_MPFR_IPFE_UDFWR(filter_enb_dis);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to select perfect/inverse matching for L2 DA
 * \param[in] perfect_inverse_match
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_l2_da_perfect_inverse_match(INT perfect_inverse_match)
{
	MAC_MPFR_DAIF_UDFWR(perfect_inverse_match);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to update the MAC address in last 96 MAC
 * address Low and High register(32-127) for L2 layer filtering
 * \param[in] idx
 * \param[in] addr
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_mac_addr32_127_low_high_reg(INT idx,
					      UCHAR addr[])
{
	MAC_MA32_127LR_RGWR(
		idx, (addr[0] | (addr[1] << 8) | (addr[2] << 16) |
		(addr[3] << 24)));
	MAC_MA32_127HR_ADDRHI_UDFWR(idx, (addr[4] | (addr[5] << 8)));
	MAC_MA32_127HR_AE_UDFWR(idx, 0x1);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to update the MAC address in first 31 MAC
 * address Low and High register(1-31) for L2 layer filtering
 * \param[in] idx
 * \param[in] addr
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_mac_addr1_31_low_high_reg(INT idx,
					    UCHAR addr[])
{
	MAC_MA1_31LR_RGWR(
		idx, (addr[0] | (addr[1] << 8) | (addr[2] << 16) |
		(addr[3] << 24)));
	MAC_MA1_31HR_ADDRHI_UDFWR(idx, (addr[4] | (addr[5] << 8)));
	MAC_MA1_31HR_AE_UDFWR(idx, 0x1);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure hash table register for
 * hash address filtering
 * \param[in] idx
 * \param[in] data
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT update_hash_table_reg(INT idx,
				 UINT data)
{
	MAC_HTR_RGWR(idx, data);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used check whether Tx drop status in the
 * MTL is enabled or not, returns 1 if it is enabled and 0 if
 * it is disabled.
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT drop_tx_status_enabled(void)
{
	ULONG VARMTL_OMR;

	MTL_OMR_RGRD(VARMTL_OMR);

	return GET_VALUE(VARMTL_OMR, MTL_OMR_DTXSTS_LPOS, MTL_OMR_DTXSTS_HPOS);
}

/*!
 * \brief This sequence is used configure MAC SSIR
 * \param[in] ptp_clock
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_sub_second_increment(ULONG ptp_clock)
{
	ULONG VARMAC_TCR;
	double ss_inc = 0;
	double sns_inc = 0;

	MAC_TCR_RGRD(VARMAC_TCR);

	/* convert the PTP_CLOCK to nano second */
	/*  formula is : ((1/ptp_clock) * 1000000000) */
	/*  where, ptp_clock = 50MHz if FINE correction */
	/*  and ptp_clock = DWC_ETH_QOS_SYSCLOCK if COARSE correction */
	if (GET_VALUE(VARMAC_TCR, MAC_TCR_TSCFUPDT_LPOS, MAC_TCR_TSCFUPDT_HPOS) == 1) {
		EMACDBG("Using PTP clock %ld MHz\n", ptp_clock);
		ss_inc = (double)1000000000.0 / (double)ptp_clock;
	}
	else {
		EMACDBG("Using SYSCLOCK for coarse correction\n");
		ss_inc = (double)1000000000.0 / (double)DWC_ETH_QOS_SYSCLOCK;
	}

	/* 0.465ns accuracy */
	if (GET_VALUE(
			VARMAC_TCR, MAC_TCR_TSCTRLSSR_LPOS,
			MAC_TCR_TSCTRLSSR_HPOS) == 0) {
		EMACDBG("using 0.465 ns accuracy");
		ss_inc /= 0.465;
 	}

	sns_inc = ss_inc - (int)ss_inc; // take remainder
	sns_inc *= 256.0; // sns_inc needs to be multiplied by 2^8, per spec.
	sns_inc += 0.5; // round to nearest int value.

	MAC_SSIR_SSINC_UDFWR((int)ss_inc);
	MAC_SSIR_SNSINC_UDFWR((int)sns_inc);
	EMACDBG("ss_inc = %d, sns_inc = %d\n", (int)ss_inc, (int)sns_inc);

	return Y_SUCCESS;
    }
/*!
 * \brief
 * \param[in]
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_default_addend(struct DWC_ETH_QOS_prv_data *pdata, ULONG ptp_clock)
{
	struct hw_if_struct *hw_if = &pdata->hw_if;
	u64 temp;

	/* formula is :
	 * addend = 2^32/freq_div_ratio;
	 *
	 * where, freq_div_ratio = DWC_ETH_QOS_SYSCLOCK/50MHz
	 *
	 * hence, addend = ((2^32) * 50MHz)/DWC_ETH_QOS_SYSCLOCK;
	 *
	 * NOTE: DWC_ETH_QOS_SYSCLOCK should be >= 50MHz to
	 *       achive 20ns accuracy.
	 *
	 * 2^x * y == (y << x), hence
	 * 2^32 * 50000000 ==> (50000000 << 32)
	 */
	if (ptp_clock == DWC_ETH_QOS_SYSCLOCK) {
		// If PTP_CLOCK == SYS_CLOCK, best we can do is 2^32 - 1
		pdata->default_addend = 0xFFFFFFFF;
	} else {
		temp = (u64)((u64)ptp_clock << 32);
		pdata->default_addend = div_u64(temp, DWC_ETH_QOS_SYSCLOCK);
	}
	hw_if->config_addend(pdata->default_addend);
	EMACDBG("PPS: PTPCLK_Config: freq=%dHz, addend_reg=0x%x\n",
				ptp_clock, (unsigned int)pdata->default_addend);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used get 64-bit system time in nano sec
 * \return (unsigned long long) on success
 * \retval ns
 */

static ULONG_LONG get_systime(void)
{
	ULONG_LONG ns;
	ULONG varmac_stnsr;
	ULONG varmac_stsr;

	MAC_STNSR_RGRD(varmac_stnsr);
	ns = GET_VALUE(varmac_stnsr, MAC_STNSR_TSSS_LPOS, MAC_STNSR_TSSS_HPOS);
	/* convert sec/high time value to nanosecond */
	MAC_STSR_RGRD(varmac_stsr);
	ns = ns + (varmac_stsr * 1000000000ull);

	return ns;
}

/*!
 * \brief This sequence is used to adjust/update the system time
 * \param[in] sec
 * \param[in] nsec
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT adjust_systime(UINT sec,
			  UINT nsec,
						INT add_sub,
						bool one_nsec_accuracy)
{
	ULONG RETRYCOUNT = 100000;
	ULONG vy_count;

	volatile ULONG VARMAC_TCR;

	/* wait for previous(if any) time adjust/update to complete. */

	/*Poll*/
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		MAC_TCR_RGRD(VARMAC_TCR);
		if (GET_VALUE(
				VARMAC_TCR, MAC_TCR_TSUPDT_LPOS,
				MAC_TCR_TSUPDT_HPOS) == 0)
			break;

		vy_count++;
		mdelay(1);
	}

	if (add_sub) {
		/* If the new sec value needs to be subtracted with
		 * the system time, then MAC_STSUR reg should be
		 * programmed with (2^32 – <new_sec_value>)
		 */
		sec = (0x100000000ull - sec);

		/* If the new nsec value need to be subtracted with
		 * the system time, then MAC_STNSUR.TSSS field should be
		 * programmed with,
		 * (10^9 - <new_nsec_value>) if MAC_TCR.TSCTRLSSR is set or
		 * (2^31 - <new_nsec_value> if MAC_TCR.TSCTRLSSR is reset)
		 */
		if (one_nsec_accuracy)
			nsec = (0x3B9ACA00 - nsec);
		else
			nsec = (0x80000000 - nsec);
	}

	MAC_STSUR_RGWR(sec);
	MAC_STNSUR_TSSS_UDFWR(nsec);
	MAC_STNSUR_ADDSUB_UDFWR(add_sub);

	/* issue command to initialize system time with the value */
	/* specified in MAC_STSUR and MAC_STNSUR. */
	MAC_TCR_TSUPDT_UDFWR(0x1);
	/* wait for present time initialize to complete. */

	/*Poll*/
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		MAC_TCR_RGRD(VARMAC_TCR);
		if (GET_VALUE(
				VARMAC_TCR, MAC_TCR_TSUPDT_LPOS,
				MAC_TCR_TSUPDT_HPOS) == 0)
			break;
		vy_count++;
		mdelay(1);
	}

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to adjust the ptp operating frequency.
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_addend(UINT data)
{
	ULONG RETRYCOUNT = 100000;
	ULONG vy_count;
	volatile ULONG VARMAC_TCR;

	/* wait for previous(if any) added update to complete. */

	/*Poll*/
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		MAC_TCR_RGRD(VARMAC_TCR);
		if (GET_VALUE(
				VARMAC_TCR, MAC_TCR_TSADDREG_LPOS,
				MAC_TCR_TSADDREG_HPOS) == 0)
			break;

		vy_count++;
		mdelay(1);
	}

	MAC_TAR_RGWR(data);
	/* issue command to update the added value */
	MAC_TCR_TSADDREG_UDFWR(0x1);
	/* wait for present added update to complete. */

	/*Poll*/
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		MAC_TCR_RGRD(VARMAC_TCR);
		if (GET_VALUE(
				VARMAC_TCR, MAC_TCR_TSADDREG_LPOS,
				MAC_TCR_TSADDREG_HPOS) == 0)
			break;

		vy_count++;
		mdelay(1);
	}

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to initialize the system time
 * \param[in] sec
 * \param[in] nsec
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT init_systime(UINT sec,
			UINT nsec)
{
	ULONG RETRYCOUNT = 100000;
	ULONG vy_count;
	volatile ULONG VARMAC_TCR;

	/* wait for previous(if any) time initialize to complete. */

	/*Poll*/
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		MAC_TCR_RGRD(VARMAC_TCR);
		if (GET_VALUE(
				VARMAC_TCR, MAC_TCR_TSINIT_LPOS,
				MAC_TCR_TSINIT_HPOS) == 0)
			break;

		vy_count++;
		mdelay(1);
	}
	MAC_STSUR_RGWR(sec);
	MAC_STNSUR_RGWR(nsec);
	/* issue command to initialize system time with the value */
	/* specified in MAC_STSUR and MAC_STNSUR. */
	MAC_TCR_TSINIT_UDFWR(0x1);
	/* wait for present time initialize to complete. */

	/*Poll*/
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		MAC_TCR_RGRD(VARMAC_TCR);
		if (GET_VALUE(
				VARMAC_TCR, MAC_TCR_TSINIT_LPOS,
				MAC_TCR_TSINIT_HPOS) == 0)
			break;

		vy_count++;
		mdelay(1);
	}

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to enable HW time stamping
 * and receive frames
 * \param[in] count
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_hw_time_stamping(UINT config_val)
{
	MAC_TCR_RGWR(config_val);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used get the 64-bit of the timestamp
 * captured by the device for the corresponding received packet
 * in nanosecond.
 * \param[in] rxdesc
 * \return (unsigned long long) on success
 * \retval ns
 */

static ULONG_LONG get_rx_tstamp(t_RX_CONTEXT_DESC *rxdesc)
{
	ULONG_LONG ns;
	ULONG varrdes1;

	RX_CONTEXT_DESC_RDES0_ML_RD(rxdesc->RDES0, ns);
	RX_CONTEXT_DESC_RDES1_ML_RD(rxdesc->RDES1, varrdes1);
	ns = ns + (varrdes1 * 1000000000ull);

	return ns;
}

/*!
 * \brief This sequence is used to check whether the captured timestamp
 * for the corresponding received packet is valid or not.
 * Returns 0 if no context descriptor
 * Returns 1 if timestamp is valid
 * Returns 2 if time stamp is corrupted
 * \param[in] rxdesc
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static UINT get_rx_tstamp_status(t_RX_CONTEXT_DESC *rxdesc)
{
	UINT VAROWN;
	UINT VARCTXT;
	UINT VARRDES0;
	UINT VARRDES1;

	/* check for own bit and CTXT bit */
	RX_CONTEXT_DESC_RDES3_OWN_MLF_RD(rxdesc->RDES3, VAROWN);
	RX_CONTEXT_DESC_RDES3_CTXT_MLF_RD(rxdesc->RDES3, VARCTXT);
	if ((VAROWN == 0) && (VARCTXT == 0x1)) {
		RX_CONTEXT_DESC_RDES0_ML_RD(rxdesc->RDES0, VARRDES0);
		RX_CONTEXT_DESC_RDES1_ML_RD(rxdesc->RDES1, VARRDES1);
		if ((VARRDES0 == 0xffffffff) && (VARRDES1 == 0xffffffff))
			/* time stamp is corrupted */
			return 2;
		/* time stamp is valid */
		return 1;
	}
	/* no CONTEX desc to hold time stamp value */
	return 0;
}

/*!
 * \brief This sequence is used to check whether the timestamp value
 * is available in a context descriptor or not. Returns 1 if timestamp
 * is available else returns 0
 * \param[in] rxdesc
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static UINT rx_tstamp_available(t_RX_NORMAL_DESC *rxdesc)
{
	UINT VARRS1V;
	UINT VARTSA;

	RX_NORMAL_DESC_RDES3_RS1V_MLF_RD(rxdesc->RDES3, VARRS1V);
	if (VARRS1V == 1) {
		RX_NORMAL_DESC_RDES1_TSA_MLF_RD(rxdesc->RDES1, VARTSA);
		return VARTSA;
	} else {
		return 0;
	}
}

/*!
 * \brief This sequence is used get the least 64-bit of the timestamp
 * captured by the device for the corresponding transmit packet in nanosecond
 * \return (unsigned long long) on success
 * \retval ns
 */

static ULONG_LONG get_tx_tstamp_via_reg(void)
{
	ULONG_LONG ns;
	ULONG varmac_ttn;

	MAC_TTSN_TXTSSTSLO_UDFRD(ns);
	MAC_TTN_TXTSSTSHI_UDFRD(varmac_ttn);
	ns = ns + (varmac_ttn * 1000000000ull);

	return ns;
}

/*!
 * \brief This sequence is used to check whether a timestamp has been
 * captured for the corresponding transmit packet. Returns 1 if
 * timestamp is taken else returns 0
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static UINT get_tx_tstamp_status_via_reg(void)
{
	ULONG VARMAC_TCR;
	ULONG VARMAC_TTSN;

	/* device is configured to overwrite the timesatmp of
	 * earlier packet if driver has not yet read it.
	 */
	MAC_TCR_RGRD(VARMAC_TCR);
	if (GET_VALUE(
			VARMAC_TCR, MAC_TCR_TXTSSTSM_LPOS,
			MAC_TCR_TXTSSTSM_HPOS) == 1)
		/* nothing to do */
		return 0;

	/* timestamp of the current pkt is ignored or not captured */
	MAC_TTSN_RGRD(VARMAC_TTSN);
	VARMAC_TTSN = GET_VALUE(
		VARMAC_TTSN, MAC_TTSN_TXTSSTSMIS_LPOS,
		MAC_TTSN_TXTSSTSMIS_HPOS);
	if (VARMAC_TTSN == 1)
		return 0;
	else
		return 1;
}

/*!
 * \brief This sequence is used get the 64-bit of the timestamp captured
 * by the device for the corresponding transmit packet in nanosecond.
 * \param[in] txdesc
 * \return (unsigned long long) on success
 * \retval ns
 */

static ULONG_LONG get_tx_tstamp(t_TX_NORMAL_DESC *txdesc)
{
	ULONG_LONG ns;
	ULONG vartdes1;

	TX_NORMAL_DESC_TDES0_ML_RD(txdesc->TDES0, ns);
	TX_NORMAL_DESC_TDES1_ML_RD(txdesc->TDES1, vartdes1);
	ns = ns + (vartdes1 * 1000000000ull);

	return ns;
}

/*!
 * \brief This sequence is used to check whether a timestamp has been
 * captured for the corresponding transmit packet. Returns 1 if
 * timestamp is taken else returns 0
 * \param[in] txdesc
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static UINT get_tx_tstamp_status(t_TX_NORMAL_DESC *txdesc)
{
	UINT VARTDES3;

	TX_NORMAL_DESC_TDES3_ML_RD(txdesc->TDES3, VARTDES3);

	return (VARTDES3 & 0x20000);
}

/*!
 * \brief This sequence is used to enable/disable split header feature
 * \param[in] QINX
 * \param[in] sph_en
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_split_header_mode(UINT QINX,
				    USHORT sph_en)
{
	DMA_CR_SPH_UDFWR(QINX, sph_en);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure header size in case
 * of split header feature
 * \param[in] header_size
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_header_size(USHORT header_size)
{
	if (header_size == 64)
		MAC_MECR_HDSMS_UDFWR(0);
	else if (header_size == 128)
		MAC_MECR_HDSMS_UDFWR(0x1);
	else if (header_size == 256)
		MAC_MECR_HDSMS_UDFWR(0x2);
	else if (header_size == 512)
		MAC_MECR_HDSMS_UDFWR(0x3);
	else
		MAC_MECR_HDSMS_UDFWR(0x4);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to set tx queue operating mode for Queue[0 - 7]
 * \param[in] QINX
 * \param[in] q_mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_tx_queue_operating_mode(UINT QINX,
				       UINT q_mode)
{
	MTL_QTOMR_TXQEN_UDFWR(QINX, q_mode);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to select Tx Scheduling
 * Algorithm for AVB feature for Queue[1 - 7]
 * \param[in] avb_algo
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_avb_algorithm(UINT QINX, UCHAR avb_algo)
{
	MTL_QECR_AVALG_UDFWR(QINX, avb_algo);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure credit-control for Queue[1 - 7]
 * \param[in] QINX
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_credit_control(UINT QINX, UINT cc)
{
	MTL_QECR_CC_UDFWR(QINX, cc);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure send slope credit value
 * required for the credit-based shaper alogorithm for Queue[1 - 7]
 * \param[in] QINX
 * \param[in] sendSlope
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_send_slope(UINT QINX,
			     UINT SENDSLOPE)
{
	MTL_QSSCR_SSC_UDFWR(QINX, SENDSLOPE);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure idle slope credit value
 * required for the credit-based shaper alogorithm for Queue[1 - 7]
 * \param[in] QINX
 * \param[in] idleSlope
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_idle_slope(UINT QINX,
			     UINT IDLESLOPE)
{
	MTL_QW_ISCQW_UDFWR(QINX, IDLESLOPE);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure low credit value
 * required for the credit-based shaper alogorithm for Queue[1 - 7]
 * \param[in] QINX
 * \param[in] lowCredit
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_low_credit(UINT QINX,
			     UINT LOWCREDIT)
{
	INT LOWCREDIT_NEG = LOWCREDIT;

	pr_crit(
		"lowCreidt = %08x lowCredit_neg:%08x\n",
		LOWCREDIT, LOWCREDIT_NEG);
	MTL_QLCR_LC_UDFWR(QINX, LOWCREDIT_NEG);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to enable/disable slot number check When set,
 * this bit enables the checking of the slot number programmed in the TX
 * descriptor with the current reference given in the RSN field. The DMA fetches
 * the data from the corresponding buffer only when the slot number is: equal to
 * the reference slot number or  ahead of the reference slot number by one.
 * \param[in] QINX
 * \param[in] slot_check
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_slot_num_check(UINT QINX, UCHAR slot_check)
{
	DMA_SFCSR_ESC_UDFWR(QINX, slot_check);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to enable/disable advance slot check When set,
 * this bit enables the DAM to fetch the data from the buffer when the slot
 * number programmed in TX descriptor is equal to the reference slot number
 * given in RSN field or ahead of the reference number by upto two slots
 * \param[in] QINX
 * \param[in] adv_slot_check
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_advance_slot_num_check(UINT QINX, UCHAR adv_slot_check)
{
	DMA_SFCSR_ASC_UDFWR(QINX, adv_slot_check);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure high credit value required
 * for the credit-based shaper alogorithm for Queue[1 - 7]
 * \param[in] QINX
 * \param[in] hiCredit
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_high_credit(UINT QINX,
			      UINT HICREDIT)
{
	MTL_QHCR_HC_UDFWR(QINX, HICREDIT);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to set weights for DCB feature for Queue[0 - 7]
 * \param[in] QINX
 * \param[in] q_weight
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_dcb_queue_weight(UINT QINX,
				UINT q_weight)
{
	MTL_QW_ISCQW_UDFWR(QINX, q_weight);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to select Tx Scheduling
 * Algorithm for DCB feature
 * \param[in] dcb_algo
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_dcb_algorithm(UCHAR dcb_algo)
{
	MTL_OMR_SCHALG_UDFWR(dcb_algo);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to get Tx queue count
 * \param[in] count
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

UCHAR get_tx_queue_count(void)
{
	UCHAR count;
	ULONG VARMAC_HFR2;

	MAC_HFR2_RGRD(VARMAC_HFR2);
	count = GET_VALUE(
		VARMAC_HFR2, MAC_HFR2_TXQCNT_LPOS, MAC_HFR2_TXQCNT_HPOS);

	return (count + 1);
}

/*!
 * \brief This sequence is used to get Rx queue count
 * \param[in] count
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

UCHAR get_rx_queue_count(void)
{
	UCHAR count;
	ULONG VARMAC_HFR2;

	MAC_HFR2_RGRD(VARMAC_HFR2);
	count = GET_VALUE(
		VARMAC_HFR2, MAC_HFR2_RXQCNT_LPOS, MAC_HFR2_RXQCNT_HPOS);

	return (count + 1);
}

/*!
 * \brief This sequence is used to disables all Tx/Rx MMC interrupts
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT disable_mmc_interrupts(void)
{
	/* disable all TX interrupts */
	MMC_INTR_MASK_TX_RGWR(0xffffffff);
	/* disable all RX interrupts */
	MMC_INTR_MASK_RX_RGWR(0xffffffff);
	/* Disable MMC Rx Interrupts for IPC */
	MMC_IPC_INTR_MASK_RX_RGWR(0xffffffff);
	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure MMC counters
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_mmc_counters(void)
{
	ULONG VARMMC_CNTRL;

	/* set COUNTER RESET */
	/* set RESET ON READ */
	/* set COUNTER PRESET */
	/* set FULL_HALF PRESET */
	MMC_CNTRL_RGRD(VARMMC_CNTRL);
	VARMMC_CNTRL = VARMMC_CNTRL & (ULONG)(0x10a);
	VARMMC_CNTRL = VARMMC_CNTRL | ((0x1) << 0) | ((0x1) << 2) |
		((0x1) << 4) | ((0x1) << 5);
	MMC_CNTRL_RGWR(VARMMC_CNTRL);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to disable given DMA channel rx interrupts
 * \param[in] QINX
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT disable_rx_interrupt(UINT QINX)
{
	DMA_IER_RBUE_UDFWR(QINX, 0);
	DMA_IER_RIE_UDFWR(QINX, 0);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to enable given DMA channel rx interrupts
 * \param[in] QINX
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT enable_rx_interrupt(UINT QINX)
{
	DMA_IER_RBUE_UDFWR(QINX, 0x1);
	DMA_IER_RIE_UDFWR(QINX, 0x1);

	return Y_SUCCESS;
}

static VOID configure_sa_via_reg(u32 cmd)
{
	MAC_MCR_SARC_UDFWR(cmd);
}

static VOID configure_mac_addr1_reg(UCHAR *mac_addr)
{
	MAC_MA1HR_RGWR(((mac_addr[5] << 8) | (mac_addr[4])));
	MAC_MA1LR_RGWR(((mac_addr[3] << 24) | (mac_addr[2] << 16) |
			(mac_addr[1] << 8) | (mac_addr[0])));
}

static VOID configure_mac_addr0_reg(UCHAR *mac_addr)
{
	MAC_MA0HR_RGWR(((mac_addr[5] << 8) | (mac_addr[4])));
	MAC_MA0LR_RGWR(((mac_addr[3] << 24) | (mac_addr[2] << 16) |
			(mac_addr[1] << 8) | (mac_addr[0])));
}

static VOID config_rx_outer_vlan_stripping(u32 cmd)
{
	MAC_VLANTR_EVLS_UDFWR(cmd);
}

static VOID config_rx_inner_vlan_stripping(u32 cmd)
{
	MAC_VLANTR_EIVLS_UDFWR(cmd);
}

static VOID config_ptpoffload_engine(UINT pto_cr, UINT mc_uc)
{
	MAC_PTO_CR_RGWR(pto_cr);
	MAC_TCR_TSENMACADDR_UDFWR(mc_uc);
}

static VOID configure_reg_vlan_control(
	struct DWC_ETH_QOS_tx_wrapper_descriptor *desc_data)
{
	USHORT vlan_id = desc_data->vlan_tag_id;
	UINT vlan_control = desc_data->tx_vlan_tag_ctrl;

	MAC_VLANTIRR_RGWR(((1 << 18) | (vlan_control << 16) | (vlan_id << 0)));
}

static VOID configure_desc_vlan_control(struct DWC_ETH_QOS_prv_data *pdata)
{
	MAC_VLANTIRR_RGWR((1 << 20));
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT configure_mac_for_vlan_pkt(void)
{
	/* Do not strip VLAN Tag*/
	MAC_VLANTR_EVLS_UDFWR(0x0);
	/* Enable operation on the outer VLAN Tag, if present */
	MAC_VLANTR_ERIVLT_UDFWR(0);
	/* Disable double VLAN Tag processing on TX and RX */
	MAC_VLANTR_EDVLP_UDFWR(0);
	/* Enable VLAN Tag in RX Status. */
	MAC_VLANTR_EVLRXS_UDFWR(0x1);
	/* Disable VLAN Type Check */
	MAC_VLANTR_DOVLTC_UDFWR(0x1);

	/* configure MAC to get VLAN Tag to be inserted/replaced from */
	/* TX descriptor(context desc) */
	MAC_VLANTIRR_VLTI_UDFWR(0x1);
	/* insert/replace C_VLAN in 13th ans 14th bytes of transmitted frames */
	MAC_VLANTIRR_CSVL_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_pblx8(UINT QINX, UINT val)
{
	DMA_CR_PBLX8_UDFWR(QINX, val);

	return Y_SUCCESS;
}

/*!
 * \return INT
 * \retval programmed Tx PBL value
 */

static INT get_tx_pbl_val(UINT QINX)
{
	UINT tx_pbl;

	DMA_TCR_PBL_UDFRD(QINX, tx_pbl);

	return tx_pbl;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_tx_pbl_val(UINT QINX, UINT tx_pbl)
{
	DMA_TCR_PBL_UDFWR(QINX, tx_pbl);

	return Y_SUCCESS;
}

/*!
 * \return INT
 * \retval programmed Rx PBL value
 */

static INT get_rx_pbl_val(UINT QINX)
{
	UINT rx_pbl;

	DMA_RCR_PBL_UDFRD(QINX, rx_pbl);

	return rx_pbl;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_rx_pbl_val(UINT QINX, UINT rx_pbl)
{
	DMA_RCR_PBL_UDFWR(QINX, rx_pbl);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_axi_rorl_val(UINT axi_rorl)
{
	DMA_SBUS_RD_OSR_LMT_UDFWR(axi_rorl);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_axi_worl_val(UINT axi_worl)
{
	DMA_SBUS_WR_OSR_LMT_UDFWR(axi_worl);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_axi_pbl_val(UINT axi_pbl)
{
	UINT VARDMA_SBUS;

	DMA_SBUS_RGRD(VARDMA_SBUS);
	VARDMA_SBUS &= ~DMA_SBUS_AXI_PBL_MASK;
	VARDMA_SBUS |= axi_pbl;
	DMA_SBUS_RGWR(VARDMA_SBUS);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_incr_incrx_mode(UINT val)
{
	DMA_SBUS_UNDEF_FB_UDFWR(val);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_osf_mode(UINT QINX, UINT val)
{
	DMA_TCR_OSP_UDFWR(QINX, val);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_rsf_mode(UINT QINX, UINT val)
{
	/* if (QINX == 0) { */
		/* MTL_Q0ROMR_RSF_UdfWr(val); */
	/* } */
	/* else { */
		MTL_QROMR_RSF_UDFWR(QINX, val);
	/* } */

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_tsf_mode(UINT QINX, UINT val)
{
	MTL_QTOMR_TSF_UDFWR(QINX, val);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_rx_threshold(UINT QINX, UINT val)
{
	MTL_QROMR_RTC_UDFWR(QINX, val);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_tx_threshold(UINT QINX, UINT val)
{
	MTL_QTOMR_TTC_UDFWR(QINX, val);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT config_rx_watchdog_timer(UINT QINX, u32 riwt)
{
	DMA_RIWTR_RWT_UDFWR(QINX, riwt);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT enable_magic_pmt_operation(void)
{
	MAC_PMTCSR_MGKPKTEN_UDFWR(0x1);
	MAC_PMTCSR_PWRDWN_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT disable_magic_pmt_operation(void)
{
	UINT VARPMTCSR_PWRDWN;

	MAC_PMTCSR_MGKPKTEN_UDFWR(0x0);
	MAC_PMTCSR_PWRDWN_UDFRD(VARPMTCSR_PWRDWN);
	if (VARPMTCSR_PWRDWN == 0x1)
		MAC_PMTCSR_PWRDWN_UDFWR(0x0);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT enable_remote_pmt_operation(void)
{
	MAC_PMTCSR_RWKPKTEN_UDFWR(0x1);
	MAC_PMTCSR_PWRDWN_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT disable_remote_pmt_operation(void)
{
	UINT VARPMTCSR_PWRDWN;

	MAC_PMTCSR_RWKPKTEN_UDFWR(0x0);
	MAC_PMTCSR_PWRDWN_UDFRD(VARPMTCSR_PWRDWN);
	if (VARPMTCSR_PWRDWN == 0x1)
		MAC_PMTCSR_PWRDWN_UDFWR(0x0);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT configure_rwk_filter_registers(UINT *value, UINT count)
{
	UINT i;

	MAC_PMTCSR_RWKFILTRST_UDFWR(1);
	for (i = 0; i < count; i++)
		MAC_RWPFFR_RGWR(value[i]);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT disable_tx_flow_ctrl(UINT QINX)
{
	MAC_QTFCR_TFE_UDFWR(QINX, 0);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT enable_tx_flow_ctrl(UINT QINX)
{
	MAC_QTFCR_TFE_UDFWR(QINX, 1);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT disable_rx_flow_ctrl(void)
{
	MAC_RFCR_RFE_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT enable_rx_flow_ctrl(void)
{
	MAC_RFCR_RFE_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \param[in] QINX
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT stop_dma_rx(UINT QINX)
{
	ULONG RETRYCOUNT = 10;
	ULONG vy_count;
	volatile ULONG VARDMA_DSR0;
	volatile ULONG VARDMA_DSR1;
	volatile ULONG VARDMA_DSR2;

	/* issue Rx dma stop command */
	DMA_RCR_ST_UDFWR(QINX, 0);

	/* wait for Rx DMA to stop, ie wait till Rx DMA
	 * goes in either Running or Suspend state.
	 */
	if (QINX == 0) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Rx Channel 0 stop failed, DSR0 = %#lx\n",
					VARDMA_DSR0);
				return -Y_FAILURE;
			}

			DMA_DSR0_RGRD(VARDMA_DSR0);
			if ((GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_RPS0_LPOS,
					DMA_DSR0_RPS0_HPOS) == 0x3) ||
				(GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_RPS0_LPOS,
					DMA_DSR0_RPS0_HPOS) == 0x4) ||
				(GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_RPS0_LPOS,
					DMA_DSR0_RPS0_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 1) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Rx Channel 1 stop failed, DSR0 = %#lx\n",
					VARDMA_DSR0);
				return -Y_FAILURE;
			}

			DMA_DSR0_RGRD(VARDMA_DSR0);
			if ((GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_RPS1_LPOS,
					DMA_DSR0_RPS1_HPOS) == 0x3) ||
				(GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_RPS1_LPOS,
					DMA_DSR0_RPS1_HPOS) == 0x4) ||
				(GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_RPS1_LPOS,
					DMA_DSR0_RPS1_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 2) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Rx Channel 2 stop failed, DSR0 = %#lx\n",
					VARDMA_DSR0);
				return -Y_FAILURE;
			}

			DMA_DSR0_RGRD(VARDMA_DSR0);
			if ((GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_RPS2_LPOS,
					DMA_DSR0_RPS2_HPOS) == 0x3) ||
				(GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_RPS2_LPOS,
					DMA_DSR0_RPS2_HPOS) == 0x4) ||
				(GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_RPS2_LPOS,
					DMA_DSR0_RPS2_HPOS) == 0x0))
				break;
			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 3) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Rx Channel 3 stop failed, DSR0 = %#lx\n",
					VARDMA_DSR1);
				return -Y_FAILURE;
			}

			DMA_DSR1_RGRD(VARDMA_DSR1);
			if ((GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS3_LPOS,
					DMA_DSR1_RPS3_HPOS) == 0x3) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS3_LPOS,
					DMA_DSR1_RPS3_HPOS) == 0x4) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS3_LPOS,
					DMA_DSR1_RPS3_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 4) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Rx Channel 4 stop failed, DSR0 = %#lx\n",
					VARDMA_DSR1);
				return -Y_FAILURE;
			}

			DMA_DSR1_RGRD(VARDMA_DSR1);
			if ((GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS4_LPOS,
					DMA_DSR1_RPS4_HPOS) == 0x3) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS4_LPOS,
					DMA_DSR1_RPS4_HPOS) == 0x4) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS4_LPOS,
					DMA_DSR1_RPS4_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 5) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Rx Channel 5 stop failed, DSR0 = %#lx\n",
					VARDMA_DSR1);
				return -Y_FAILURE;
			}

			DMA_DSR1_RGRD(VARDMA_DSR1);
			if ((GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS5_LPOS,
					DMA_DSR1_RPS5_HPOS) == 0x3) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS5_LPOS,
					DMA_DSR1_RPS5_HPOS) == 0x4) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS5_LPOS,
					DMA_DSR1_RPS5_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 6) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Rx Channel 6 stop failed, DSR0 = %#lx\n",
					VARDMA_DSR1);
				return -Y_FAILURE;
			}

			DMA_DSR1_RGRD(VARDMA_DSR1);
			if ((GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS6_LPOS,
					DMA_DSR1_RPS6_HPOS) == 0x3) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS6_LPOS,
					DMA_DSR1_RPS6_HPOS) == 0x4) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_RPS6_LPOS,
					DMA_DSR1_RPS6_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 7) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Rx Channel 7 stop failed, DSR0 = %#lx\n",
					VARDMA_DSR2);
				return -Y_FAILURE;
			}

			DMA_DSR2_RGRD(VARDMA_DSR2);
			if ((GET_VALUE(
					VARDMA_DSR2, DMA_DSR2_RPS7_LPOS,
					DMA_DSR2_RPS7_HPOS) == 0x3) ||
				(GET_VALUE(
					VARDMA_DSR2, DMA_DSR2_RPS7_LPOS,
					DMA_DSR2_RPS7_HPOS) == 0x4) ||
				(GET_VALUE(
					VARDMA_DSR2, DMA_DSR2_RPS7_LPOS,
					DMA_DSR2_RPS7_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	}

	return Y_SUCCESS;
}

/*!
 * \param[in] QINX
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT start_dma_rx(UINT QINX)
{
	DMA_RCR_ST_UDFWR(QINX, 0x1);

	return Y_SUCCESS;
}

/*!
 * \param[in] QINX
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT stop_dma_tx(UINT QINX)
{
	ULONG RETRYCOUNT = 10;
	ULONG vy_count;
	volatile ULONG VARDMA_DSR0;
	volatile ULONG VARDMA_DSR1;
	volatile ULONG VARDMA_DSR2;

	/* issue Tx dma stop command */
	DMA_TCR_ST_UDFWR(QINX, 0);

	/* wait for Tx DMA to stop, ie wait till Tx DMA
	 * goes in Suspend state or stopped state.
	 */
	if (QINX == 0) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Tx Channel 0 stop failed, DSR0 = %lx\n",
					VARDMA_DSR0);
				return -Y_FAILURE;
			}

			DMA_DSR0_RGRD(VARDMA_DSR0);
			if ((GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_TPS0_LPOS,
					DMA_DSR0_TPS0_HPOS) == 0x6) ||
				(GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_TPS0_LPOS,
					DMA_DSR0_TPS0_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 1) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Channel 1 stop failed, DSR0 = %lx\n",
					VARDMA_DSR0);
				return -Y_FAILURE;
			}

			DMA_DSR0_RGRD(VARDMA_DSR0);
			if ((GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_TPS1_LPOS,
					DMA_DSR0_TPS1_HPOS) == 0x6) ||
				(GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_TPS1_LPOS,
					DMA_DSR0_TPS1_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 2) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Channel 2 stop failed, DSR0 = %lx\n",
					VARDMA_DSR0);
				return -Y_FAILURE;
			}

			DMA_DSR0_RGRD(VARDMA_DSR0);
			if ((GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_TPS2_LPOS,
					DMA_DSR0_TPS2_HPOS) == 0x6) ||
				(GET_VALUE(
					VARDMA_DSR0, DMA_DSR0_TPS2_LPOS,
					DMA_DSR0_TPS2_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 3) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Channel 3 stop failed, DSR0 = %lx\n",
					VARDMA_DSR1);
				return -Y_FAILURE;
			}

			DMA_DSR1_RGRD(VARDMA_DSR1);
			if ((GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_TPS3_LPOS,
					DMA_DSR1_TPS3_HPOS) == 0x6) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_TPS3_LPOS,
					DMA_DSR1_TPS3_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 4) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Channel 4 stop failed, DSR0 = %lx\n",
					VARDMA_DSR1);
				return -Y_FAILURE;
			}

			DMA_DSR1_RGRD(VARDMA_DSR1);
			if ((GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_TPS4_LPOS,
					DMA_DSR1_TPS4_HPOS) == 0x6) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_TPS4_LPOS,
					DMA_DSR1_TPS4_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 5) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Channel 5 stop failed, DSR0 = %lx\n",
					VARDMA_DSR1);
				return -Y_FAILURE;
			}

			DMA_DSR1_RGRD(VARDMA_DSR1);
			if ((GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_TPS5_LPOS,
					DMA_DSR1_TPS5_HPOS) == 0x6) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_TPS5_LPOS,
					DMA_DSR1_TPS5_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 6) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Channel 6 stop failed, DSR0 = %lx\n",
					VARDMA_DSR1);
				return -Y_FAILURE;
			}

			DMA_DSR1_RGRD(VARDMA_DSR1);
			if ((GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_TPS6_LPOS,
					DMA_DSR1_TPS6_HPOS) == 0x6) ||
				(GET_VALUE(
					VARDMA_DSR1, DMA_DSR1_TPS6_LPOS,
					DMA_DSR1_TPS6_HPOS) == 0x0))
				break;

			vy_count++;
			mdelay(1);
		}
	} else if (QINX == 7) {
		/*Poll*/
		vy_count = 0;
		while (1) {
			if (vy_count > RETRYCOUNT) {
				EMACERR(
					"ERROR: Channel 7 stop failed, DSR0 = %lx\n",
					VARDMA_DSR2);
				return -Y_FAILURE;
		}

		DMA_DSR2_RGRD(VARDMA_DSR2);
		if ((GET_VALUE(
				VARDMA_DSR2, DMA_DSR2_TPS7_LPOS,
				DMA_DSR2_TPS7_HPOS) == 0x6) ||
			(GET_VALUE(
				VARDMA_DSR2, DMA_DSR2_TPS7_LPOS,
				DMA_DSR2_TPS7_HPOS) == 0x0))
			break;

			vy_count++;
			mdelay(1);
		}
	}

	return Y_SUCCESS;
}

/*!
 * \param[in] QINX
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT start_dma_tx(UINT QINX)
{
	DMA_TCR_ST_UDFWR(QINX, 0x1);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT stop_mac_tx_rx(void)
{
	ULONG VARMAC_MCR;

	MAC_MCR_RGRD(VARMAC_MCR);
	VARMAC_MCR = VARMAC_MCR & (ULONG)(0xffffff7c);
	VARMAC_MCR = VARMAC_MCR | ((0) << 1) | ((0) << 0);
	MAC_MCR_RGWR(VARMAC_MCR);

	return Y_SUCCESS;
}

/*!
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT start_mac_tx_rx(void)
{
	ULONG VARMAC_MCR;

	MAC_MCR_RGRD(VARMAC_MCR);
	VARMAC_MCR = VARMAC_MCR & (ULONG)(0xffffff7c);
	VARMAC_MCR = VARMAC_MCR | ((0x1) << 1) | ((0x1) << 0);
	MAC_MCR_RGWR(VARMAC_MCR);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to enable DMA interrupts
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT enable_tx_dma_interrupts(UINT QINX,
	struct DWC_ETH_QOS_prv_data *pdata)
{
	UINT tmp;
	ULONG VARDMA_SR;
	ULONG VARDMA_IER;
	ULONG DMA_TX_INT_MASK = 0xFC07;
	ULONG DMA_TX_INT_RESET_MASK = 0xFBC0;

	/* clear all the interrupts which are set */
	DMA_SR_RGRD(QINX, VARDMA_SR);
	tmp = VARDMA_SR & DMA_TX_INT_MASK;
	DMA_SR_RGWR(QINX, tmp);

	/* Enable following interrupts for Queue 0 */
	/* NIE - Normal Interrupt Summary Enable */
	/* AIE - Abnormal Interrupt Summary Enable */
	/* FBE - Fatal Bus Error Enable */
	/* TXSE - Transmit Stopped Enable */
	DMA_IER_RGRD(QINX, VARDMA_IER);
	/* Reset all Tx interrupt bits */
	VARDMA_IER = VARDMA_IER & DMA_TX_INT_RESET_MASK;

	VARDMA_IER = VARDMA_IER | ((0x1) << 1) |
	     ((0x1) << 12) | ((0x1) << 14) | ((0x1) << 15);

#ifndef DWC_ETH_QOS_TXPOLLING_MODE_ENABLE
	/* TIE - Transmit Interrupt Enable */
	/* TBUE - Transmit Buffer Unavailable Enable */
	if (!(pdata->ipa_enabled && QINX == IPA_DMA_TX_CH))
		VARDMA_IER |= ((0x1) << 0);
#endif

	DMA_IER_RGWR(QINX, VARDMA_IER);

	return Y_SUCCESS;
}

static INT enable_rx_dma_interrupts(UINT QINX,
	struct DWC_ETH_QOS_prv_data *pdata)
{
	UINT tmp;
	ULONG VARDMA_SR;
	ULONG VARDMA_IER;
	ULONG DMA_RX_INT_MASK = 0xFBC0;
	ULONG DMA_RX_INT_RESET_MASK = 0xF407;

	/* clear all the interrupts which are set */
	DMA_SR_RGRD(QINX, VARDMA_SR);
	tmp = VARDMA_SR & DMA_RX_INT_MASK;
	DMA_SR_RGWR(QINX, tmp);
	/* Enable following interrupts for Queue 0 */
	/* NIE - Normal Interrupt Summary Enable */
	/* AIE - Abnormal Interrupt Summary Enable */
	/* FBE - Fatal Bus Error Enable */
	/* RIE - Receive Interrupt Enable */
	/* RBUE - Receive Buffer Unavailable Enable  */
	/* RSE - Receive Stopped Enable */
	DMA_IER_RGRD(QINX, VARDMA_IER);
	/* Reset all Rx interrupt bits */
	VARDMA_IER = VARDMA_IER & (ULONG)(DMA_RX_INT_RESET_MASK);

	VARDMA_IER = VARDMA_IER | ((0x1) << 7) |
		((0x1) << 8) | ((0x1) << 14) | ((0x1) << 12) |
	    ((0x1) << 15);

	/* RIE - Receive Interrupt Enable */
	if (!(pdata->ipa_enabled && QINX == IPA_DMA_RX_CH))
		VARDMA_IER |= ((0x1) << 6);

	DMA_IER_RGWR(QINX, VARDMA_IER);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure the MAC registers for
 * GMII-1000Mbps speed
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_gmii_speed(void)
{
	MAC_MCR_PS_UDFWR(0);
	MAC_MCR_FES_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure the MAC registers for
 * MII-10Mpbs speed
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_mii_speed_10(void)
{
	MAC_MCR_PS_UDFWR(0x1);
	MAC_MCR_FES_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure the MAC registers for
 * MII-100Mpbs speed
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_mii_speed_100(void)
{
	MAC_MCR_PS_UDFWR(0x1);
	MAC_MCR_FES_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure the MAC registers for
 * half duplex mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_half_duplex(void)
{
	MAC_MCR_DM_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure the MAC registers for
 * full duplex mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_full_duplex(void)
{
	MAC_MCR_DM_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure the device in list of
 * multicast mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_multicast_list_mode(void)
{
	MAC_MPFR_HMC_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure the device in unicast mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_unicast_mode(void)
{
	MAC_MPFR_HUC_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure the device in all multicast mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_all_multicast_mode(void)
{
	MAC_MPFR_PM_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to configure the device in promiscuous mode
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT set_promiscuous_mode(void)
{
	MAC_MPFR_PR_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to write into phy registers
 * \param[in] phy_id
 * \param[in] phy_reg
 * \param[in] phy_reg_data
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT write_phy_regs(INT phy_id, INT phy_reg, INT phy_reg_data)
{
	ULONG RETRYCOUNT = 5000;
	ULONG vy_count;
	volatile ULONG VARMAC_GMIIAR;

	/* wait for any previous MII read/write operation to complete */

	/*Poll Until Poll Condition */
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		vy_count++;
		udelay(200);

		MAC_GMIIAR_RGRD(VARMAC_GMIIAR);
		if (GET_VALUE(
			VARMAC_GMIIAR, MAC_GMIIAR_GB_LPOS,
			MAC_GMIIAR_GB_HPOS) == 0)
			break;
	}
	/* write the data */
	MAC_GMIIDR_GD_UDFWR(phy_reg_data);
	/* initiate the MII write operation by updating desired */
	/* phy address/id (0 - 31) */
	/* phy register offset */
	/* CSR Clock Range (20 - 35MHz) */
	/* Select write operation */
	/* set busy bit */
	MAC_GMIIAR_RGRD(VARMAC_GMIIAR);
	VARMAC_GMIIAR = VARMAC_GMIIAR & (ULONG)(0x12);
	VARMAC_GMIIAR =
	    VARMAC_GMIIAR | ((phy_id) << 21) | ((phy_reg) << 16) | ((0x1) << 8)
	    | ((0x1) << 2) | ((0x1) << 0);
	MAC_GMIIAR_RGWR(VARMAC_GMIIAR);

	/*DELAY IMPLEMENTATION USING udelay() */
	udelay(10);
	/* wait for MII write operation to complete */

	/*Poll Until Poll Condition */
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		vy_count++;
		udelay(200);

		MAC_GMIIAR_RGRD(VARMAC_GMIIAR);
		if (GET_VALUE(
			VARMAC_GMIIAR, MAC_GMIIAR_GB_LPOS,
			MAC_GMIIAR_GB_HPOS) == 0)
			break;
	}

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to read the phy registers
 * \param[in] phy_id
 * \param[in] phy_reg
 * \param[out] phy_reg_data
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT read_phy_regs(INT phy_id, INT phy_reg, INT *phy_reg_data)
{
	ULONG RETRYCOUNT = 5000;
	ULONG vy_count;
	volatile ULONG VARMAC_GMIIAR;
	ULONG VARMAC_GMIIDR;

	/* wait for any previous MII read/write operation to complete */

	/*Poll Until Poll Condition */
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		vy_count++;
		udelay(200);
		MAC_GMIIAR_RGRD(VARMAC_GMIIAR);
		if (GET_VALUE(
				VARMAC_GMIIAR, MAC_GMIIAR_GB_LPOS,
				MAC_GMIIAR_GB_HPOS) == 0)
			break;
	}
	/* initiate the MII read operation by updating desired */
	/* phy address/id (0 - 31) */
	/* phy register offset */
	/* CSR Clock Range (20 - 35MHz) */
	/* Select read operation */
	/* set busy bit */
	MAC_GMIIAR_RGRD(VARMAC_GMIIAR);
	VARMAC_GMIIAR = VARMAC_GMIIAR & (ULONG)(0x12);
	VARMAC_GMIIAR =
	    VARMAC_GMIIAR | ((phy_id) << 21) | ((phy_reg) << 16) | ((0x1) << 8)
	    | ((0x3) << 2) | ((0x1) << 0);
	MAC_GMIIAR_RGWR(VARMAC_GMIIAR);

	/*DELAY IMPLEMENTATION USING udelay() */
	udelay(10);
	/* wait for MII write operation to complete */

	/*Poll Until Poll Condition */
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT)
			return -Y_FAILURE;

		vy_count++;
		udelay(200);

		MAC_GMIIAR_RGRD(VARMAC_GMIIAR);
		if (GET_VALUE(
				VARMAC_GMIIAR, MAC_GMIIAR_GB_LPOS,
				MAC_GMIIAR_GB_HPOS) == 0)
			break;
	}
	/* read the data */
	MAC_GMIIDR_RGRD(VARMAC_GMIIDR);
	*phy_reg_data = GET_VALUE(
		VARMAC_GMIIDR, MAC_GMIIDR_GD_LPOS, MAC_GMIIDR_GD_HPOS);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to check whether transmitted pkts have
 * fifo under run loss error or not, returns 1 if fifo under run error
 * else returns 0
 * \param[in] txdesc
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT tx_fifo_underrun(t_TX_NORMAL_DESC *txdesc)
{
	UINT VARTDES3;

	/* check TDES3.UF bit */
	TX_NORMAL_DESC_TDES3_ML_RD(txdesc->TDES3, VARTDES3);
	if ((VARTDES3 & 0x4) == 0x4)
		return 1;
	else
		return 0;
}

/*!
 * \brief This sequence is used to check whether transmitted pkts have
 * carrier loss error or not, returns 1 if carrier loss error else returns 0
 * \param[in] txdesc
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT tx_carrier_lost_error(t_TX_NORMAL_DESC *txdesc)
{
	UINT VARTDES3;

	/* check TDES3.LoC and TDES3.NC bits */
	TX_NORMAL_DESC_TDES3_ML_RD(txdesc->TDES3, VARTDES3);
	if (((VARTDES3 & 0x800) == 0x800) || ((VARTDES3 & 0x400) == 0x400))
		return 1;
	else
		return 0;
}

/*!
 * \brief This sequence is used to check whether transmission is aborted
 * or not returns 1 if transmission is aborted else returns 0
 * \param[in] txdesc
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT tx_aborted_error(t_TX_NORMAL_DESC *txdesc)
{
	UINT VARTDES3;

	/* check for TDES3.LC and TDES3.EC */
	TX_NORMAL_DESC_TDES3_ML_RD(txdesc->TDES3, VARTDES3);
	if (((VARTDES3 & 0x200) == 0x200) || ((VARTDES3 & 0x100) == 0x100))
		return 1;
	else
		return 0;
}

/*!
 * \brief This sequence is used to check whether the pkt transmitted is
 * successful or not, returns 1 if transmission is success else returns 0
 * \param[in] txdesc
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT tx_complete(t_TX_NORMAL_DESC *txdesc)
{
	UINT VAROWN;

	TX_NORMAL_DESC_TDES3_OWN_MLF_RD(txdesc->TDES3, VAROWN);
	if (VAROWN == 0)
		return 1;
	else
		return 0;
}

/*!
 * \brief This sequence is used to check whethet rx csum is enabled/disabled
 * returns 1 if rx csum is enabled else returns 0
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT get_rx_csum_status(void)
{
	ULONG VARMAC_MCR;

	MAC_MCR_RGRD(VARMAC_MCR);
	if (GET_VALUE(VARMAC_MCR, MAC_MCR_IPC_LPOS, MAC_MCR_IPC_HPOS)
		== 0x1) {
		return 1;
	} else {
		return 0;
	}
}

/*!
 * \brief This sequence is used to disable the rx csum
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT disable_rx_csum(void)
{
	/* enable rx checksum */
	MAC_MCR_IPC_UDFWR(0);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to enable the rx csum
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT enable_rx_csum(void)
{
	/* enable rx checksum */
	MAC_MCR_IPC_UDFWR(0x1);

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to reinitialize the TX descriptor fields,
 * so that device can reuse the descriptors
 * \param[in] idx
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT tx_descriptor_reset(UINT idx, struct DWC_ETH_QOS_prv_data *pdata,
			       UINT QINX)
{
	struct s_TX_NORMAL_DESC *TX_NORMAL_DESC =
		GET_TX_DESC_PTR(QINX, idx);

	DBGPR("-->tx_descriptor_reset\n");

	/* update buffer 1 address pointer to zero */
	TX_NORMAL_DESC_TDES0_ML_WR(TX_NORMAL_DESC->TDES0, 0);
	/* update buffer 2 address pointer to zero */
	TX_NORMAL_DESC_TDES1_ML_WR(TX_NORMAL_DESC->TDES1, 0);
	/* set all other control bits (IC, TTSE, B2L & B1L) to zero */
	TX_NORMAL_DESC_TDES2_ML_WR(TX_NORMAL_DESC->TDES2, 0);
	/* set all other control bits (OWN, CTXT, FD, LD, CPC,
	 * CIC etc) to zero
	 */
	TX_NORMAL_DESC_TDES3_ML_WR(TX_NORMAL_DESC->TDES3, 0);

	DBGPR("<--tx_descriptor_reset\n");

	return Y_SUCCESS;
}

/*!
 * \brief This sequence is used to reinitialize the RX descriptor fields,
 * so that device can reuse the descriptors
 * \param[in] idx
 * \param[in] pdata
 */

static void rx_descriptor_reset(UINT idx,
				struct DWC_ETH_QOS_prv_data *pdata,
				unsigned int inte,
				UINT QINX)
{
	struct DWC_ETH_QOS_rx_buffer *buffer = GET_RX_BUF_PTR(QINX, idx);
	struct s_RX_NORMAL_DESC *RX_NORMAL_DESC = GET_RX_DESC_PTR(QINX, idx);

	DBGPR("-->rx_descriptor_reset\n");

	memset(RX_NORMAL_DESC, 0, sizeof(struct s_RX_NORMAL_DESC));
	/* update buffer 1 address pointer */
	RX_NORMAL_DESC_RDES0_ML_WR(RX_NORMAL_DESC->RDES0, buffer->dma);
	/* set to zero */
	RX_NORMAL_DESC_RDES1_ML_WR(RX_NORMAL_DESC->RDES1, 0);

	if ((pdata->dev->mtu > DWC_ETH_QOS_ETH_FRAME_LEN) ||
	    (pdata->rx_split_hdr == 1)) {
		/* update buffer 2 address pointer */
		RX_NORMAL_DESC_RDES2_ML_WR(RX_NORMAL_DESC->RDES2, buffer->dma2);
		/* set control bits - OWN, INTE, BUF1V and BUF2V */
		RX_NORMAL_DESC_RDES3_ML_WR(RX_NORMAL_DESC->RDES3,
					   (0x83000000 | inte));
	} else {
		/* set buffer 2 address pointer to zero */
		RX_NORMAL_DESC_RDES2_ML_WR(RX_NORMAL_DESC->RDES2, 0);
		/* set control bits - OWN, INTE and BUF1V */
		RX_NORMAL_DESC_RDES3_ML_WR(RX_NORMAL_DESC->RDES3,
					   (0x81000000 | inte));
	}

	DBGPR("<--rx_descriptor_reset\n");
}

/*!
 * \brief This sequence is used to initialize the rx descriptors.
 * \param[in] pdata
 */

static void rx_descriptor_init(struct DWC_ETH_QOS_prv_data *pdata, UINT QINX)
{
	struct DWC_ETH_QOS_rx_wrapper_descriptor *rx_desc_data =
	    GET_RX_WRAPPER_DESC(QINX);
	struct DWC_ETH_QOS_rx_buffer *buffer =
	    GET_RX_BUF_PTR(QINX, rx_desc_data->cur_rx);
	struct s_RX_NORMAL_DESC *RX_NORMAL_DESC =
	    GET_RX_DESC_PTR(QINX, rx_desc_data->cur_rx);
	INT i;
	INT start_index = rx_desc_data->cur_rx;
	INT last_index;

	DBGPR("-->rx_descriptor_init\n");

	/* initialize all desc */

	for (i = 0; i < pdata->rx_queue[QINX].desc_cnt; i++) {
		memset(RX_NORMAL_DESC, 0, sizeof(struct s_RX_NORMAL_DESC));
		/* update buffer 1 address pointer */
		RX_NORMAL_DESC_RDES0_ML_WR(RX_NORMAL_DESC->RDES0, buffer->dma);
		/* set to zero  */
		RX_NORMAL_DESC_RDES1_ML_WR(RX_NORMAL_DESC->RDES1, 0);

		if ((pdata->dev->mtu > DWC_ETH_QOS_ETH_FRAME_LEN) ||
		    (pdata->rx_split_hdr == 1)) {
			/* update buffer 2 address pointer */
			RX_NORMAL_DESC_RDES2_ML_WR(RX_NORMAL_DESC->RDES2,
						   buffer->dma2);
			/* set control bits - OWN, INTE, BUF1V and BUF2V */
			RX_NORMAL_DESC_RDES3_ML_WR(
				RX_NORMAL_DESC->RDES3, (0xc3000000));
		} else {
			/* set buffer 2 address pointer to zero */
			RX_NORMAL_DESC_RDES2_ML_WR(RX_NORMAL_DESC->RDES2, 0);
			/* set control bits - OWN, INTE and BUF1V */
			RX_NORMAL_DESC_RDES3_ML_WR(
				RX_NORMAL_DESC->RDES3, (0xc1000000));
		}
		/* Don't Set the IOC bit for IPA controlled Desc */
		if (pdata->ipa_enabled && QINX == IPA_DMA_RX_CH) {
			UINT varRDES3 = 0;
			RX_NORMAL_DESC_RDES3_ML_RD(RX_NORMAL_DESC->RDES3,
									   varRDES3);
			/* reset IOC for all buffers */
			RX_NORMAL_DESC_RDES3_ML_WR(RX_NORMAL_DESC->RDES3,
									   (varRDES3 & ~(1 << 30)));
		} else {
			buffer->inte = (1 << 30);

			/* reconfigure INTE bit if RX watchdog timer is enabled */
			if (rx_desc_data->use_riwt) {
				if ((i % rx_desc_data->rx_coal_frames) != 0) {
					UINT VARRDES3 = 0;

					RX_NORMAL_DESC_RDES3_ML_RD(
						RX_NORMAL_DESC->RDES3, VARRDES3);
					/* reset INTE */
					RX_NORMAL_DESC_RDES3_ML_WR(
						RX_NORMAL_DESC->RDES3,
						(VARRDES3 & ~(1 << 30)));
					buffer->inte = 0;
				}
			}
		}

		INCR_RX_DESC_INDEX(rx_desc_data->cur_rx, 1, pdata->rx_queue[QINX].desc_cnt);
		RX_NORMAL_DESC =
			GET_RX_DESC_PTR(QINX, rx_desc_data->cur_rx);
		buffer = GET_RX_BUF_PTR(QINX, rx_desc_data->cur_rx);
	}
	
	/* Reset the OWN bit of last descriptor */
	if (pdata->ipa_enabled && QINX == IPA_DMA_RX_CH) {
		RX_NORMAL_DESC = GET_RX_DESC_PTR(QINX, pdata->rx_queue[QINX].desc_cnt - 1);
		RX_CONTEXT_DESC_RDES3_OWN_MLF_WR(RX_NORMAL_DESC->RDES3, 0);
	}
	
	/* update the total no of Rx descriptors count */
	DMA_RDRLR_RGWR(QINX, (pdata->rx_queue[QINX].desc_cnt - 1));
	/* update the Rx Descriptor Tail Pointer */
	last_index = GET_RX_CURRENT_RCVD_LAST_DESC_INDEX(start_index, 0, pdata->rx_queue[QINX].desc_cnt);
	DMA_RDTP_RPDR_RGWR(QINX, GET_RX_DESC_DMA_ADDR(QINX, last_index));
	/* update the starting address of desc chain/ring */
	DMA_RDLAR_RGWR(QINX, GET_RX_DESC_DMA_ADDR(QINX, start_index));

	DBGPR("<--rx_descriptor_init\n");
}

/*!
 * \brief This sequence is used to initialize the tx descriptors.
 * \param[in] pdata
 */

static void tx_descriptor_init(struct DWC_ETH_QOS_prv_data *pdata,
			       UINT QINX)
{
	struct DWC_ETH_QOS_tx_wrapper_descriptor *tx_desc_data =
		GET_TX_WRAPPER_DESC(QINX);
	struct s_TX_NORMAL_DESC *TX_NORMAL_DESC =
		GET_TX_DESC_PTR(QINX, tx_desc_data->cur_tx);
	INT i;
	INT start_index = tx_desc_data->cur_tx;

	DBGPR("-->tx_descriptor_init\n");

	/* initialze all descriptors. */

	for (i = 0; i < pdata->tx_queue[QINX].desc_cnt; i++) {
		/* update buffer 1 address pointer to zero */
		TX_NORMAL_DESC_TDES0_ML_WR(TX_NORMAL_DESC->TDES0, 0);
		/* update buffer 2 address pointer to zero */
		TX_NORMAL_DESC_TDES1_ML_WR(TX_NORMAL_DESC->TDES1, 0);
		/* set all other control bits (IC, TTSE, B2L & B1L) to zero */
		TX_NORMAL_DESC_TDES2_ML_WR(TX_NORMAL_DESC->TDES2, 0);
		/* set all other control bits (OWN, CTXT, FD, LD, CPC, CIC etc)
		 * to zero
		 */
		TX_NORMAL_DESC_TDES3_ML_WR(TX_NORMAL_DESC->TDES3, 0);

		INCR_TX_DESC_INDEX(tx_desc_data->cur_tx, 1, pdata->tx_queue[QINX].desc_cnt);
		TX_NORMAL_DESC = GET_TX_DESC_PTR(QINX, tx_desc_data->cur_tx);
	}
	/* update the total no of Tx descriptors count */
	DMA_TDRLR_RGWR(QINX, (pdata->tx_queue[QINX].desc_cnt - 1));
	/* update the starting address of desc chain/ring */
	DMA_TDLAR_RGWR(QINX, GET_TX_DESC_DMA_ADDR(QINX, start_index));

	DBGPR("<--tx_descriptor_init\n");
}

/*!
 * \brief This sequence is used to prepare tx descriptor for
 * packet transmission and issue the poll demand command to TxDMA
 *
 * \param[in] pdata
 */

static void pre_transmit(struct DWC_ETH_QOS_prv_data *pdata,
			 UINT QINX, UINT int_mod)
{
	struct DWC_ETH_QOS_tx_wrapper_descriptor *tx_desc_data =
	    GET_TX_WRAPPER_DESC(QINX);
	struct DWC_ETH_QOS_tx_buffer *buffer =
	    GET_TX_BUF_PTR(QINX, tx_desc_data->cur_tx);
	struct s_TX_NORMAL_DESC *TX_NORMAL_DESC =
	    GET_TX_DESC_PTR(QINX, tx_desc_data->cur_tx);
	struct s_TX_CONTEXT_DESC *TX_CONTEXT_DESC =
	    (struct s_TX_CONTEXT_DESC *)GET_TX_DESC_PTR(QINX, tx_desc_data->cur_tx);
	UINT varcsum_enable;
#ifdef DWC_ETH_QOS_ENABLE_VLAN_TAG
	UINT varvlan_pkt;
	UINT varvt;
#endif
	INT i;
	INT start_index = tx_desc_data->cur_tx;
	INT last_index, original_start_index = tx_desc_data->cur_tx;
	struct s_tx_pkt_features *tx_pkt_features = GET_TX_PKT_FEATURES_PTR;
#ifdef DWC_ETH_QOS_CERTIFICATION_PKTBURSTCNT
	INT update_tail = 0;
	UINT VARQTDR;
#endif
	UINT vartso_enable = 0;
	UINT varmss = 0;
	UINT varpay_len = 0;
	UINT vartcp_udp_hdr_len = 0;
	UINT varptp_enable = 0;
	INT total_len = 0;

	DBGPR("-->pre_transmit: QINX = %u\n", QINX);

#ifdef DWC_ETH_QOS_CERTIFICATION_PKTBURSTCNT
	if (QINX == 0)
		MTL_Q0TDR_TXQSTS_UDFRD(VARQTDR);
	else
		MTL_QTDR_TXQSTS_UDFRD(QINX, VARQTDR);

	/* No activity on MAC Tx-Fifo and fifo is empty */
	if (VARQTDR == 0) {
		/* disable MAC Transmit */
		MAC_MCR_TE_UDFWR(0);
		update_tail = 1;
	}
#endif

#ifdef DWC_ETH_QOS_ENABLE_VLAN_TAG
	TX_PKT_FEATURES_PKT_ATTRIBUTES_VLAN_PKT_MLF_RD(
		tx_pkt_features->pkt_attributes, varvlan_pkt);
	if (varvlan_pkt == 0x1) {
		/* put vlan tag in contex descriptor and set other control
		 * bits accordingly
		 */
		TX_PKT_FEATURES_VLAN_TAG_VT_MLF_RD(
			tx_pkt_features->vlan_tag, varvt);
		TX_CONTEXT_DESC_TDES3_VT_MLF_WR(TX_CONTEXT_DESC->TDES3, varvt);
		TX_CONTEXT_DESC_TDES3_VLTV_MLF_WR(TX_CONTEXT_DESC->TDES3, 0x1);
		TX_CONTEXT_DESC_TDES3_CTXT_MLF_WR(TX_CONTEXT_DESC->TDES3, 0x1);
		TX_CONTEXT_DESC_TDES3_OWN_MLF_WR(TX_CONTEXT_DESC->TDES3, 0x1);

		original_start_index = tx_desc_data->cur_tx;
		INCR_TX_DESC_INDEX(tx_desc_data->cur_tx, 1, pdata->tx_queue[QINX].desc_cnt);
		start_index = tx_desc_data->cur_tx;
		TX_NORMAL_DESC =
			GET_TX_DESC_PTR(QINX, tx_desc_data->cur_tx);
		buffer = GET_TX_BUF_PTR(QINX, tx_desc_data->cur_tx);
	}
#endif	/* DWC_ETH_QOS_ENABLE_VLAN_TAG */
#ifdef DWC_ETH_QOS_ENABLE_DVLAN
	if (pdata->via_reg_or_desc == DWC_ETH_QOS_VIA_DESC) {
		/* put vlan tag in contex descriptor and set other control
		 * bits accordingly
		 */

		if (pdata->in_out & DWC_ETH_QOS_DVLAN_OUTER) {
			TX_CONTEXT_DESC_TDES3_VT_MLF_WR(TX_CONTEXT_DESC->TDES3,
							pdata->outer_vlan_tag);
			TX_CONTEXT_DESC_TDES3_VLTV_MLF_WR(
				TX_CONTEXT_DESC->TDES3, 0x1);
			/* operation (insertion/replacement/deletion/none)
			 * will be specified in normal descriptor TDES2
			 */
		}
		if (pdata->in_out & DWC_ETH_QOS_DVLAN_INNER) {
			TX_CONTEXT_DESC_TDES2_IVT_MLF_WR(
				TX_CONTEXT_DESC->TDES2, pdata->inner_vlan_tag);
			TX_CONTEXT_DESC_TDES3_IVLTV_MLF_WR(
				TX_CONTEXT_DESC->TDES3, 0x1);
			TX_CONTEXT_DESC_TDES3_IVTIR_MLF_WR(
				TX_CONTEXT_DESC->TDES3,
				pdata->op_type);
		}
		TX_CONTEXT_DESC_TDES3_CTXT_MLF_WR(TX_CONTEXT_DESC->TDES3, 0x1);
		TX_CONTEXT_DESC_TDES3_OWN_MLF_WR(TX_CONTEXT_DESC->TDES3, 0x1);

		original_start_index = tx_desc_data->cur_tx;
		INCR_TX_DESC_INDEX(tx_desc_data->cur_tx, 1, pdata->tx_queue[QINX].desc_cnt);
		start_index = tx_desc_data->cur_tx;
		TX_NORMAL_DESC = GET_TX_DESC_PTR(QINX, tx_desc_data->cur_tx);
		buffer = GET_TX_BUF_PTR(QINX, tx_desc_data->cur_tx);
	}
#endif /* End of DWC_ETH_QOS_ENABLE_DVLAN */

	/* prepare CONTEXT descriptor for TSO */
	TX_PKT_FEATURES_PKT_ATTRIBUTES_TSO_ENABLE_MLF_RD(
		tx_pkt_features->pkt_attributes, vartso_enable);
	if (vartso_enable && (
			tx_pkt_features->mss != tx_desc_data->default_mss)) {
		/* get MSS and update */
		TX_PKT_FEATURES_MSS_MSS_MLF_RD(tx_pkt_features->mss, varmss);
		TX_CONTEXT_DESC_TDES2_MSS_MLF_WR(
			TX_CONTEXT_DESC->TDES2, varmss);
		/* set MSS valid, CTXT and OWN bits */
		TX_CONTEXT_DESC_TDES3_TCMSSV_MLF_WR(
			TX_CONTEXT_DESC->TDES3, 0x1);
		TX_CONTEXT_DESC_TDES3_CTXT_MLF_WR(
			TX_CONTEXT_DESC->TDES3, 0x1);
		TX_CONTEXT_DESC_TDES3_OWN_MLF_WR(
			TX_CONTEXT_DESC->TDES3, 0x1);

		tx_desc_data->default_mss = tx_pkt_features->mss;

		original_start_index = tx_desc_data->cur_tx;
		INCR_TX_DESC_INDEX(tx_desc_data->cur_tx, 1, pdata->tx_queue[QINX].desc_cnt);
		start_index = tx_desc_data->cur_tx;
		TX_NORMAL_DESC = GET_TX_DESC_PTR(QINX, tx_desc_data->cur_tx);
		buffer = GET_TX_BUF_PTR(QINX, tx_desc_data->cur_tx);
	}

	/* update the first buffer pointer and length */
	TX_NORMAL_DESC_TDES0_ML_WR(TX_NORMAL_DESC->TDES0, buffer->dma);
	TX_NORMAL_DESC_TDES2_HL_B1L_MLF_WR(TX_NORMAL_DESC->TDES2, buffer->len);
	if (buffer->dma2 != 0) {
		/* update the second buffer pointer and length */
		TX_NORMAL_DESC_TDES1_ML_WR(TX_NORMAL_DESC->TDES1, buffer->dma2);
		TX_NORMAL_DESC_TDES2_B2L_MLF_WR(
			TX_NORMAL_DESC->TDES2, buffer->len2);
	}

	if (vartso_enable) {
		/* update TCP payload length (only for the
		 * descriptor with FD set)
		 */
		TX_PKT_FEATURES_PAY_LEN_ML_RD(
			tx_pkt_features->pay_len, varpay_len);
		/* TDES3[17:0] will be TCP payload length */
		TX_NORMAL_DESC->TDES3 |= varpay_len;
	} else {
		/* update total length of packet */
		GET_TX_TOT_LEN(
			GET_TX_BUF_PTR(QINX, 0), tx_desc_data->cur_tx,
			GET_CURRENT_XFER_DESC_CNT(QINX), total_len, pdata->tx_queue[QINX].desc_cnt);
		TX_NORMAL_DESC_TDES3_FL_MLF_WR(
			TX_NORMAL_DESC->TDES3, total_len);
	}

#ifdef DWC_ETH_QOS_ENABLE_VLAN_TAG
	/* Insert a VLAN tag with a tag value programmed in MAC Reg 24 or
	 * CONTEXT descriptor
	 */
	if (
		tx_desc_data->vlan_tag_present &&
		tx_desc_data->tx_vlan_tag_via_reg == Y_FALSE) {
		/* pr_alert("VLAN control info update via descriptor\n\n"); */
		TX_NORMAL_DESC_TDES2_VTIR_MLF_WR(
			TX_NORMAL_DESC->TDES2,
			tx_desc_data->tx_vlan_tag_ctrl);
	}
#endif	/* DWC_ETH_QOS_ENABLE_VLAN_TAG */

#ifdef DWC_ETH_QOS_ENABLE_DVLAN
	if (pdata->via_reg_or_desc == DWC_ETH_QOS_VIA_DESC) {
		if (pdata->in_out & DWC_ETH_QOS_DVLAN_OUTER) {
			TX_NORMAL_DESC_TDES2_VTIR_MLF_WR(
				TX_NORMAL_DESC->TDES2, pdata->op_type);
		}
	}
#endif /* End of DWC_ETH_QOS_ENABLE_DVLAN */

	/* Mark it as First Descriptor */
	TX_NORMAL_DESC_TDES3_FD_MLF_WR(TX_NORMAL_DESC->TDES3, 0x1);
	/* Enable CRC and Pad Insertion (NOTE: set this only
	 * for FIRST descriptor)
	 */
	TX_NORMAL_DESC_TDES3_CPC_MLF_WR(TX_NORMAL_DESC->TDES3, 0);
	/* Mark it as NORMAL descriptor */
	TX_NORMAL_DESC_TDES3_CTXT_MLF_WR(TX_NORMAL_DESC->TDES3, 0);
	/* Enable HW CSUM */
	TX_PKT_FEATURES_PKT_ATTRIBUTES_CSUM_ENABLE_MLF_RD(
		tx_pkt_features->pkt_attributes,
		varcsum_enable);
	if (varcsum_enable == 0x1)
		TX_NORMAL_DESC_TDES3_CIC_MLF_WR(TX_NORMAL_DESC->TDES3, 0x3);

	/* configure SA Insertion Control */
	TX_NORMAL_DESC_TDES3_SAIC_MLF_WR(
		TX_NORMAL_DESC->TDES3,
		pdata->tx_sa_ctrl_via_desc);
	if (vartso_enable) {
		/* set TSE bit */
		TX_NORMAL_DESC_TDES3_TSE_MLF_WR(TX_NORMAL_DESC->TDES3, 0x1);

		/* update tcp data offset or tcp hdr len */
		TX_PKT_FEATURES_TCP_HDR_LEN_ML_RD(
			tx_pkt_features->tcp_udp_hdr_len, vartcp_udp_hdr_len);
		/* convert to bit value */
		vartcp_udp_hdr_len = vartcp_udp_hdr_len / 4;
		TX_NORMAL_DESC_TDES3_SLOTNUM_TCPHDRLEN_MLF_WR(
			TX_NORMAL_DESC->TDES3, vartcp_udp_hdr_len);
	}

	/* enable timestamping */
	TX_PKT_FEATURES_PKT_ATTRIBUTES_PTP_ENABLE_MLF_RD(
		tx_pkt_features->pkt_attributes, varptp_enable);
	if (varptp_enable)
		TX_NORMAL_DESC_TDES2_TTSE_MLF_WR(TX_NORMAL_DESC->TDES2, 0x1);

	INCR_TX_DESC_INDEX(tx_desc_data->cur_tx, 1, pdata->tx_queue[QINX].desc_cnt);
	TX_NORMAL_DESC = GET_TX_DESC_PTR(QINX, tx_desc_data->cur_tx);
	buffer = GET_TX_BUF_PTR(QINX, tx_desc_data->cur_tx);

	for (i = 1; i < GET_CURRENT_XFER_DESC_CNT(QINX); i++) {
		/* update the first buffer pointer and length */
		TX_NORMAL_DESC_TDES0_ML_WR(TX_NORMAL_DESC->TDES0, buffer->dma);
		TX_NORMAL_DESC_TDES2_HL_B1L_MLF_WR(
			TX_NORMAL_DESC->TDES2, buffer->len);
		if (buffer->dma2 != 0) {
			/* update the second buffer pointer and length */
			TX_NORMAL_DESC_TDES1_ML_WR(
				TX_NORMAL_DESC->TDES1, buffer->dma2);
			TX_NORMAL_DESC_TDES2_B2L_MLF_WR(
				TX_NORMAL_DESC->TDES2, buffer->len2);
		}

		/* set own bit */
		TX_NORMAL_DESC_TDES3_OWN_MLF_WR(TX_NORMAL_DESC->TDES3, 0x1);
		/* Mark it as NORMAL descriptor */
		TX_NORMAL_DESC_TDES3_CTXT_MLF_WR(TX_NORMAL_DESC->TDES3, 0);

		INCR_TX_DESC_INDEX(tx_desc_data->cur_tx, 1, pdata->tx_queue[QINX].desc_cnt);
		TX_NORMAL_DESC = GET_TX_DESC_PTR(QINX, tx_desc_data->cur_tx);
		buffer = GET_TX_BUF_PTR(QINX, tx_desc_data->cur_tx);
	}
	/* Mark it as LAST descriptor */
	last_index =
		GET_TX_CURRENT_XFER_LAST_DESC_INDEX(QINX, start_index, 0, pdata->tx_queue[QINX].desc_cnt);
	TX_NORMAL_DESC = GET_TX_DESC_PTR(QINX, last_index);
	TX_NORMAL_DESC_TDES3_LD_MLF_WR(TX_NORMAL_DESC->TDES3, 0x1);
	/* set Interrupt on Completion for last descriptor */
#ifdef DWC_ETH_QOS_CERTIFICATION_PKTBURSTCNT
	pdata->mac_enable_count += 1;
	if ((pdata->mac_enable_count % pdata->drop_tx_pktburstcnt) == 0)
		TX_NORMAL_DESC_TDES2_IC_MLF_WR(TX_NORMAL_DESC->TDES2, 0x1);
#else
	TX_NORMAL_DESC_TDES2_IC_MLF_WR(TX_NORMAL_DESC->TDES2,
			(!(tx_desc_data->cur_tx % int_mod)));
#endif

	/* set OWN bit of FIRST descriptor at end to avoid race condition */
	TX_NORMAL_DESC = GET_TX_DESC_PTR(QINX, start_index);
	TX_NORMAL_DESC_TDES3_OWN_MLF_WR(TX_NORMAL_DESC->TDES3, 0x1);

#ifdef DWC_ETH_QOS_ENABLE_TX_DESC_DUMP
	dump_tx_desc(
		pdata, original_start_index,
		(tx_desc_data->cur_tx - 1), 1, QINX);
#endif

#ifdef DWC_ETH_QOS_CERTIFICATION_PKTBURSTCNT
	/* updating descriptor tail pointer for DMA Transmit
	 * under two conditions,
	 * 1. if burst number of packets are present in descriptor list
	 * 2. MAC has no activity on Tx fifo
	 */
	if (
		(pdata->mac_enable_count >= pdata->drop_tx_pktburstcnt) &&
		(update_tail == 1)) {
		pdata->mac_enable_count -= pdata->drop_tx_pktburstcnt;
		/* issue a poll command to Tx DMA by writing address
		 * of next immediate free descriptor
		 */
		last_index = GET_TX_CURRENT_XFER_LAST_DESC_INDEX(
			QINX, start_index, 1, pdata->tx_queue[QINX].desc_cnt);
		DMA_TDTP_TPDR_RGWR(QINX,
				   GET_TX_DESC_DMA_ADDR(QINX, last_index));
	}
#else
	/* issue a poll command to Tx DMA by writing address
	 * of next immediate free descriptor
	 */
	last_index = GET_TX_CURRENT_XFER_LAST_DESC_INDEX(QINX, start_index, 1, pdata->tx_queue[QINX].desc_cnt);
	DMA_TDTP_TPDR_RGWR(QINX,
			   GET_TX_DESC_DMA_ADDR(QINX, last_index));
#endif

	if (pdata->eee_enabled && (!pdata->use_lpi_auto_entry_timer)) {
		/* restart EEE timer */
		mod_timer(&pdata->eee_ctrl_timer,
			  DWC_ETH_QOS_LPI_TIMER(DWC_ETH_QOS_DEFAULT_LPI_TIMER));
	}

	DBGPR("<--pre_transmit\n");
}

/*!
 * \brief This sequence is used to read data from device,
 * it checks whether data is good or bad and updates the errors appropriately
 * \param[in] pdata
 */

static void device_read(struct DWC_ETH_QOS_prv_data *pdata, UINT QINX)
{
	struct DWC_ETH_QOS_rx_wrapper_descriptor *rx_desc_data =
	    GET_RX_WRAPPER_DESC(QINX);
	struct s_RX_NORMAL_DESC *RX_NORMAL_DESC =
	    GET_RX_DESC_PTR(QINX, rx_desc_data->cur_rx);
	UINT VAROWN;
	UINT VARES;
	struct DWC_ETH_QOS_rx_buffer *buffer =
	    GET_RX_BUF_PTR(QINX, rx_desc_data->cur_rx);
	UINT VARRS1V;
	UINT VARIPPE;
	UINT VARIPCB;
	UINT VARIPHE;
	struct s_rx_pkt_features *rx_pkt_features = GET_RX_PKT_FEATURES_PTR;
#ifdef DWC_ETH_QOS_ENABLE_VLAN_TAG
	UINT VARRS0V;
	UINT VARLT;
	UINT VARRDES0;
#endif
	UINT VAROE;
	struct s_rx_error_counters *rx_error_counters =
	    GET_RX_ERROR_COUNTERS_PTR;
	UINT VARCE;
	UINT VARRE;
	UINT VARLD;

	DBGPR("-->device_read: cur_rx = %d\n", rx_desc_data->cur_rx);

	/* check for data availability */
	RX_NORMAL_DESC_RDES3_OWN_MLF_RD(RX_NORMAL_DESC->RDES3, VAROWN);
	if (VAROWN == 0) {
		/* check whether it is good packet or bad packet */
		RX_NORMAL_DESC_RDES3_ES_MLF_RD(RX_NORMAL_DESC->RDES3, VARES);
		RX_NORMAL_DESC_RDES3_LD_MLF_RD(RX_NORMAL_DESC->RDES3, VARLD);
#ifdef DWC_ETH_QOS_CERTIFICATION_PKTBURSTCNT_HALFDUPLEX
		/* Synopsys testing and debugging purposes only */
		if (VARES == 1 && VARLD == 1) {
			VARES = 0;
			DBGPR("Forwarding error pkts as good pkts to stack\n");
		}
#endif
		if ((VARES == 0) && (VARLD == 1)) {
			/* get the packet length */
			RX_NORMAL_DESC_RDES3_FL_MLF_RD(
				RX_NORMAL_DESC->RDES3, buffer->len);
			RX_NORMAL_DESC_RDES3_RS1V_MLF_RD(
				RX_NORMAL_DESC->RDES3, VARRS1V);
			if (VARRS1V == 0x1) {
				/* check whether device has done csum
				 * correctly or not
				 */
				RX_NORMAL_DESC_RDES1_IPPE_MLF_RD(
					RX_NORMAL_DESC->RDES1, VARIPPE);
				RX_NORMAL_DESC_RDES1_IPCB_MLF_RD(
					RX_NORMAL_DESC->RDES1, VARIPCB);
				RX_NORMAL_DESC_RDES1_IPHE_MLF_RD(
					RX_NORMAL_DESC->RDES1, VARIPHE);
				if (
					(VARIPPE == 0) && (VARIPCB == 0) &&
					(VARIPHE == 0)) {
					/* IPC Checksum done */
					RX_PKT_ATTR_CSUM_DONE_MLF_WR(
						rx_pkt_features->pkt_attributes,
						0x1);
				}
			}
#ifdef DWC_ETH_QOS_ENABLE_VLAN_TAG
			RX_NORMAL_DESC_RDES3_RS0V_MLF_RD(RX_NORMAL_DESC->RDES3,
							 VARRS0V);
			if (VARRS0V == 0x1) {
				/* device received frame with VLAN Tag or
				 * double VLAN Tag ?
				 */
				RX_NORMAL_DESC_RDES3_LT_MLF_RD(
					RX_NORMAL_DESC->RDES3, VARLT);
				if ((VARLT == 0x4) || (VARLT == 0x5)) {
					RX_PKT_ATTR_VLAN_PKT_MLF_WR(
						rx_pkt_features->pkt_attributes,
						0x1);
					/* get the VLAN Tag */
					RX_NORMAL_DESC_RDES0_ML_RD(
						RX_NORMAL_DESC->RDES0,
						VARRDES0);
					RX_PKT_FEATURES_VLAN_TAG_VT_MLF_WR(
						rx_pkt_features->vlan_tag,
						(VARRDES0 & 0xffff));
				}
			}
#endif
		} else {
#ifdef DWC_ETH_QOS_ENABLE_RX_DESC_DUMP
			dump_rx_desc(
				QINX, RX_NORMAL_DESC, rx_desc_data->cur_rx);
#endif
			/* not a good packet, hence check for
			 * appropriate errors.
			 */
			RX_NORMAL_DESC_RDES3_OE_MLF_RD(
				RX_NORMAL_DESC->RDES3, VAROE);
			if (VAROE == 1)
				RX_ERR_COUNTERS_RX_ERR_OVERRUN_ERR_MLF_WR(
					rx_error_counters->rx_errors, 1);
			RX_NORMAL_DESC_RDES3_CE_MLF_RD(
				RX_NORMAL_DESC->RDES3, VARCE);
			if (VARCE == 1) {
				RX_ERROR_COUNTERS_RX_ERRORS_CRC_ERROR_MLF_WR(
					rx_error_counters->rx_errors, 1);
			}
			RX_NORMAL_DESC_RDES3_RE_MLF_RD(
				RX_NORMAL_DESC->RDES3, VARRE);
			if (VARRE == 1) {
				RX_ERROR_COUNTERS_RX_ERRORS_FRAME_ERROR_MLF_WR(
					rx_error_counters->rx_errors, 1);
			}
			RX_NORMAL_DESC_RDES3_LD_MLF_RD(
				RX_NORMAL_DESC->RDES3, VARLD);
			if (VARRE == 0) {
				RX_ERR_COUNTERS_RX_ERR_OVERRUN_ERR_MLF_WR(
					rx_error_counters->rx_errors, 1);
			}
		}
	}

	DBGPR("<--device_read: cur_rx = %d\n", rx_desc_data->cur_rx);
}

static void update_rx_tail_ptr(unsigned int QINX, unsigned int dma_addr)
{
	DMA_RDTP_RPDR_RGWR(QINX, dma_addr);
}

/*!
 * \brief This sequence is used to check whether CTXT bit is
 * set or not returns 1 if CTXT is set else returns zero
 * \param[in] txdesc
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT get_tx_descriptor_ctxt(t_TX_NORMAL_DESC *txdesc)
{
	ULONG VARCTXT;

	/* check TDES3.CTXT bit */
	TX_NORMAL_DESC_TDES3_CTXT_MLF_RD(txdesc->TDES3, VARCTXT);
	if (VARCTXT == 1)
		return 1;
	else
		return 0;
}

/*!
 * \brief This sequence is used to check whether LD bit is set or not
 * returns 1 if LD is set else returns zero
 * \param[in] txdesc
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static INT get_tx_descriptor_last(t_TX_NORMAL_DESC *txdesc)
{
	ULONG VARLD;

	/* check TDES3.LD bit */
	TX_NORMAL_DESC_TDES3_LD_MLF_RD(txdesc->TDES3, VARLD);
	if (VARLD == 1)
		return 1;
	else
		return 0;
}

/*!
 * \brief Exit routine
 * \details Exit function that unregisters the device, deallocates buffers,
 * unbinds the driver from controlling the device etc.
 *
 * \return Returns successful execution of the routine
 * \retval Y_SUCCESS Function executed successfully
 */

static INT DWC_ETH_QOS_yexit(void)
{
	ULONG RETRYCOUNT = 1000;
	ULONG vy_count;
	volatile ULONG VARDMA_BMR;

	DBGPR("-->DWC_ETH_QOS_yexit\n");

	/*issue a software reset */
	DMA_BMR_SWR_UDFWR(0x1);
	/*DELAY IMPLEMENTATION USING udelay() */
	udelay(10);

	/*Poll Until Poll Condition */
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT) {
			EMACERR("Unable to reset MAC 0x%x\n", VARDMA_BMR);
			return -Y_FAILURE;
		}

		vy_count++;
		mdelay(1);

		DMA_BMR_RGRD(VARDMA_BMR);
		if (GET_VALUE(
			VARDMA_BMR, DMA_BMR_SWR_LPOS, DMA_BMR_SWR_HPOS) == 0) {
			break;
		}
	}

	DBGPR("<--DWC_ETH_QOS_yexit\n");

	return Y_SUCCESS;
}

/*!
 * \details This API will calculate per queue FIFO size.
 *
 * \param[in] fifo_size - total fifo size in h/w register
 * \param[in] queue_count - total queue count
 *
 * \return returns integer
 * \retval - fifo size per queue.
 */
static UINT calculate_per_queue_fifo(ULONG fifo_size, UCHAR queue_count)
{
	ULONG q_fifo_size = 0;	/* calculated fifo size per queue */
	/* per queue fifo sizeprogrammable value */
	ULONG p_fifo = EDWC_ETH_QOS_256;

	/* calculate Tx/Rx fifo share per queue */
	switch (fifo_size) {
	case 0:
		q_fifo_size = FIFO_SIZE_B(128);
		break;
	case 1:
		q_fifo_size = FIFO_SIZE_B(256);
		break;
	case 2:
		q_fifo_size = FIFO_SIZE_B(512);
		break;
	case 3:
		q_fifo_size = FIFO_SIZE_KB(1);
		break;
	case 4:
		q_fifo_size = FIFO_SIZE_KB(2);
		break;
	case 5:
		q_fifo_size = FIFO_SIZE_KB(4);
		break;
	case 6:
		q_fifo_size = FIFO_SIZE_KB(8);
		break;
	case 7:
		q_fifo_size = FIFO_SIZE_KB(16);
		break;
	case 8:
		q_fifo_size = FIFO_SIZE_KB(32);
		break;
	case 9:
		q_fifo_size = FIFO_SIZE_KB(64);
		break;
	case 10:
		q_fifo_size = FIFO_SIZE_KB(128);
		break;
	case 11:
		q_fifo_size = FIFO_SIZE_KB(256);
		break;
	}

	q_fifo_size = q_fifo_size / queue_count;

	if (q_fifo_size >= FIFO_SIZE_KB(32))
		p_fifo = EDWC_ETH_QOS_32K;
	else if (q_fifo_size >= FIFO_SIZE_KB(16))
		p_fifo = EDWC_ETH_QOS_16K;
	else if (q_fifo_size >= FIFO_SIZE_KB(8))
		p_fifo = EDWC_ETH_QOS_8K;
	else if (q_fifo_size >= FIFO_SIZE_KB(4))
		p_fifo = EDWC_ETH_QOS_4K;
	else if (q_fifo_size >= FIFO_SIZE_KB(2))
		p_fifo = EDWC_ETH_QOS_2K;
	else if (q_fifo_size >= FIFO_SIZE_KB(1))
		p_fifo = EDWC_ETH_QOS_1K;
	else if (q_fifo_size >= FIFO_SIZE_B(512))
		p_fifo = EDWC_ETH_QOS_512;
	else if (q_fifo_size >= FIFO_SIZE_B(256))
		p_fifo = EDWC_ETH_QOS_256;

	return p_fifo;
}

static INT configure_tx_queue(UINT queue_index)
{
	UINT scheduling_algo = EDWC_ETH_QOS_DCB_SP;
	UINT tsf_config = 0x1;
	UINT vy_count = 0;
	ULONG RETRYCOUNT = 1000;
	UINT op_mode = DWC_ETH_QOS_Q_GENERIC;
	UINT desc_posted_write = 0x1;
	volatile ULONG VARMTL_QTOMR;

	EMACDBG("Enter\n");

	/*Flush Tx Queue */
	MTL_QTOMR_FTQ_UDFWR(queue_index, 0x1);

	/*Poll Until Poll Condition */
	while (1) {
		if (vy_count > RETRYCOUNT) {
			EMACERR("unable to flush tx queue %d", queue_index);
			return -Y_FAILURE;
		}
		vy_count++;
		usleep_range(1000, 1500);
		MTL_QTOMR_RGRD(queue_index, VARMTL_QTOMR);
		if (GET_VALUE(
				VARMTL_QTOMR, MTL_QTOMR_FTQ_LPOS,
				MTL_QTOMR_FTQ_HPOS)
				== 0)
			break;
	}

	switch (queue_index) {
	case 0:
		op_mode = DWC_ETH_QOS_Q_GENERIC;
		break;
	case 1:
		op_mode = DWC_ETH_QOS_Q_GENERIC;
		MTL_QTOMR_TXQEN_UDFWR(queue_index, op_mode);
		break;
	case 2:
		op_mode = DWC_ETH_QOS_Q_AVB;
		MTL_QTOMR_TXQEN_UDFWR(queue_index, op_mode);
		break;
	case 3:
		op_mode = DWC_ETH_QOS_Q_AVB;
		MTL_QTOMR_TXQEN_UDFWR(queue_index, op_mode);
		break;
	case 4:
		op_mode = DWC_ETH_QOS_Q_AVB;
		MTL_QTOMR_TXQEN_UDFWR(queue_index, op_mode);
		break;
	}
	/* Transmit Store and Forward enabled for all queues */
	config_tsf_mode(queue_index, tsf_config);

	/* Select Tx Scheduling Algorithm */
	MTL_OMR_SCHALG_UDFWR(scheduling_algo);

	DMA_BMR_DSPW_UDFWR(desc_posted_write);

	return Y_SUCCESS;
	EMACDBG("Exit\n");
}

static void configure_avb_ip_rx_filtering(void)
{
	UINT untagged_avb_ctrl_queue = 0x2, tagged_avb_ctrl_queue_en = 0x1;
	UINT untagged_pkt_queue = 0x0;
	UINT multicast_queue = 0x1;
	UINT multi_braodcast_routing_en = 0x1;

	/* Assign queue for untagged AVB control packets*/
	MAC_RQC1R_AVUCPQ_UDFWR(untagged_avb_ctrl_queue);

	/* Assign queue for untagged packets */
	MAC_RQC1R_UPQ_UDFWR(untagged_pkt_queue);

	/* Assign queue for multicast and broadcast packets */
	MAC_RQC1R_MCBCQ_UDFWR(multicast_queue);

	/* Enable multicast and broadcast routing to RX queue */
	MAC_RQC1R_MCBCQEN_UDFWR(multi_braodcast_routing_en);

	/* Assign queue for tagged AVB control packets*/
	MAC_RQC1R_TACPQE_UDFWR(tagged_avb_ctrl_queue_en);

	/* Set priorities 2 and 3 for PSRQ3 in order to route all tagged
	 * AVB data packets to queue 3
	 */
	MAC_RQC2R_PSRQ3_UDFWR(0x0C);

	/* Set prority zero to route all vlan tagged
	 * BE/IP traffic to queue 0
	 */
	MAC_RQC2R_PSRQ0_UDFWR(0x1);

	/* Strict priority arbitration algorithm set on Rx side */
	MTL_OMR_RAA_UDFWR(0x0);

	/* Mapping MTL Rx queue and DMA Rx channel. */
	MTL_RQDCM0R_RGWR(0x3020100);
}

static void configure_ptp_rx_filtering(void)
{
	UINT ptp_pkt_queue = 0x1, tagged_ptp_queue = 0x1;

	/* Assign queue for untagged PTP packets */
	MAC_RQC1R_AVPTPQ_UDFWR(ptp_pkt_queue);

	/* Assign queue for tagged PTP packets */
	MAC_RQC1R_TPQC_UDFWR(tagged_ptp_queue);

	/* Set TSIPENA bit to 1 to route tagged and untagged PTP pkts
	 * to RX queue as per TPQC and PTPQ settings
	 */
	MAC_TCR_TSIPENA_UDFWR(0x1);

	/* Set TSENMACADDR to do PTP packet filtering that
	 *  sent over Ethernet packet
	 */
	MAC_TCR_TSENMACADDR_UDFWR(0x1);
}

static INT configure_rx_queue(UINT queue_index)
{
	int op_mode = DWC_ETH_QOS_Q_GENERIC;
	UINT rsf_config = 0x1;
	UINT fup_config = 0x1;
	UINT fep_config = 0x1;
	UINT disable_csum_err_pkt_drop = 0x1;

	EMACDBG("Enter\n");

	switch (queue_index) {
	case 0:
		op_mode = DWC_ETH_QOS_Q_GENERIC;
		/* Enable Rx queue for generic traffic */
		MAC_RQC0R_RXQEN_UDFWR(queue_index, 0x2);
		break;
	case 1:
		op_mode = DWC_ETH_QOS_Q_GENERIC;
		/* Enable Rx queue for AVB traffic */
		MAC_RQC0R_RXQEN_UDFWR(queue_index, op_mode);
		break;
	case 2:
		op_mode = DWC_ETH_QOS_Q_AVB;
		/* Enable Rx queue for AVB traffic */
		MAC_RQC0R_RXQEN_UDFWR(queue_index, op_mode);
		break;
	case 3:
		op_mode = DWC_ETH_QOS_Q_AVB;
		/* Enable Rx queue for AVB traffic */
		MAC_RQC0R_RXQEN_UDFWR(queue_index, op_mode);
		break;
	}

	/* Receive Store and Forward enabled for all RX queues */
	config_rsf_mode(queue_index, rsf_config);
	MTL_QROMR_FUP_UDFWR(queue_index, fup_config);
	MTL_QROMR_FEP_UDFWR(queue_index, fep_config);
	/* Disable Dropping of TCP/IP Checksum Error Packets */
	MTL_QROMR_DIS_TCP_EF_UDFWR(queue_index, disable_csum_err_pkt_drop);

	/* Receive Queue Packet Arbitration reset for all RX queues */
	MTL_QRCR_RXQ_PKT_ARBIT_UDFWR(queue_index, 0x0);

	return Y_SUCCESS;
	EMACDBG("Exit\n");
}

static INT configure_mtl_queue(UINT QINX, struct DWC_ETH_QOS_prv_data *pdata)
{
	struct DWC_ETH_QOS_tx_queue *queue_data = GET_TX_QUEUE_PTR(QINX);
	ULONG RETRYCOUNT = 1000;
	ULONG vy_count;
	volatile ULONG VARMTL_QTOMR;
	UINT p_rx_fifo = EDWC_ETH_QOS_256, p_tx_fifo = EDWC_ETH_QOS_256;

	DBGPR("-->configure_mtl_queue\n");

	/*Flush Tx Queue */
	MTL_QTOMR_FTQ_UDFWR(QINX, 0x1);

	/*Poll Until Poll Condition */
	vy_count = 0;
	while (1) {
		if (vy_count > RETRYCOUNT){
			EMACERR("unable to flush tx queue %d", QINX);
			return -Y_FAILURE;
		}
		vy_count++;
		mdelay(1);

		MTL_QTOMR_RGRD(QINX, VARMTL_QTOMR);
		if (GET_VALUE(
				VARMTL_QTOMR, MTL_QTOMR_FTQ_LPOS,
				MTL_QTOMR_FTQ_HPOS)
				== 0)
			break;
	}

	/*Enable Store and Forward mode for TX */
	MTL_QTOMR_TSF_UDFWR(QINX, 0x1);
	/* Program Tx operating mode */
	MTL_QTOMR_TXQEN_UDFWR(QINX, queue_data->q_op_mode);
	/* Transmit Queue weight */
	MTL_QW_ISCQW_UDFWR(QINX, (0x10 + QINX));

	MTL_QROMR_FEP_UDFWR(QINX, 0x1);

	/* Configure for Jumbo frame in MTL */
	if (pdata->dev->mtu > DWC_ETH_QOS_ETH_FRAME_LEN) {
		/* Disable RX Store and Forward mode */
		MTL_QROMR_RSF_UDFWR(QINX, 0x0);
		pr_alert("RX is configured in threshold mode and threshold = 64Byte\n");
	}

	p_rx_fifo = calculate_per_queue_fifo(
		pdata->hw_feat.rx_fifo_size, DWC_ETH_QOS_RX_QUEUE_CNT);
	p_tx_fifo = calculate_per_queue_fifo(
		pdata->hw_feat.tx_fifo_size, DWC_ETH_QOS_TX_QUEUE_CNT);

	/* Transmit/Receive queue fifo size programmed */
	MTL_QROMR_RQS_UDFWR(QINX, p_rx_fifo);
	MTL_QTOMR_TQS_UDFWR(QINX, p_tx_fifo);
	EMACDBG(
		"Queue%d Tx fifo size %d, Rx fifo size %d\n",
		QINX, ((p_tx_fifo + 1) * 256), ((p_rx_fifo + 1) * 256));

	/* flow control will be used only if
	 * each channel gets 8KB or more fifo
	 */
	if (p_rx_fifo >= EDWC_ETH_QOS_4K) {
		/* Enable Rx FLOW CTRL in MTL and MAC
		 * Programming is valid only if Rx fifo size is greater than
		 * or equal to 8k
		 */
		if ((pdata->flow_ctrl & DWC_ETH_QOS_FLOW_CTRL_TX) ==
			DWC_ETH_QOS_FLOW_CTRL_TX) {
			MTL_QROMR_EHFC_UDFWR(QINX, 0x1);

#ifdef DWC_ETH_QOS_VER_4_0
			if (p_rx_fifo == EDWC_ETH_QOS_4K) {
				/* This violates the above formula because of
				 * FIFO size limit therefore overflow may occur
				 * inspite of this
				 */
				MTL_QROMR_RFD_UDFWR(QINX, 0x2);
				MTL_QROMR_RFA_UDFWR(QINX, 0x1);
			} else if (p_rx_fifo == EDWC_ETH_QOS_8K) {
				MTL_QROMR_RFD_UDFWR(QINX, 0x4);
				MTL_QROMR_RFA_UDFWR(QINX, 0x2);
			} else if (p_rx_fifo == EDWC_ETH_QOS_16K) {
				MTL_QROMR_RFD_UDFWR(QINX, 0x5);
				MTL_QROMR_RFA_UDFWR(QINX, 0x2);
			} else if (p_rx_fifo == EDWC_ETH_QOS_32K) {
				MTL_QROMR_RFD_UDFWR(QINX, 0x7);
				MTL_QROMR_RFA_UDFWR(QINX, 0x2);
			}
#else
			/* Set Threshold for Activating Flow Contol space
			 * for min 2 frames ie, (1500 * 1) = 1500 bytes
			 * Set Threshold for Deactivating Flow Contol for
			 * space of min 1 frame (frame size 1500bytes)
			 * in receive fifo
			 */
			if (p_rx_fifo == EDWC_ETH_QOS_4K) {
				/* This violates the above formula because of
				 * FIFO size limit therefore overflow may occur
				 * inspite of this
				 */
				/* Full - 3K */
				MTL_QROMR_RFD_UDFWR(QINX, 0x3);
				/* Full - 1.5K */
				MTL_QROMR_RFA_UDFWR(QINX, 0x1);
			} else if (p_rx_fifo == EDWC_ETH_QOS_8K) {
				MTL_QROMR_RFD_UDFWR(QINX, 0x6); /* Full - 4K */
				MTL_QROMR_RFA_UDFWR(QINX, 0xA); /* Full - 6K */
			} else if (p_rx_fifo == EDWC_ETH_QOS_16K) {
				MTL_QROMR_RFD_UDFWR(QINX, 0x6); /* Full - 4K */
				/* Full - 10K */
				MTL_QROMR_RFA_UDFWR(QINX, 0x12);
			} else if (p_rx_fifo == EDWC_ETH_QOS_32K) {
				MTL_QROMR_RFD_UDFWR(QINX, 0x6); /* Full - 4K */
				/* Full - 16K */
				MTL_QROMR_RFA_UDFWR(QINX, 0x1E);
			}

#endif
		}
	}

	DBGPR("<--configure_mtl_queue\n");

	return Y_SUCCESS;
}

static void configure_dma_sys_bus(struct DWC_ETH_QOS_prv_data *pdata)
{
	/* Setting INCRx */
	DMA_SBUS_RGWR(0x0);

	/* To get Best Performance */
	DMA_SBUS_BLEN16_UDFWR(1);
	DMA_SBUS_BLEN8_UDFWR(1);
	DMA_SBUS_BLEN4_UDFWR(1);
	DMA_SBUS_RD_OSR_LMT_UDFWR(2);
}

static void configure_tx_dma_channel(UINT QINX,
	struct DWC_ETH_QOS_prv_data *pdata)
{
	DBGPR("-->configure_tx_dma_channel\n");
	/*Enable OSF mode */
	DMA_TCR_OSP_UDFWR(QINX, 0x1);

	/* set PBLx8 */
	DMA_CR_PBLX8_UDFWR(QINX, 0x1);
	/* set TX PBL = 16 */
	DMA_TCR_PBL_UDFWR(QINX, 32);

	enable_tx_dma_interrupts(QINX, pdata);

	/* enable TSO if HW supports */
	if (pdata->hw_feat.tso_en)
		DMA_TCR_TSE_UDFWR(QINX, 0x1);
	EMACDBG(
		"%s TSO\n",
		(pdata->hw_feat.tso_en ? "Enabled" : "Disabled"));

	/* For PG don't start TX DMA now.*/
#ifndef DWC_ETH_QOS_CONFIG_PGTEST
	/* start TX DMA */
	DMA_TCR_ST_UDFWR(QINX, 0x1);
#endif

	DBGPR("<--configure_tx_dma_channel\n");
}

static void configure_rx_dma_channel(UINT QINX,
	struct DWC_ETH_QOS_prv_data *pdata)
{
	struct DWC_ETH_QOS_rx_wrapper_descriptor *rx_desc_data =
		GET_RX_WRAPPER_DESC(QINX);

	DBGPR("-->configure_rx_dma_channel\n");
	/*Select Rx Buffer size = 2048bytes */
	switch (pdata->rx_buffer_len) {
	case 16384:
		DMA_RCR_RBSZ_UDFWR(QINX, 16384);
		break;
	case 8192:
		DMA_RCR_RBSZ_UDFWR(QINX, 8192);
		break;
	case 4096:
		DMA_RCR_RBSZ_UDFWR(QINX, 4096);
		break;
	default:        /* default is 2K */
		DMA_RCR_RBSZ_UDFWR(QINX, 2048);
		break;
	}

	/* program RX watchdog timer */
	if (rx_desc_data->use_riwt)
		DMA_RIWTR_RWT_UDFWR(QINX, rx_desc_data->rx_riwt);
	else
		DMA_RIWTR_RWT_UDFWR(QINX, 0);

	EMACDBG(
		"%s Rx watchdog timer\n",
		(rx_desc_data->use_riwt ? "Enabled" : "Disabled"));

	/* set PBLx8 */
	DMA_CR_PBLX8_UDFWR(QINX, 0x1);
	/* set RX PBL = 16 */
	DMA_RCR_PBL_UDFWR(QINX, 32);
	enable_rx_dma_interrupts(QINX, pdata);

	/* program split header mode */
	DMA_CR_SPH_UDFWR(QINX, pdata->rx_split_hdr);
	EMACDBG(
		"%s Rx Split header mode\n",
		(pdata->rx_split_hdr ? "Enabled" : "Disabled"));

	/* start RX DMA */
	DMA_RCR_ST_UDFWR(QINX, 0x1);

	DBGPR("<--configure_rx_dma_channel\n");
}

/*!
 * \brief This sequence is used to enable MAC interrupts
 * \return Success or Failure
 * \retval  0 Success
 * \retval -1 Failure
 */

static int enable_mac_interrupts(void)
{
	unsigned long varmac_imr;

	/* Enable following interrupts */
	MAC_IMR_RGRD(varmac_imr);
	varmac_imr = varmac_imr & (unsigned long)(0x1000);
	MAC_IMR_RGWR(varmac_imr);

	return Y_SUCCESS;
}

static INT configure_mac(struct DWC_ETH_QOS_prv_data *pdata)
{
	ULONG VARMAC_MCR;
	UINT QINX;

	DBGPR("-->configure_mac\n");

	/* Set Tx flow control parameters */
	for (QINX = 0; QINX < DWC_ETH_QOS_TX_QUEUE_CNT; QINX++) {
		/* set Pause Time */
		MAC_QTFCR_PT_UDFWR(QINX, 0xffff);
#ifndef DWC_ETH_QOS_QUEUE_SELECT_ALGO
		/* Assign priority for RX flow control */
		/* Assign priority for TX flow control */
		switch (QINX) {
		case 0:
			MAC_TQPM0R_PSTQ0_UDFWR(0);
			MAC_RQC2R_PSRQ0_UDFWR(0x1 << QINX);
			break;
		case 1:
			MAC_TQPM0R_PSTQ1_UDFWR(1);
			MAC_RQC2R_PSRQ1_UDFWR(0x1 << QINX);
			break;
		case 2:
			MAC_TQPM0R_PSTQ2_UDFWR(2);
			MAC_RQC2R_PSRQ2_UDFWR(0x1 << QINX);
			break;
		case 3:
			MAC_TQPM0R_PSTQ3_UDFWR(3);
			MAC_RQC2R_PSRQ3_UDFWR(0x1 << QINX);
			break;
		case 4:
			MAC_TQPM1R_PSTQ4_UDFWR(4);
			MAC_RQC3R_PSRQ4_UDFWR(0x1 << QINX);
			break;
		case 5:
			MAC_TQPM1R_PSTQ5_UDFWR(5);
			MAC_RQC3R_PSRQ5_UDFWR(0x1 << QINX);
			break;
		case 6:
			MAC_TQPM1R_PSTQ6_UDFWR(6);
			MAC_RQC3R_PSRQ6_UDFWR(0x1 << QINX);
			break;
		case 7:
			MAC_TQPM1R_PSTQ7_UDFWR(7);
			MAC_RQC3R_PSRQ7_UDFWR(0x1 << QINX);
			break;
		}
#endif
#ifdef DWC_ETH_QOS_QUEUE_SELECT_ALGO
		configure_tx_queue(QINX);
#endif
		if ((pdata->flow_ctrl & DWC_ETH_QOS_FLOW_CTRL_TX) ==
		DWC_ETH_QOS_FLOW_CTRL_TX)
			enable_tx_flow_ctrl(QINX);
		else
			disable_tx_flow_ctrl(QINX);
	}

	/* Set Rx flow control parameters */
	if ((pdata->flow_ctrl & DWC_ETH_QOS_FLOW_CTRL_RX) ==
	DWC_ETH_QOS_FLOW_CTRL_RX)
		enable_rx_flow_ctrl();
	else
		disable_rx_flow_ctrl();

	/* Configure for Jumbo frame in MAC */
	if (pdata->dev->mtu > DWC_ETH_QOS_ETH_FRAME_LEN) {
		if (pdata->dev->mtu < DWC_ETH_QOS_MAX_GPSL) {
			MAC_MCR_JE_UDFWR(0x1);
			MAC_MCR_WD_UDFWR(0x0);
			MAC_MCR_GPSLCE_UDFWR(0x0);
			MAC_MCR_JD_UDFWR(0x0);
		} else {
			MAC_MCR_JE_UDFWR(0x0);
			MAC_MCR_WD_UDFWR(0x1);
			MAC_MCR_GPSLCE_UDFWR(0x1);
			MAC_MECR_GPSL_UDFWR(DWC_ETH_QOS_MAX_SUPPORTED_MTU);
			MAC_MCR_JD_UDFWR(0x1);
			EMACDBG(
				"Configured Gaint Packet Size Limit to %d\n",
				DWC_ETH_QOS_MAX_SUPPORTED_MTU);
		}
		EMACDBG("Enabled JUMBO pkt\n");
	} else {
		MAC_MCR_JE_UDFWR(0x0);
		MAC_MCR_WD_UDFWR(0x0);
		MAC_MCR_GPSLCE_UDFWR(0x0);
		MAC_MCR_JD_UDFWR(0x0);
		EMACDBG("Disabled JUMBO pkt\n");
	}

	/* update the MAC address */
	MAC_MA0HR_RGWR(((pdata->dev->dev_addr[5] << 8) |
			(pdata->dev->dev_addr[4])));
	MAC_MA0LR_RGWR(((pdata->dev->dev_addr[3] << 24) |
			(pdata->dev->dev_addr[2] << 16) |
			(pdata->dev->dev_addr[1] << 8) |
			(pdata->dev->dev_addr[0])));

	/*Enable MAC Transmit process */
	/*Enable MAC Receive process */
	/*Enable padding - disabled */
	/*Enable CRC stripping - disabled */
	MAC_MCR_RGRD(VARMAC_MCR);
	VARMAC_MCR = VARMAC_MCR & (ULONG)(0xffcfff7c);
	VARMAC_MCR = VARMAC_MCR | ((0x1) << 0) | ((0x1) << 20) | ((0x1) << 21);
#ifndef DWC_ETH_QOS_CERTIFICATION_PKTBURSTCNT
	VARMAC_MCR |= ((0x1) << 1);
#endif
	MAC_MCR_RGWR(VARMAC_MCR);

	switch (pdata->speed) {
	case SPEED_1000:
		set_gmii_speed();
		break;
	case SPEED_100:
		set_mii_speed_100();
		break;
	case SPEED_10:
		set_mii_speed_10();
		break;
	}

	if (pdata->hw_feat.rx_coe_sel &&
	    ((pdata->dev_state & NETIF_F_RXCSUM) == NETIF_F_RXCSUM))
		MAC_MCR_IPC_UDFWR(0x1);

#ifdef DWC_ETH_QOS_ENABLE_VLAN_TAG
	configure_mac_for_vlan_pkt();
	if (pdata->hw_feat.vlan_hash_en) {
		/* Configure vlan tag based filtering options*/
		config_vlan_filtering(
		   DWC_ETH_QOS_VLAN_FILTERING_EN_DIS,
		   DWC_ETH_QOS_VLAN_HASH_FILTERING,
		   DWC_ETH_QOS_VLAN_INVERSE_MATCHING);
	}
#endif

	if (pdata->hw_feat.mmc_sel) {
		/* disable all MMC intterrupt as MMC are managed in SW and
		 * registers are cleared on each READ eventually
		 */
		disable_mmc_interrupts();
		config_mmc_counters();
	}
	for (QINX = 0; QINX < DWC_ETH_QOS_RX_QUEUE_CNT; QINX++) {
#ifdef DWC_ETH_QOS_QUEUE_SELECT_ALGO
		configure_rx_queue(QINX);
#else
		MAC_RQC0R_RXQEN_UDFWR(QINX, 0x2);
#endif
		/* Fix for unintended stopping of Rx DMA channels
		when any one Rx DMA channel is stopped */
		DMA_RCR_RPF_UDFWR(QINX, 0x1);
	}
	configure_avb_ip_rx_filtering();
	configure_ptp_rx_filtering();

	enable_mac_interrupts();

	DBGPR("<--configure_mac\n");

	return Y_SUCCESS;
}

static int DWC_ETH_QOS_yinit_offload(struct DWC_ETH_QOS_prv_data *pdata)
{
	DBGPR("-->DWC_ETH_QOS_yinit_offload\n");

	configure_tx_dma_channel(IPA_DMA_TX_CH, pdata);
	configure_rx_dma_channel(IPA_DMA_RX_CH, pdata);

	DBGPR("-->DWC_ETH_QOS_yinit_offload\n");
	return Y_SUCCESS;
}

static int DWC_ETH_QOS_yexit_offload(void)
{
	DBGPR("-->DWC_ETH_QOS_yexit_offload\n");
	DBGPR("-->DWC_ETH_QOS_yexit_offload\n");
	return Y_SUCCESS;
}

/*!
 * \brief Initialises device registers.
 * \details This function initialises device registers.
 *
 * \return none
 */

static INT DWC_ETH_QOS_yinit(struct DWC_ETH_QOS_prv_data *pdata)
{
	UINT QINX;

	DBGPR("-->DWC_ETH_QOS_yinit\n");

	/* reset mmc counters */
	MMC_CNTRL_RGWR(0x1);

	for (QINX = 0; QINX < DWC_ETH_QOS_TX_QUEUE_CNT; QINX++)
		configure_mtl_queue(QINX, pdata);

#ifdef DWC_ETH_QOS_CERTIFICATION_PKTBURSTCNT
	/* enable tx drop status */
	MTL_OMR_DTXSTS_UDFWR(0x1);
#endif

	configure_mac(pdata);
	configure_dma_sys_bus(pdata);

	/* Mapping MTL Rx queue and DMA Rx channel. */
	if (pdata->res_data->early_eth_en)
		MTL_RQDCM0R_RGWR(0x3020101);
	else /* Mapped RX queue 0 to DMA channel 1 */
		MTL_RQDCM0R_RGWR(0x3020100);

	for (QINX = 0; QINX < DWC_ETH_QOS_TX_QUEUE_CNT; QINX++) {
		if (pdata->ipa_enabled && QINX == IPA_DMA_TX_CH)
			continue;

		configure_tx_dma_channel(QINX, pdata);
	}

	for (QINX = 0; QINX < DWC_ETH_QOS_RX_QUEUE_CNT; QINX++) {
		if (pdata->ipa_enabled && QINX == IPA_DMA_RX_CH)
			continue;

		configure_rx_dma_channel(QINX, pdata);
	}

#ifdef DWC_ETH_QOS_CERTIFICATION_PKTBURSTCNT_HALFDUPLEX
	MTL_Q0ROMR_FEP_UDFWR(0x1);
	MAC_MPFR_RA_UDFWR(0x1);
	MAC_MCR_BE_UDFWR(0x1);
#endif

	DBGPR("<--DWC_ETH_QOS_yinit\n");

	return Y_SUCCESS;
}

#ifdef DWC_ETH_QOS_CONFIG_PGTEST

/*!
 * \brief This sequence is used to initialize the tx descriptors.
 * \param[in] pdata
 */

static void tx_descriptor_init_pg(struct DWC_ETH_QOS_prv_data *pdata,
				  UINT qinx)
{
	struct DWC_ETH_QOS_tx_wrapper_descriptor *tx_desc_data =
		GET_TX_WRAPPER_DESC(qinx);
	struct s_TX_NORMAL_DESC *TX_NORMAL_DESC =
		GET_TX_DESC_PTR(qinx, tx_desc_data->cur_tx);
	struct DWC_ETH_QOS_tx_buffer *buffer =
		GET_TX_BUF_PTR(qinx, tx_desc_data->cur_tx);
	INT i;
	INT start_index = tx_desc_data->cur_tx;

	DBGPR("-->tx_descriptor_init_pg\n");

	/* initialze all descriptors. */

	for (i = 0; i < pdata->tx_queue[qinx].desc_cnt; i++) {
		/* update buffer 1 address pointer to zero */
		TX_NORMAL_DESC_TDES0_ML_WR(TX_NORMAL_DESC->TDES0, 0);
		/* update buffer 2 address pointer to zero */
		TX_NORMAL_DESC_TDES1_ML_WR(TX_NORMAL_DESC->TDES1, 0);
		/* set all other control bits (IC, TTSE, B2L & B1L) to zero */
		TX_NORMAL_DESC_TDES2_ML_WR(TX_NORMAL_DESC->TDES2, 0);
		/* set all other control bits (OWN, CTXT, FD, LD, CPC, CIC etc)
		 * to zero
		 */
		TX_NORMAL_DESC_TDES3_ML_WR(TX_NORMAL_DESC->TDES3, 0);

		INCR_TX_DESC_INDEX(tx_desc_data->cur_tx, 1, pdata->tx_queue[qinx].desc_cnt);
		TX_NORMAL_DESC = GET_TX_DESC_PTR(qinx, tx_desc_data->cur_tx);
		buffer = GET_TX_BUF_PTR(qinx, tx_desc_data->cur_tx);
	}
	/* update the total no of Tx descriptors count */
	DMA_TDRLR_RGWR(qinx, (pdata->tx_queue[qinx].desc_cnt - 1));
	/* update the starting address of desc chain/ring */
	DMA_TDLAR_RGWR(qinx, GET_TX_DESC_DMA_ADDR(qinx, start_index));

	DBGPR("<--tx_descriptor_init_pg\n");
}

/*!
 * \brief This sequence is used to initialize the rx descriptors.
 * \param[in] pdata
 */

static void rx_descriptor_init_pg(struct DWC_ETH_QOS_prv_data *pdata, UINT QINX)
{
	struct DWC_ETH_QOS_rx_wrapper_descriptor *rx_desc_data =
	    GET_RX_WRAPPER_DESC(QINX);
	struct DWC_ETH_QOS_rx_buffer *buffer =
	    GET_RX_BUF_PTR(QINX, rx_desc_data->cur_rx);
	struct s_RX_NORMAL_DESC *RX_NORMAL_DESC =
	    GET_RX_DESC_PTR(QINX, rx_desc_data->cur_rx);
	INT i;
	INT start_index = rx_desc_data->cur_rx;
	INT last_index;

	DBGPR("-->rx_descriptor_init_pg\n");

	/* initialize all desc */

	for (i = 0; i < pdata->rx_queue[QINX].desc_cnt; i++) {
		memset(RX_NORMAL_DESC, 0, sizeof(struct s_RX_NORMAL_DESC));
		/* update buffer 1 address pointer */
		RX_NORMAL_DESC_RDES0_ML_WR(RX_NORMAL_DESC->RDES0, buffer->dma);
		/* set to zero  */
		RX_NORMAL_DESC_RDES1_ML_WR(RX_NORMAL_DESC->RDES1, 0);

		/* set buffer 2 address pointer to zero */
		RX_NORMAL_DESC_RDES2_ML_WR(RX_NORMAL_DESC->RDES2, 0);
		/* set control bits - OWN, INTE and BUF1V */
		RX_NORMAL_DESC_RDES3_ML_WR(RX_NORMAL_DESC->RDES3, (0xc1000000));

		INCR_RX_DESC_INDEX(rx_desc_data->cur_rx, 1, pdata->rx_queue[QINX].desc_cnt);
		RX_NORMAL_DESC =
			GET_RX_DESC_PTR(QINX, rx_desc_data->cur_rx);
		buffer = GET_RX_BUF_PTR(QINX, rx_desc_data->cur_rx);
	}
	/* update the total no of Rx descriptors count */
	DMA_RDRLR_RGWR(QINX, (pdata->rx_queue[QINX].desc_cnt - 1));
	/* update the Rx Descriptor Tail Pointer */
	last_index = GET_RX_CURRENT_RCVD_LAST_DESC_INDEX(start_index,
			0, pdata->rx_queue[QINX].desc_cnt);
	DMA_RDTP_RPDR_RGWR(QINX, GET_RX_DESC_DMA_ADDR(QINX, last_index));
	/* update the starting address of desc chain/ring */
	DMA_RDLAR_RGWR(QINX, GET_RX_DESC_DMA_ADDR(QINX, start_index));

	DBGPR("<--rx_descriptor_init_pg\n");
}

#endif /* end of DWC_ETH_QOS_CONFIG_PGTEST */

/*!
 * \brief This sequence is used to enable PHY interrupt to EMAC
 * \retval  0 Success
 */
static int enable_mac_phy_interrupt(void)
{
	unsigned long varmac_imr = 0;
	/* PHYIE - PHY Interrupt Enable */
	MAC_IMR_RGRD(varmac_imr);
	varmac_imr = varmac_imr & (unsigned long)(0x1008);
	varmac_imr = varmac_imr | ((0x1) << 3);
	MAC_IMR_RGWR(varmac_imr);
	EMACDBG("Enabled MAC-PHY interrupt\n");

	return Y_SUCCESS;
}

/*!
 * \brief API to initialize the function pointers.
 *
 * \details This function is called in probe to initialize all the
 * function pointers which are used in other functions to capture
 * the different device features.
 *
 * \param[in] hw_if - pointer to hw_if_struct structure.
 *
 * \return void.
 */

void DWC_ETH_QOS_init_function_ptrs_dev(struct hw_if_struct *hw_if)
{
	DBGPR("-->DWC_ETH_QOS_init_function_ptrs_dev\n");

	hw_if->tx_complete = tx_complete;
	hw_if->tx_window_error = NULL;
	hw_if->tx_aborted_error = tx_aborted_error;
	hw_if->tx_carrier_lost_error = tx_carrier_lost_error;
	hw_if->tx_fifo_underrun = tx_fifo_underrun;
	hw_if->tx_get_collision_count = NULL;
	hw_if->tx_handle_aborted_error = NULL;
	hw_if->tx_update_fifo_threshold = NULL;
	hw_if->tx_config_threshold = NULL;

	hw_if->set_promiscuous_mode = set_promiscuous_mode;
	hw_if->set_all_multicast_mode = set_all_multicast_mode;
	hw_if->set_multicast_list_mode = set_multicast_list_mode;
	hw_if->set_unicast_mode = set_unicast_mode;

	hw_if->enable_rx_csum = enable_rx_csum;
	hw_if->disable_rx_csum = disable_rx_csum;
	hw_if->get_rx_csum_status = get_rx_csum_status;

	hw_if->write_phy_regs = write_phy_regs;
	hw_if->read_phy_regs = read_phy_regs;
	hw_if->set_full_duplex = set_full_duplex;
	hw_if->set_half_duplex = set_half_duplex;
	hw_if->set_mii_speed_100 = set_mii_speed_100;
	hw_if->set_mii_speed_10 = set_mii_speed_10;
	hw_if->set_gmii_speed = set_gmii_speed;
	/* for PMT */
	hw_if->start_dma_rx = start_dma_rx;
	hw_if->stop_dma_rx = stop_dma_rx;
	hw_if->start_dma_tx = start_dma_tx;
	hw_if->stop_dma_tx = stop_dma_tx;
	hw_if->start_mac_tx_rx = start_mac_tx_rx;
	hw_if->stop_mac_tx_rx = stop_mac_tx_rx;

	hw_if->pre_xmit = pre_transmit;
	hw_if->dev_read = device_read;
	hw_if->init = DWC_ETH_QOS_yinit;
	hw_if->exit = DWC_ETH_QOS_yexit;
	
	hw_if->init_offload = DWC_ETH_QOS_yinit_offload;
	hw_if->exit_offload = DWC_ETH_QOS_yexit_offload;
			
	/* Descriptor related Sequences have to be initialized here */
	hw_if->tx_desc_init = tx_descriptor_init;
	hw_if->rx_desc_init = rx_descriptor_init;
	hw_if->rx_desc_reset = rx_descriptor_reset;
	hw_if->tx_desc_reset = tx_descriptor_reset;
	hw_if->get_tx_desc_ls = get_tx_descriptor_last;
	hw_if->get_tx_desc_ctxt = get_tx_descriptor_ctxt;
	hw_if->update_rx_tail_ptr = update_rx_tail_ptr;

	/* for FLOW ctrl */
	hw_if->enable_rx_flow_ctrl = enable_rx_flow_ctrl;
	hw_if->disable_rx_flow_ctrl = disable_rx_flow_ctrl;
	hw_if->enable_tx_flow_ctrl = enable_tx_flow_ctrl;
	hw_if->disable_tx_flow_ctrl = disable_tx_flow_ctrl;

	/* for PMT operation */
	hw_if->enable_magic_pmt = enable_magic_pmt_operation;
	hw_if->disable_magic_pmt = disable_magic_pmt_operation;
	hw_if->enable_remote_pmt = enable_remote_pmt_operation;
	hw_if->disable_remote_pmt = disable_remote_pmt_operation;
	hw_if->configure_rwk_filter = configure_rwk_filter_registers;

    /* for TX vlan control */
	hw_if->enable_vlan_reg_control = configure_reg_vlan_control;
	hw_if->enable_vlan_desc_control = configure_desc_vlan_control;

	/* for rx vlan stripping */
	hw_if->config_rx_outer_vlan_stripping =
	    config_rx_outer_vlan_stripping;
	hw_if->config_rx_inner_vlan_stripping =
	    config_rx_inner_vlan_stripping;

	/* for sa(source address) insert/replace */
	hw_if->configure_mac_addr0_reg = configure_mac_addr0_reg;
	hw_if->configure_mac_addr1_reg = configure_mac_addr1_reg;
	hw_if->configure_sa_via_reg = configure_sa_via_reg;

	/* for RX watchdog timer */
	hw_if->config_rx_watchdog = config_rx_watchdog_timer;

	/* for RX and TX threshold config */
	hw_if->config_rx_threshold = config_rx_threshold;
	hw_if->config_tx_threshold = config_tx_threshold;

	/* for RX and TX Store and Forward Mode config */
	hw_if->config_rsf_mode = config_rsf_mode;
	hw_if->config_tsf_mode = config_tsf_mode;

	/* for TX DMA Operating on Second Frame config */
	hw_if->config_osf_mode = config_osf_mode;

	/* for INCR/INCRX config */
	hw_if->config_incr_incrx_mode = config_incr_incrx_mode;
	/* for AXI PBL config */
	hw_if->config_axi_pbl_val = config_axi_pbl_val;
	/* for AXI WORL config */
	hw_if->config_axi_worl_val = config_axi_worl_val;
	/* for AXI RORL config */
	hw_if->config_axi_rorl_val = config_axi_rorl_val;

	/* for RX and TX PBL config */
	hw_if->config_rx_pbl_val = config_rx_pbl_val;
	hw_if->get_rx_pbl_val = get_rx_pbl_val;
	hw_if->config_tx_pbl_val = config_tx_pbl_val;
	hw_if->get_tx_pbl_val = get_tx_pbl_val;
	hw_if->config_pblx8 = config_pblx8;

	hw_if->disable_rx_interrupt = disable_rx_interrupt;
	hw_if->enable_rx_interrupt = enable_rx_interrupt;

	/* for handling MMC */
	hw_if->disable_mmc_interrupts = disable_mmc_interrupts;
	hw_if->config_mmc_counters = config_mmc_counters;

	/* for handling split header */
	hw_if->config_split_header_mode = config_split_header_mode;
	hw_if->config_header_size = config_header_size;

	hw_if->set_dcb_algorithm = set_dcb_algorithm;
	hw_if->set_dcb_queue_weight = set_dcb_queue_weight;

	hw_if->set_tx_queue_operating_mode = set_tx_queue_operating_mode;
	hw_if->set_avb_algorithm = set_avb_algorithm;
	hw_if->config_credit_control = config_credit_control;
	hw_if->config_send_slope = config_send_slope;
	hw_if->config_idle_slope = config_idle_slope;
	hw_if->config_high_credit = config_high_credit;
	hw_if->config_low_credit = config_low_credit;
	hw_if->config_slot_num_check = config_slot_num_check;
	hw_if->config_advance_slot_num_check = config_advance_slot_num_check;
#ifdef DWC_ETH_QOS_CONFIG_PGTEST
	hw_if->tx_desc_init_pg = tx_descriptor_init_pg;
	hw_if->rx_desc_init_pg = rx_descriptor_init_pg;
	hw_if->set_ch_arb_weights = set_ch_arb_weights;
	hw_if->config_slot_interrupt = config_slot_interrupt;
	hw_if->set_slot_count = set_slot_count;
	hw_if->set_tx_rx_prio_policy = set_tx_rx_prio_policy;
	hw_if->set_tx_rx_prio = set_tx_rx_prio;
	hw_if->set_tx_rx_prio_ratio = set_tx_rx_prio_ratio;
	hw_if->set_dma_tx_arb_algorithm = set_dma_tx_arb_algorithm;
	hw_if->prepare_dev_pktgen = prepare_dev_pktgen;
#endif /* end of DWC_ETH_QOS_CONFIG_PGTEST */

	/* for hw time stamping */
	hw_if->config_hw_time_stamping = config_hw_time_stamping;
	hw_if->config_sub_second_increment = config_sub_second_increment;
	hw_if->config_default_addend = config_default_addend;
	hw_if->init_systime = init_systime;
	hw_if->config_addend = config_addend;
	hw_if->adjust_systime = adjust_systime;
	hw_if->get_systime = get_systime;
	hw_if->get_tx_tstamp_status = get_tx_tstamp_status;
	hw_if->get_tx_tstamp = get_tx_tstamp;
	hw_if->get_tx_tstamp_status_via_reg = get_tx_tstamp_status_via_reg;
	hw_if->get_tx_tstamp_via_reg = get_tx_tstamp_via_reg;
	hw_if->rx_tstamp_available = rx_tstamp_available;
	hw_if->get_rx_tstamp_status = get_rx_tstamp_status;
	hw_if->get_rx_tstamp = get_rx_tstamp;
	hw_if->drop_tx_status_enabled = drop_tx_status_enabled;

	/* for l3 and l4 layer filtering */
	hw_if->config_l2_da_perfect_inverse_match =
		config_l2_da_perfect_inverse_match;
	hw_if->update_mac_addr32_127_low_high_reg =
		update_mac_addr32_127_low_high_reg;
	hw_if->update_mac_addr1_31_low_high_reg =
		update_mac_addr1_31_low_high_reg;
	hw_if->update_hash_table_reg = update_hash_table_reg;
	hw_if->config_mac_pkt_filter_reg = config_mac_pkt_filter_reg;
	hw_if->config_l3_l4_filter_enable = config_l3_l4_filter_enable;
	hw_if->config_l3_filters = config_l3_filters;
	hw_if->update_ip4_addr0 = update_ip4_addr0;
	hw_if->update_ip4_addr1 = update_ip4_addr1;
	hw_if->update_ip6_addr = update_ip6_addr;
	hw_if->config_l4_filters = config_l4_filters;
	hw_if->update_l4_sa_port_no = update_l4_sa_port_no;
	hw_if->update_l4_da_port_no = update_l4_da_port_no;

	/* for VLAN filtering */
	hw_if->get_vlan_hash_table_reg = get_vlan_hash_table_reg;
	hw_if->update_vlan_hash_table_reg = update_vlan_hash_table_reg;
	hw_if->update_vlan_id = update_vlan_id;
	hw_if->config_vlan_filtering = config_vlan_filtering;
	hw_if->config_mac_for_vlan_pkt = configure_mac_for_vlan_pkt;
	hw_if->get_vlan_tag_comparison = get_vlan_tag_comparison;
	hw_if->config_vlan_tag_data = config_vlan_tag_data;

	/* for differnet PHY interconnect */
	hw_if->control_an = control_an;
	hw_if->get_an_adv_pause_param = get_an_adv_pause_param;
	hw_if->get_an_adv_duplex_param = get_an_adv_duplex_param;
	hw_if->get_lp_an_adv_pause_param = get_lp_an_adv_pause_param;
	hw_if->get_lp_an_adv_duplex_param = get_lp_an_adv_duplex_param;

	/* for EEE */
	hw_if->set_eee_mode = set_eee_mode;
	hw_if->reset_eee_mode = reset_eee_mode;
	hw_if->set_eee_pls = set_eee_pls;
	hw_if->set_eee_timer = set_eee_timer;
	hw_if->get_lpi_status = get_lpi_status;
	hw_if->set_lpi_tx_automate = set_lpi_tx_automate;
	hw_if->set_lpi_tx_auto_entry_timer_en = set_lpi_tx_auto_entry_timer_en;
	hw_if->set_lpi_tx_auto_entry_timer = set_lpi_tx_auto_entry_timer;
	hw_if->set_lpi_us_tic_counter = set_lpi_us_tic_counter;

	/* for ARP */
	hw_if->config_arp_offload = config_arp_offload;
	hw_if->update_arp_offload_ip_addr = update_arp_offload_ip_addr;

	/* for MAC loopback */
	hw_if->config_mac_loopback_mode = config_mac_loopback_mode;

	/* for PFC */
	hw_if->config_pfc = config_pfc;

    /* for MAC Double VLAN Processing config */
	hw_if->config_tx_outer_vlan = config_tx_outer_vlan;
	hw_if->config_tx_inner_vlan = config_tx_inner_vlan;
	hw_if->config_svlan = config_svlan;
	hw_if->config_dvlan = config_dvlan;
	hw_if->config_rx_outer_vlan_stripping = config_rx_outer_vlan_stripping;
	hw_if->config_rx_inner_vlan_stripping = config_rx_inner_vlan_stripping;

	/* for PTP Offloading */
	hw_if->config_ptpoffload_engine = config_ptpoffload_engine;

	/* For enabling PHY interrupt to EMAC */
	hw_if->enable_mac_phy_interrupt = enable_mac_phy_interrupt;

	DBGPR("<--DWC_ETH_QOS_init_function_ptrs_dev\n");
}
