162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * AMD 10Gb Ethernet driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is available to you under your choice of the following two
562306a36Sopenharmony_ci * licenses:
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * License 1: GPLv2
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * This file is free software; you may copy, redistribute and/or modify
1262306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
1362306a36Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or (at
1462306a36Sopenharmony_ci * your option) any later version.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * This file is distributed in the hope that it will be useful, but
1762306a36Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
1862306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1962306a36Sopenharmony_ci * General Public License for more details.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License
2262306a36Sopenharmony_ci * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and
2562306a36Sopenharmony_ci * permission notice:
2662306a36Sopenharmony_ci *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
2762306a36Sopenharmony_ci *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
2862306a36Sopenharmony_ci *     Inc. unless otherwise expressly agreed to in writing between Synopsys
2962306a36Sopenharmony_ci *     and you.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci *     The Software IS NOT an item of Licensed Software or Licensed Product
3262306a36Sopenharmony_ci *     under any End User Software License Agreement or Agreement for Licensed
3362306a36Sopenharmony_ci *     Product with Synopsys or any supplement thereto.  Permission is hereby
3462306a36Sopenharmony_ci *     granted, free of charge, to any person obtaining a copy of this software
3562306a36Sopenharmony_ci *     annotated with this license and the Software, to deal in the Software
3662306a36Sopenharmony_ci *     without restriction, including without limitation the rights to use,
3762306a36Sopenharmony_ci *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
3862306a36Sopenharmony_ci *     of the Software, and to permit persons to whom the Software is furnished
3962306a36Sopenharmony_ci *     to do so, subject to the following conditions:
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci *     The above copyright notice and this permission notice shall be included
4262306a36Sopenharmony_ci *     in all copies or substantial portions of the Software.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4562306a36Sopenharmony_ci *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
4662306a36Sopenharmony_ci *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
4762306a36Sopenharmony_ci *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
4862306a36Sopenharmony_ci *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4962306a36Sopenharmony_ci *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5062306a36Sopenharmony_ci *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5162306a36Sopenharmony_ci *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5262306a36Sopenharmony_ci *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5362306a36Sopenharmony_ci *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
5462306a36Sopenharmony_ci *     THE POSSIBILITY OF SUCH DAMAGE.
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * License 2: Modified BSD
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
6062306a36Sopenharmony_ci * All rights reserved.
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
6362306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
6462306a36Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
6562306a36Sopenharmony_ci *       notice, this list of conditions and the following disclaimer.
6662306a36Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
6762306a36Sopenharmony_ci *       notice, this list of conditions and the following disclaimer in the
6862306a36Sopenharmony_ci *       documentation and/or other materials provided with the distribution.
6962306a36Sopenharmony_ci *     * Neither the name of Advanced Micro Devices, Inc. nor the
7062306a36Sopenharmony_ci *       names of its contributors may be used to endorse or promote products
7162306a36Sopenharmony_ci *       derived from this software without specific prior written permission.
7262306a36Sopenharmony_ci *
7362306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7462306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7562306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7662306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
7762306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7862306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
7962306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
8062306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8162306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
8262306a36Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and
8562306a36Sopenharmony_ci * permission notice:
8662306a36Sopenharmony_ci *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
8762306a36Sopenharmony_ci *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
8862306a36Sopenharmony_ci *     Inc. unless otherwise expressly agreed to in writing between Synopsys
8962306a36Sopenharmony_ci *     and you.
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci *     The Software IS NOT an item of Licensed Software or Licensed Product
9262306a36Sopenharmony_ci *     under any End User Software License Agreement or Agreement for Licensed
9362306a36Sopenharmony_ci *     Product with Synopsys or any supplement thereto.  Permission is hereby
9462306a36Sopenharmony_ci *     granted, free of charge, to any person obtaining a copy of this software
9562306a36Sopenharmony_ci *     annotated with this license and the Software, to deal in the Software
9662306a36Sopenharmony_ci *     without restriction, including without limitation the rights to use,
9762306a36Sopenharmony_ci *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9862306a36Sopenharmony_ci *     of the Software, and to permit persons to whom the Software is furnished
9962306a36Sopenharmony_ci *     to do so, subject to the following conditions:
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci *     The above copyright notice and this permission notice shall be included
10262306a36Sopenharmony_ci *     in all copies or substantial portions of the Software.
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10562306a36Sopenharmony_ci *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
10662306a36Sopenharmony_ci *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
10762306a36Sopenharmony_ci *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
10862306a36Sopenharmony_ci *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10962306a36Sopenharmony_ci *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
11062306a36Sopenharmony_ci *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
11162306a36Sopenharmony_ci *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
11262306a36Sopenharmony_ci *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
11362306a36Sopenharmony_ci *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
11462306a36Sopenharmony_ci *     THE POSSIBILITY OF SUCH DAMAGE.
11562306a36Sopenharmony_ci */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#include <linux/phy.h>
11862306a36Sopenharmony_ci#include <linux/mdio.h>
11962306a36Sopenharmony_ci#include <linux/clk.h>
12062306a36Sopenharmony_ci#include <linux/bitrev.h>
12162306a36Sopenharmony_ci#include <linux/crc32.h>
12262306a36Sopenharmony_ci#include <linux/crc32poly.h>
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#include "xgbe.h"
12562306a36Sopenharmony_ci#include "xgbe-common.h"
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic inline unsigned int xgbe_get_max_frame(struct xgbe_prv_data *pdata)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	return pdata->netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata,
13362306a36Sopenharmony_ci				      unsigned int usec)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	unsigned long rate;
13662306a36Sopenharmony_ci	unsigned int ret;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	DBGPR("-->xgbe_usec_to_riwt\n");
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	rate = pdata->sysclk_rate;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/*
14362306a36Sopenharmony_ci	 * Convert the input usec value to the watchdog timer value. Each
14462306a36Sopenharmony_ci	 * watchdog timer value is equivalent to 256 clock cycles.
14562306a36Sopenharmony_ci	 * Calculate the required value as:
14662306a36Sopenharmony_ci	 *   ( usec * ( system_clock_mhz / 10^6 ) / 256
14762306a36Sopenharmony_ci	 */
14862306a36Sopenharmony_ci	ret = (usec * (rate / 1000000)) / 256;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	DBGPR("<--xgbe_usec_to_riwt\n");
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return ret;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata,
15662306a36Sopenharmony_ci				      unsigned int riwt)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	unsigned long rate;
15962306a36Sopenharmony_ci	unsigned int ret;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	DBGPR("-->xgbe_riwt_to_usec\n");
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	rate = pdata->sysclk_rate;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/*
16662306a36Sopenharmony_ci	 * Convert the input watchdog timer value to the usec value. Each
16762306a36Sopenharmony_ci	 * watchdog timer value is equivalent to 256 clock cycles.
16862306a36Sopenharmony_ci	 * Calculate the required value as:
16962306a36Sopenharmony_ci	 *   ( riwt * 256 ) / ( system_clock_mhz / 10^6 )
17062306a36Sopenharmony_ci	 */
17162306a36Sopenharmony_ci	ret = (riwt * 256) / (rate / 1000000);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	DBGPR("<--xgbe_riwt_to_usec\n");
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return ret;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic int xgbe_config_pbl_val(struct xgbe_prv_data *pdata)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	unsigned int pblx8, pbl;
18162306a36Sopenharmony_ci	unsigned int i;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	pblx8 = DMA_PBL_X8_DISABLE;
18462306a36Sopenharmony_ci	pbl = pdata->pbl;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (pdata->pbl > 32) {
18762306a36Sopenharmony_ci		pblx8 = DMA_PBL_X8_ENABLE;
18862306a36Sopenharmony_ci		pbl >>= 3;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
19262306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, PBLX8,
19362306a36Sopenharmony_ci				       pblx8);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		if (pdata->channel[i]->tx_ring)
19662306a36Sopenharmony_ci			XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR,
19762306a36Sopenharmony_ci					       PBL, pbl);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		if (pdata->channel[i]->rx_ring)
20062306a36Sopenharmony_ci			XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR,
20162306a36Sopenharmony_ci					       PBL, pbl);
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return 0;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int xgbe_config_osp_mode(struct xgbe_prv_data *pdata)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	unsigned int i;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
21262306a36Sopenharmony_ci		if (!pdata->channel[i]->tx_ring)
21362306a36Sopenharmony_ci			break;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, OSP,
21662306a36Sopenharmony_ci				       pdata->tx_osp_mode);
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	return 0;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic int xgbe_config_rsf_mode(struct xgbe_prv_data *pdata, unsigned int val)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	unsigned int i;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count; i++)
22762306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RSF, val);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	return 0;
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic int xgbe_config_tsf_mode(struct xgbe_prv_data *pdata, unsigned int val)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	unsigned int i;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	for (i = 0; i < pdata->tx_q_count; i++)
23762306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TSF, val);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return 0;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int xgbe_config_rx_threshold(struct xgbe_prv_data *pdata,
24362306a36Sopenharmony_ci				    unsigned int val)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	unsigned int i;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count; i++)
24862306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RTC, val);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	return 0;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic int xgbe_config_tx_threshold(struct xgbe_prv_data *pdata,
25462306a36Sopenharmony_ci				    unsigned int val)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	unsigned int i;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	for (i = 0; i < pdata->tx_q_count; i++)
25962306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TTC, val);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return 0;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int xgbe_config_rx_coalesce(struct xgbe_prv_data *pdata)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	unsigned int i;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
26962306a36Sopenharmony_ci		if (!pdata->channel[i]->rx_ring)
27062306a36Sopenharmony_ci			break;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RIWT, RWT,
27362306a36Sopenharmony_ci				       pdata->rx_riwt);
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return 0;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic int xgbe_config_tx_coalesce(struct xgbe_prv_data *pdata)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	return 0;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic void xgbe_config_rx_buffer_size(struct xgbe_prv_data *pdata)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	unsigned int i;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
28962306a36Sopenharmony_ci		if (!pdata->channel[i]->rx_ring)
29062306a36Sopenharmony_ci			break;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, RBSZ,
29362306a36Sopenharmony_ci				       pdata->rx_buf_size);
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic void xgbe_config_tso_mode(struct xgbe_prv_data *pdata)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	unsigned int i;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
30262306a36Sopenharmony_ci		if (!pdata->channel[i]->tx_ring)
30362306a36Sopenharmony_ci			break;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, TSE, 1);
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic void xgbe_config_sph_mode(struct xgbe_prv_data *pdata)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	unsigned int i;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
31462306a36Sopenharmony_ci		if (!pdata->channel[i]->rx_ring)
31562306a36Sopenharmony_ci			break;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, SPH, 1);
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, HDSMS, XGBE_SPH_HDSMS_SIZE);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int xgbe_write_rss_reg(struct xgbe_prv_data *pdata, unsigned int type,
32462306a36Sopenharmony_ci			      unsigned int index, unsigned int val)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	unsigned int wait;
32762306a36Sopenharmony_ci	int ret = 0;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	mutex_lock(&pdata->rss_mutex);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (XGMAC_IOREAD_BITS(pdata, MAC_RSSAR, OB)) {
33262306a36Sopenharmony_ci		ret = -EBUSY;
33362306a36Sopenharmony_ci		goto unlock;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_RSSDR, val);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RSSAR, RSSIA, index);
33962306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RSSAR, ADDRT, type);
34062306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RSSAR, CT, 0);
34162306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RSSAR, OB, 1);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	wait = 1000;
34462306a36Sopenharmony_ci	while (wait--) {
34562306a36Sopenharmony_ci		if (!XGMAC_IOREAD_BITS(pdata, MAC_RSSAR, OB))
34662306a36Sopenharmony_ci			goto unlock;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		usleep_range(1000, 1500);
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	ret = -EBUSY;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ciunlock:
35462306a36Sopenharmony_ci	mutex_unlock(&pdata->rss_mutex);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return ret;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int xgbe_write_rss_hash_key(struct xgbe_prv_data *pdata)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	unsigned int key_regs = sizeof(pdata->rss_key) / sizeof(u32);
36262306a36Sopenharmony_ci	unsigned int *key = (unsigned int *)&pdata->rss_key;
36362306a36Sopenharmony_ci	int ret;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	while (key_regs--) {
36662306a36Sopenharmony_ci		ret = xgbe_write_rss_reg(pdata, XGBE_RSS_HASH_KEY_TYPE,
36762306a36Sopenharmony_ci					 key_regs, *key++);
36862306a36Sopenharmony_ci		if (ret)
36962306a36Sopenharmony_ci			return ret;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	return 0;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic int xgbe_write_rss_lookup_table(struct xgbe_prv_data *pdata)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	unsigned int i;
37862306a36Sopenharmony_ci	int ret;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++) {
38162306a36Sopenharmony_ci		ret = xgbe_write_rss_reg(pdata,
38262306a36Sopenharmony_ci					 XGBE_RSS_LOOKUP_TABLE_TYPE, i,
38362306a36Sopenharmony_ci					 pdata->rss_table[i]);
38462306a36Sopenharmony_ci		if (ret)
38562306a36Sopenharmony_ci			return ret;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return 0;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic int xgbe_set_rss_hash_key(struct xgbe_prv_data *pdata, const u8 *key)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	memcpy(pdata->rss_key, key, sizeof(pdata->rss_key));
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return xgbe_write_rss_hash_key(pdata);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int xgbe_set_rss_lookup_table(struct xgbe_prv_data *pdata,
39962306a36Sopenharmony_ci				     const u32 *table)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	unsigned int i;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++)
40462306a36Sopenharmony_ci		XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH, table[i]);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return xgbe_write_rss_lookup_table(pdata);
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic int xgbe_enable_rss(struct xgbe_prv_data *pdata)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	int ret;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (!pdata->hw_feat.rss)
41462306a36Sopenharmony_ci		return -EOPNOTSUPP;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	/* Program the hash key */
41762306a36Sopenharmony_ci	ret = xgbe_write_rss_hash_key(pdata);
41862306a36Sopenharmony_ci	if (ret)
41962306a36Sopenharmony_ci		return ret;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/* Program the lookup table */
42262306a36Sopenharmony_ci	ret = xgbe_write_rss_lookup_table(pdata);
42362306a36Sopenharmony_ci	if (ret)
42462306a36Sopenharmony_ci		return ret;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* Set the RSS options */
42762306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_RSSCR, pdata->rss_options);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* Enable RSS */
43062306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RSSCR, RSSE, 1);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	return 0;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic int xgbe_disable_rss(struct xgbe_prv_data *pdata)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	if (!pdata->hw_feat.rss)
43862306a36Sopenharmony_ci		return -EOPNOTSUPP;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RSSCR, RSSE, 0);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return 0;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic void xgbe_config_rss(struct xgbe_prv_data *pdata)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	int ret;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (!pdata->hw_feat.rss)
45062306a36Sopenharmony_ci		return;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (pdata->netdev->features & NETIF_F_RXHASH)
45362306a36Sopenharmony_ci		ret = xgbe_enable_rss(pdata);
45462306a36Sopenharmony_ci	else
45562306a36Sopenharmony_ci		ret = xgbe_disable_rss(pdata);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (ret)
45862306a36Sopenharmony_ci		netdev_err(pdata->netdev,
45962306a36Sopenharmony_ci			   "error configuring RSS, RSS disabled\n");
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic bool xgbe_is_pfc_queue(struct xgbe_prv_data *pdata,
46362306a36Sopenharmony_ci			      unsigned int queue)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	unsigned int prio, tc;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) {
46862306a36Sopenharmony_ci		/* Does this queue handle the priority? */
46962306a36Sopenharmony_ci		if (pdata->prio2q_map[prio] != queue)
47062306a36Sopenharmony_ci			continue;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		/* Get the Traffic Class for this priority */
47362306a36Sopenharmony_ci		tc = pdata->ets->prio_tc[prio];
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		/* Check if PFC is enabled for this traffic class */
47662306a36Sopenharmony_ci		if (pdata->pfc->pfc_en & (1 << tc))
47762306a36Sopenharmony_ci			return true;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	return false;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic void xgbe_set_vxlan_id(struct xgbe_prv_data *pdata)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	/* Program the VXLAN port */
48662306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TIR, TNID, pdata->vxlan_port);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	netif_dbg(pdata, drv, pdata->netdev, "VXLAN tunnel id set to %hx\n",
48962306a36Sopenharmony_ci		  pdata->vxlan_port);
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic void xgbe_enable_vxlan(struct xgbe_prv_data *pdata)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	if (!pdata->hw_feat.vxn)
49562306a36Sopenharmony_ci		return;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/* Program the VXLAN port */
49862306a36Sopenharmony_ci	xgbe_set_vxlan_id(pdata);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/* Allow for IPv6/UDP zero-checksum VXLAN packets */
50162306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VUCC, 1);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* Enable VXLAN tunneling mode */
50462306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TCR, VNM, 0);
50562306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TCR, VNE, 1);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	netif_dbg(pdata, drv, pdata->netdev, "VXLAN acceleration enabled\n");
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic void xgbe_disable_vxlan(struct xgbe_prv_data *pdata)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	if (!pdata->hw_feat.vxn)
51362306a36Sopenharmony_ci		return;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/* Disable tunneling mode */
51662306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TCR, VNE, 0);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* Clear IPv6/UDP zero-checksum VXLAN packets setting */
51962306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VUCC, 0);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/* Clear the VXLAN port */
52262306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TIR, TNID, 0);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	netif_dbg(pdata, drv, pdata->netdev, "VXLAN acceleration disabled\n");
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic unsigned int xgbe_get_fc_queue_count(struct xgbe_prv_data *pdata)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	unsigned int max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* From MAC ver 30H the TFCR is per priority, instead of per queue */
53262306a36Sopenharmony_ci	if (XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER) >= 0x30)
53362306a36Sopenharmony_ci		return max_q_count;
53462306a36Sopenharmony_ci	else
53562306a36Sopenharmony_ci		return min_t(unsigned int, pdata->tx_q_count, max_q_count);
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	unsigned int reg, reg_val;
54162306a36Sopenharmony_ci	unsigned int i, q_count;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* Clear MTL flow control */
54462306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count; i++)
54562306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 0);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/* Clear MAC flow control */
54862306a36Sopenharmony_ci	q_count = xgbe_get_fc_queue_count(pdata);
54962306a36Sopenharmony_ci	reg = MAC_Q0TFCR;
55062306a36Sopenharmony_ci	for (i = 0; i < q_count; i++) {
55162306a36Sopenharmony_ci		reg_val = XGMAC_IOREAD(pdata, reg);
55262306a36Sopenharmony_ci		XGMAC_SET_BITS(reg_val, MAC_Q0TFCR, TFE, 0);
55362306a36Sopenharmony_ci		XGMAC_IOWRITE(pdata, reg, reg_val);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		reg += MAC_QTFCR_INC;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return 0;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	struct ieee_pfc *pfc = pdata->pfc;
56462306a36Sopenharmony_ci	struct ieee_ets *ets = pdata->ets;
56562306a36Sopenharmony_ci	unsigned int reg, reg_val;
56662306a36Sopenharmony_ci	unsigned int i, q_count;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	/* Set MTL flow control */
56962306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count; i++) {
57062306a36Sopenharmony_ci		unsigned int ehfc = 0;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci		if (pdata->rx_rfd[i]) {
57362306a36Sopenharmony_ci			/* Flow control thresholds are established */
57462306a36Sopenharmony_ci			if (pfc && ets) {
57562306a36Sopenharmony_ci				if (xgbe_is_pfc_queue(pdata, i))
57662306a36Sopenharmony_ci					ehfc = 1;
57762306a36Sopenharmony_ci			} else {
57862306a36Sopenharmony_ci				ehfc = 1;
57962306a36Sopenharmony_ci			}
58062306a36Sopenharmony_ci		}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, ehfc);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		netif_dbg(pdata, drv, pdata->netdev,
58562306a36Sopenharmony_ci			  "flow control %s for RXq%u\n",
58662306a36Sopenharmony_ci			  ehfc ? "enabled" : "disabled", i);
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	/* Set MAC flow control */
59062306a36Sopenharmony_ci	q_count = xgbe_get_fc_queue_count(pdata);
59162306a36Sopenharmony_ci	reg = MAC_Q0TFCR;
59262306a36Sopenharmony_ci	for (i = 0; i < q_count; i++) {
59362306a36Sopenharmony_ci		reg_val = XGMAC_IOREAD(pdata, reg);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci		/* Enable transmit flow control */
59662306a36Sopenharmony_ci		XGMAC_SET_BITS(reg_val, MAC_Q0TFCR, TFE, 1);
59762306a36Sopenharmony_ci		/* Set pause time */
59862306a36Sopenharmony_ci		XGMAC_SET_BITS(reg_val, MAC_Q0TFCR, PT, 0xffff);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		XGMAC_IOWRITE(pdata, reg, reg_val);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		reg += MAC_QTFCR_INC;
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	return 0;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic int xgbe_disable_rx_flow_control(struct xgbe_prv_data *pdata)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RFCR, RFE, 0);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	return 0;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic int xgbe_enable_rx_flow_control(struct xgbe_prv_data *pdata)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RFCR, RFE, 1);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	return 0;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic int xgbe_config_tx_flow_control(struct xgbe_prv_data *pdata)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	struct ieee_pfc *pfc = pdata->pfc;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (pdata->tx_pause || (pfc && pfc->pfc_en))
62762306a36Sopenharmony_ci		xgbe_enable_tx_flow_control(pdata);
62862306a36Sopenharmony_ci	else
62962306a36Sopenharmony_ci		xgbe_disable_tx_flow_control(pdata);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return 0;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic int xgbe_config_rx_flow_control(struct xgbe_prv_data *pdata)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct ieee_pfc *pfc = pdata->pfc;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if (pdata->rx_pause || (pfc && pfc->pfc_en))
63962306a36Sopenharmony_ci		xgbe_enable_rx_flow_control(pdata);
64062306a36Sopenharmony_ci	else
64162306a36Sopenharmony_ci		xgbe_disable_rx_flow_control(pdata);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	return 0;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic void xgbe_config_flow_control(struct xgbe_prv_data *pdata)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	struct ieee_pfc *pfc = pdata->pfc;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	xgbe_config_tx_flow_control(pdata);
65162306a36Sopenharmony_ci	xgbe_config_rx_flow_control(pdata);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RFCR, PFCE,
65462306a36Sopenharmony_ci			   (pfc && pfc->pfc_en) ? 1 : 0);
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct xgbe_channel *channel;
66062306a36Sopenharmony_ci	unsigned int i, ver;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/* Set the interrupt mode if supported */
66362306a36Sopenharmony_ci	if (pdata->channel_irq_mode)
66462306a36Sopenharmony_ci		XGMAC_IOWRITE_BITS(pdata, DMA_MR, INTM,
66562306a36Sopenharmony_ci				   pdata->channel_irq_mode);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
67062306a36Sopenharmony_ci		channel = pdata->channel[i];
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci		/* Clear all the interrupts which are set */
67362306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE(channel, DMA_CH_SR,
67462306a36Sopenharmony_ci				  XGMAC_DMA_IOREAD(channel, DMA_CH_SR));
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		/* Clear all interrupt enable bits */
67762306a36Sopenharmony_ci		channel->curr_ier = 0;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		/* Enable following interrupts
68062306a36Sopenharmony_ci		 *   NIE  - Normal Interrupt Summary Enable
68162306a36Sopenharmony_ci		 *   AIE  - Abnormal Interrupt Summary Enable
68262306a36Sopenharmony_ci		 *   FBEE - Fatal Bus Error Enable
68362306a36Sopenharmony_ci		 */
68462306a36Sopenharmony_ci		if (ver < 0x21) {
68562306a36Sopenharmony_ci			XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, NIE20, 1);
68662306a36Sopenharmony_ci			XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, AIE20, 1);
68762306a36Sopenharmony_ci		} else {
68862306a36Sopenharmony_ci			XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, NIE, 1);
68962306a36Sopenharmony_ci			XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, AIE, 1);
69062306a36Sopenharmony_ci		}
69162306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, FBEE, 1);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		if (channel->tx_ring) {
69462306a36Sopenharmony_ci			/* Enable the following Tx interrupts
69562306a36Sopenharmony_ci			 *   TIE  - Transmit Interrupt Enable (unless using
69662306a36Sopenharmony_ci			 *          per channel interrupts in edge triggered
69762306a36Sopenharmony_ci			 *          mode)
69862306a36Sopenharmony_ci			 */
69962306a36Sopenharmony_ci			if (!pdata->per_channel_irq || pdata->channel_irq_mode)
70062306a36Sopenharmony_ci				XGMAC_SET_BITS(channel->curr_ier,
70162306a36Sopenharmony_ci					       DMA_CH_IER, TIE, 1);
70262306a36Sopenharmony_ci		}
70362306a36Sopenharmony_ci		if (channel->rx_ring) {
70462306a36Sopenharmony_ci			/* Enable following Rx interrupts
70562306a36Sopenharmony_ci			 *   RBUE - Receive Buffer Unavailable Enable
70662306a36Sopenharmony_ci			 *   RIE  - Receive Interrupt Enable (unless using
70762306a36Sopenharmony_ci			 *          per channel interrupts in edge triggered
70862306a36Sopenharmony_ci			 *          mode)
70962306a36Sopenharmony_ci			 */
71062306a36Sopenharmony_ci			XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RBUE, 1);
71162306a36Sopenharmony_ci			if (!pdata->per_channel_irq || pdata->channel_irq_mode)
71262306a36Sopenharmony_ci				XGMAC_SET_BITS(channel->curr_ier,
71362306a36Sopenharmony_ci					       DMA_CH_IER, RIE, 1);
71462306a36Sopenharmony_ci		}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, channel->curr_ier);
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic void xgbe_enable_mtl_interrupts(struct xgbe_prv_data *pdata)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	unsigned int mtl_q_isr;
72362306a36Sopenharmony_ci	unsigned int q_count, i;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	q_count = max(pdata->hw_feat.tx_q_cnt, pdata->hw_feat.rx_q_cnt);
72662306a36Sopenharmony_ci	for (i = 0; i < q_count; i++) {
72762306a36Sopenharmony_ci		/* Clear all the interrupts which are set */
72862306a36Sopenharmony_ci		mtl_q_isr = XGMAC_MTL_IOREAD(pdata, i, MTL_Q_ISR);
72962306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE(pdata, i, MTL_Q_ISR, mtl_q_isr);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		/* No MTL interrupts to be enabled */
73262306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE(pdata, i, MTL_Q_IER, 0);
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	unsigned int mac_ier = 0;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	/* Enable Timestamp interrupt */
74162306a36Sopenharmony_ci	XGMAC_SET_BITS(mac_ier, MAC_IER, TSIE, 1);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_IER, mac_ier);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	/* Enable all counter interrupts */
74662306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MMC_RIER, ALL_INTERRUPTS, 0xffffffff);
74762306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MMC_TIER, ALL_INTERRUPTS, 0xffffffff);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	/* Enable MDIO single command completion interrupt */
75062306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_MDIOIER, SNGLCOMPIE, 1);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic void xgbe_enable_ecc_interrupts(struct xgbe_prv_data *pdata)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	unsigned int ecc_isr, ecc_ier = 0;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (!pdata->vdata->ecc_support)
75862306a36Sopenharmony_ci		return;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	/* Clear all the interrupts which are set */
76162306a36Sopenharmony_ci	ecc_isr = XP_IOREAD(pdata, XP_ECC_ISR);
76262306a36Sopenharmony_ci	XP_IOWRITE(pdata, XP_ECC_ISR, ecc_isr);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	/* Enable ECC interrupts */
76562306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, TX_DED, 1);
76662306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, TX_SEC, 1);
76762306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, RX_DED, 1);
76862306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, RX_SEC, 1);
76962306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, DESC_DED, 1);
77062306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, DESC_SEC, 1);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	XP_IOWRITE(pdata, XP_ECC_IER, ecc_ier);
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cistatic void xgbe_disable_ecc_ded(struct xgbe_prv_data *pdata)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	unsigned int ecc_ier;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	ecc_ier = XP_IOREAD(pdata, XP_ECC_IER);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	/* Disable ECC DED interrupts */
78262306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, TX_DED, 0);
78362306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, RX_DED, 0);
78462306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, DESC_DED, 0);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	XP_IOWRITE(pdata, XP_ECC_IER, ecc_ier);
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic void xgbe_disable_ecc_sec(struct xgbe_prv_data *pdata,
79062306a36Sopenharmony_ci				 enum xgbe_ecc_sec sec)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	unsigned int ecc_ier;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	ecc_ier = XP_IOREAD(pdata, XP_ECC_IER);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	/* Disable ECC SEC interrupt */
79762306a36Sopenharmony_ci	switch (sec) {
79862306a36Sopenharmony_ci	case XGBE_ECC_SEC_TX:
79962306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, TX_SEC, 0);
80062306a36Sopenharmony_ci		break;
80162306a36Sopenharmony_ci	case XGBE_ECC_SEC_RX:
80262306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, RX_SEC, 0);
80362306a36Sopenharmony_ci		break;
80462306a36Sopenharmony_ci	case XGBE_ECC_SEC_DESC:
80562306a36Sopenharmony_ci	XP_SET_BITS(ecc_ier, XP_ECC_IER, DESC_SEC, 0);
80662306a36Sopenharmony_ci		break;
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	XP_IOWRITE(pdata, XP_ECC_IER, ecc_ier);
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic int xgbe_set_speed(struct xgbe_prv_data *pdata, int speed)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	unsigned int ss;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	switch (speed) {
81762306a36Sopenharmony_ci	case SPEED_10:
81862306a36Sopenharmony_ci		ss = 0x07;
81962306a36Sopenharmony_ci		break;
82062306a36Sopenharmony_ci	case SPEED_1000:
82162306a36Sopenharmony_ci		ss = 0x03;
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci	case SPEED_2500:
82462306a36Sopenharmony_ci		ss = 0x02;
82562306a36Sopenharmony_ci		break;
82662306a36Sopenharmony_ci	case SPEED_10000:
82762306a36Sopenharmony_ci		ss = 0x00;
82862306a36Sopenharmony_ci		break;
82962306a36Sopenharmony_ci	default:
83062306a36Sopenharmony_ci		return -EINVAL;
83162306a36Sopenharmony_ci	}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) != ss)
83462306a36Sopenharmony_ci		XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, ss);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	return 0;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int xgbe_enable_rx_vlan_stripping(struct xgbe_prv_data *pdata)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	/* Put the VLAN tag in the Rx descriptor */
84262306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLRXS, 1);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	/* Don't check the VLAN type */
84562306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, DOVLTC, 1);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	/* Check only C-TAG (0x8100) packets */
84862306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ERSVLM, 0);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	/* Don't consider an S-TAG (0x88A8) packet as a VLAN packet */
85162306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ESVL, 0);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/* Enable VLAN tag stripping */
85462306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLS, 0x3);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	return 0;
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_cistatic int xgbe_disable_rx_vlan_stripping(struct xgbe_prv_data *pdata)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLS, 0);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	return 0;
86462306a36Sopenharmony_ci}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic int xgbe_enable_rx_vlan_filtering(struct xgbe_prv_data *pdata)
86762306a36Sopenharmony_ci{
86862306a36Sopenharmony_ci	/* Enable VLAN filtering */
86962306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 1);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	/* Enable VLAN Hash Table filtering */
87262306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTHM, 1);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	/* Disable VLAN tag inverse matching */
87562306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTIM, 0);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* Only filter on the lower 12-bits of the VLAN tag */
87862306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ETV, 1);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* In order for the VLAN Hash Table filtering to be effective,
88162306a36Sopenharmony_ci	 * the VLAN tag identifier in the VLAN Tag Register must not
88262306a36Sopenharmony_ci	 * be zero.  Set the VLAN tag identifier to "1" to enable the
88362306a36Sopenharmony_ci	 * VLAN Hash Table filtering.  This implies that a VLAN tag of
88462306a36Sopenharmony_ci	 * 1 will always pass filtering.
88562306a36Sopenharmony_ci	 */
88662306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VL, 1);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	return 0;
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic int xgbe_disable_rx_vlan_filtering(struct xgbe_prv_data *pdata)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	/* Disable VLAN filtering */
89462306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 0);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	return 0;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_cistatic u32 xgbe_vid_crc32_le(__le16 vid_le)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	u32 crc = ~0;
90262306a36Sopenharmony_ci	u32 temp = 0;
90362306a36Sopenharmony_ci	unsigned char *data = (unsigned char *)&vid_le;
90462306a36Sopenharmony_ci	unsigned char data_byte = 0;
90562306a36Sopenharmony_ci	int i, bits;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	bits = get_bitmask_order(VLAN_VID_MASK);
90862306a36Sopenharmony_ci	for (i = 0; i < bits; i++) {
90962306a36Sopenharmony_ci		if ((i % 8) == 0)
91062306a36Sopenharmony_ci			data_byte = data[i / 8];
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci		temp = ((crc & 1) ^ data_byte) & 1;
91362306a36Sopenharmony_ci		crc >>= 1;
91462306a36Sopenharmony_ci		data_byte >>= 1;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci		if (temp)
91762306a36Sopenharmony_ci			crc ^= CRC32_POLY_LE;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	return crc;
92162306a36Sopenharmony_ci}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_cistatic int xgbe_update_vlan_hash_table(struct xgbe_prv_data *pdata)
92462306a36Sopenharmony_ci{
92562306a36Sopenharmony_ci	u32 crc;
92662306a36Sopenharmony_ci	u16 vid;
92762306a36Sopenharmony_ci	__le16 vid_le;
92862306a36Sopenharmony_ci	u16 vlan_hash_table = 0;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	/* Generate the VLAN Hash Table value */
93162306a36Sopenharmony_ci	for_each_set_bit(vid, pdata->active_vlans, VLAN_N_VID) {
93262306a36Sopenharmony_ci		/* Get the CRC32 value of the VLAN ID */
93362306a36Sopenharmony_ci		vid_le = cpu_to_le16(vid);
93462306a36Sopenharmony_ci		crc = bitrev32(~xgbe_vid_crc32_le(vid_le)) >> 28;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci		vlan_hash_table |= (1 << crc);
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/* Set the VLAN Hash Table filtering register */
94062306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANHTR, VLHT, vlan_hash_table);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	return 0;
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic int xgbe_set_promiscuous_mode(struct xgbe_prv_data *pdata,
94662306a36Sopenharmony_ci				     unsigned int enable)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	unsigned int val = enable ? 1 : 0;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	if (XGMAC_IOREAD_BITS(pdata, MAC_PFR, PR) == val)
95162306a36Sopenharmony_ci		return 0;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	netif_dbg(pdata, drv, pdata->netdev, "%s promiscuous mode\n",
95462306a36Sopenharmony_ci		  enable ? "entering" : "leaving");
95562306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_PFR, PR, val);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	/* Hardware will still perform VLAN filtering in promiscuous mode */
95862306a36Sopenharmony_ci	if (enable) {
95962306a36Sopenharmony_ci		xgbe_disable_rx_vlan_filtering(pdata);
96062306a36Sopenharmony_ci	} else {
96162306a36Sopenharmony_ci		if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
96262306a36Sopenharmony_ci			xgbe_enable_rx_vlan_filtering(pdata);
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	return 0;
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistatic int xgbe_set_all_multicast_mode(struct xgbe_prv_data *pdata,
96962306a36Sopenharmony_ci				       unsigned int enable)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	unsigned int val = enable ? 1 : 0;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	if (XGMAC_IOREAD_BITS(pdata, MAC_PFR, PM) == val)
97462306a36Sopenharmony_ci		return 0;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	netif_dbg(pdata, drv, pdata->netdev, "%s allmulti mode\n",
97762306a36Sopenharmony_ci		  enable ? "entering" : "leaving");
97862306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_PFR, PM, val);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	return 0;
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cistatic void xgbe_set_mac_reg(struct xgbe_prv_data *pdata,
98462306a36Sopenharmony_ci			     struct netdev_hw_addr *ha, unsigned int *mac_reg)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	unsigned int mac_addr_hi, mac_addr_lo;
98762306a36Sopenharmony_ci	u8 *mac_addr;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	mac_addr_lo = 0;
99062306a36Sopenharmony_ci	mac_addr_hi = 0;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (ha) {
99362306a36Sopenharmony_ci		mac_addr = (u8 *)&mac_addr_lo;
99462306a36Sopenharmony_ci		mac_addr[0] = ha->addr[0];
99562306a36Sopenharmony_ci		mac_addr[1] = ha->addr[1];
99662306a36Sopenharmony_ci		mac_addr[2] = ha->addr[2];
99762306a36Sopenharmony_ci		mac_addr[3] = ha->addr[3];
99862306a36Sopenharmony_ci		mac_addr = (u8 *)&mac_addr_hi;
99962306a36Sopenharmony_ci		mac_addr[0] = ha->addr[4];
100062306a36Sopenharmony_ci		mac_addr[1] = ha->addr[5];
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci		netif_dbg(pdata, drv, pdata->netdev,
100362306a36Sopenharmony_ci			  "adding mac address %pM at %#x\n",
100462306a36Sopenharmony_ci			  ha->addr, *mac_reg);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci		XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1);
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_hi);
101062306a36Sopenharmony_ci	*mac_reg += MAC_MACA_INC;
101162306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_lo);
101262306a36Sopenharmony_ci	*mac_reg += MAC_MACA_INC;
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic void xgbe_set_mac_addn_addrs(struct xgbe_prv_data *pdata)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	struct net_device *netdev = pdata->netdev;
101862306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
101962306a36Sopenharmony_ci	unsigned int mac_reg;
102062306a36Sopenharmony_ci	unsigned int addn_macs;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	mac_reg = MAC_MACA1HR;
102362306a36Sopenharmony_ci	addn_macs = pdata->hw_feat.addn_mac;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	if (netdev_uc_count(netdev) > addn_macs) {
102662306a36Sopenharmony_ci		xgbe_set_promiscuous_mode(pdata, 1);
102762306a36Sopenharmony_ci	} else {
102862306a36Sopenharmony_ci		netdev_for_each_uc_addr(ha, netdev) {
102962306a36Sopenharmony_ci			xgbe_set_mac_reg(pdata, ha, &mac_reg);
103062306a36Sopenharmony_ci			addn_macs--;
103162306a36Sopenharmony_ci		}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci		if (netdev_mc_count(netdev) > addn_macs) {
103462306a36Sopenharmony_ci			xgbe_set_all_multicast_mode(pdata, 1);
103562306a36Sopenharmony_ci		} else {
103662306a36Sopenharmony_ci			netdev_for_each_mc_addr(ha, netdev) {
103762306a36Sopenharmony_ci				xgbe_set_mac_reg(pdata, ha, &mac_reg);
103862306a36Sopenharmony_ci				addn_macs--;
103962306a36Sopenharmony_ci			}
104062306a36Sopenharmony_ci		}
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* Clear remaining additional MAC address entries */
104462306a36Sopenharmony_ci	while (addn_macs--)
104562306a36Sopenharmony_ci		xgbe_set_mac_reg(pdata, NULL, &mac_reg);
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic void xgbe_set_mac_hash_table(struct xgbe_prv_data *pdata)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	struct net_device *netdev = pdata->netdev;
105162306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
105262306a36Sopenharmony_ci	unsigned int hash_reg;
105362306a36Sopenharmony_ci	unsigned int hash_table_shift, hash_table_count;
105462306a36Sopenharmony_ci	u32 hash_table[XGBE_MAC_HASH_TABLE_SIZE];
105562306a36Sopenharmony_ci	u32 crc;
105662306a36Sopenharmony_ci	unsigned int i;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	hash_table_shift = 26 - (pdata->hw_feat.hash_table_size >> 7);
105962306a36Sopenharmony_ci	hash_table_count = pdata->hw_feat.hash_table_size / 32;
106062306a36Sopenharmony_ci	memset(hash_table, 0, sizeof(hash_table));
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* Build the MAC Hash Table register values */
106362306a36Sopenharmony_ci	netdev_for_each_uc_addr(ha, netdev) {
106462306a36Sopenharmony_ci		crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN));
106562306a36Sopenharmony_ci		crc >>= hash_table_shift;
106662306a36Sopenharmony_ci		hash_table[crc >> 5] |= (1 << (crc & 0x1f));
106762306a36Sopenharmony_ci	}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	netdev_for_each_mc_addr(ha, netdev) {
107062306a36Sopenharmony_ci		crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN));
107162306a36Sopenharmony_ci		crc >>= hash_table_shift;
107262306a36Sopenharmony_ci		hash_table[crc >> 5] |= (1 << (crc & 0x1f));
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/* Set the MAC Hash Table registers */
107662306a36Sopenharmony_ci	hash_reg = MAC_HTR0;
107762306a36Sopenharmony_ci	for (i = 0; i < hash_table_count; i++) {
107862306a36Sopenharmony_ci		XGMAC_IOWRITE(pdata, hash_reg, hash_table[i]);
107962306a36Sopenharmony_ci		hash_reg += MAC_HTR_INC;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic int xgbe_add_mac_addresses(struct xgbe_prv_data *pdata)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	if (pdata->hw_feat.hash_table_size)
108662306a36Sopenharmony_ci		xgbe_set_mac_hash_table(pdata);
108762306a36Sopenharmony_ci	else
108862306a36Sopenharmony_ci		xgbe_set_mac_addn_addrs(pdata);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	return 0;
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic int xgbe_set_mac_address(struct xgbe_prv_data *pdata, const u8 *addr)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	unsigned int mac_addr_hi, mac_addr_lo;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	mac_addr_hi = (addr[5] <<  8) | (addr[4] <<  0);
109862306a36Sopenharmony_ci	mac_addr_lo = (addr[3] << 24) | (addr[2] << 16) |
109962306a36Sopenharmony_ci		      (addr[1] <<  8) | (addr[0] <<  0);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_MACA0HR, mac_addr_hi);
110262306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_MACA0LR, mac_addr_lo);
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	return 0;
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic int xgbe_config_rx_mode(struct xgbe_prv_data *pdata)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	struct net_device *netdev = pdata->netdev;
111062306a36Sopenharmony_ci	unsigned int pr_mode, am_mode;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	pr_mode = ((netdev->flags & IFF_PROMISC) != 0);
111362306a36Sopenharmony_ci	am_mode = ((netdev->flags & IFF_ALLMULTI) != 0);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	xgbe_set_promiscuous_mode(pdata, pr_mode);
111662306a36Sopenharmony_ci	xgbe_set_all_multicast_mode(pdata, am_mode);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	xgbe_add_mac_addresses(pdata);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	return 0;
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_cistatic int xgbe_clr_gpio(struct xgbe_prv_data *pdata, unsigned int gpio)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	unsigned int reg;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	if (gpio > 15)
112862306a36Sopenharmony_ci		return -EINVAL;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	reg = XGMAC_IOREAD(pdata, MAC_GPIOSR);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	reg &= ~(1 << (gpio + 16));
113362306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_GPIOSR, reg);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	return 0;
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic int xgbe_set_gpio(struct xgbe_prv_data *pdata, unsigned int gpio)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	unsigned int reg;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	if (gpio > 15)
114362306a36Sopenharmony_ci		return -EINVAL;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	reg = XGMAC_IOREAD(pdata, MAC_GPIOSR);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	reg |= (1 << (gpio + 16));
114862306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_GPIOSR, reg);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	return 0;
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic int xgbe_read_mmd_regs_v2(struct xgbe_prv_data *pdata, int prtad,
115462306a36Sopenharmony_ci				 int mmd_reg)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	unsigned long flags;
115762306a36Sopenharmony_ci	unsigned int mmd_address, index, offset;
115862306a36Sopenharmony_ci	int mmd_data;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	if (mmd_reg & XGBE_ADDR_C45)
116162306a36Sopenharmony_ci		mmd_address = mmd_reg & ~XGBE_ADDR_C45;
116262306a36Sopenharmony_ci	else
116362306a36Sopenharmony_ci		mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/* The PCS registers are accessed using mmio. The underlying
116662306a36Sopenharmony_ci	 * management interface uses indirect addressing to access the MMD
116762306a36Sopenharmony_ci	 * register sets. This requires accessing of the PCS register in two
116862306a36Sopenharmony_ci	 * phases, an address phase and a data phase.
116962306a36Sopenharmony_ci	 *
117062306a36Sopenharmony_ci	 * The mmio interface is based on 16-bit offsets and values. All
117162306a36Sopenharmony_ci	 * register offsets must therefore be adjusted by left shifting the
117262306a36Sopenharmony_ci	 * offset 1 bit and reading 16 bits of data.
117362306a36Sopenharmony_ci	 */
117462306a36Sopenharmony_ci	mmd_address <<= 1;
117562306a36Sopenharmony_ci	index = mmd_address & ~pdata->xpcs_window_mask;
117662306a36Sopenharmony_ci	offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	spin_lock_irqsave(&pdata->xpcs_lock, flags);
117962306a36Sopenharmony_ci	XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index);
118062306a36Sopenharmony_ci	mmd_data = XPCS16_IOREAD(pdata, offset);
118162306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	return mmd_data;
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic void xgbe_write_mmd_regs_v2(struct xgbe_prv_data *pdata, int prtad,
118762306a36Sopenharmony_ci				   int mmd_reg, int mmd_data)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	unsigned long flags;
119062306a36Sopenharmony_ci	unsigned int mmd_address, index, offset;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	if (mmd_reg & XGBE_ADDR_C45)
119362306a36Sopenharmony_ci		mmd_address = mmd_reg & ~XGBE_ADDR_C45;
119462306a36Sopenharmony_ci	else
119562306a36Sopenharmony_ci		mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/* The PCS registers are accessed using mmio. The underlying
119862306a36Sopenharmony_ci	 * management interface uses indirect addressing to access the MMD
119962306a36Sopenharmony_ci	 * register sets. This requires accessing of the PCS register in two
120062306a36Sopenharmony_ci	 * phases, an address phase and a data phase.
120162306a36Sopenharmony_ci	 *
120262306a36Sopenharmony_ci	 * The mmio interface is based on 16-bit offsets and values. All
120362306a36Sopenharmony_ci	 * register offsets must therefore be adjusted by left shifting the
120462306a36Sopenharmony_ci	 * offset 1 bit and writing 16 bits of data.
120562306a36Sopenharmony_ci	 */
120662306a36Sopenharmony_ci	mmd_address <<= 1;
120762306a36Sopenharmony_ci	index = mmd_address & ~pdata->xpcs_window_mask;
120862306a36Sopenharmony_ci	offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	spin_lock_irqsave(&pdata->xpcs_lock, flags);
121162306a36Sopenharmony_ci	XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index);
121262306a36Sopenharmony_ci	XPCS16_IOWRITE(pdata, offset, mmd_data);
121362306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic int xgbe_read_mmd_regs_v1(struct xgbe_prv_data *pdata, int prtad,
121762306a36Sopenharmony_ci				 int mmd_reg)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	unsigned long flags;
122062306a36Sopenharmony_ci	unsigned int mmd_address;
122162306a36Sopenharmony_ci	int mmd_data;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	if (mmd_reg & XGBE_ADDR_C45)
122462306a36Sopenharmony_ci		mmd_address = mmd_reg & ~XGBE_ADDR_C45;
122562306a36Sopenharmony_ci	else
122662306a36Sopenharmony_ci		mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	/* The PCS registers are accessed using mmio. The underlying APB3
122962306a36Sopenharmony_ci	 * management interface uses indirect addressing to access the MMD
123062306a36Sopenharmony_ci	 * register sets. This requires accessing of the PCS register in two
123162306a36Sopenharmony_ci	 * phases, an address phase and a data phase.
123262306a36Sopenharmony_ci	 *
123362306a36Sopenharmony_ci	 * The mmio interface is based on 32-bit offsets and values. All
123462306a36Sopenharmony_ci	 * register offsets must therefore be adjusted by left shifting the
123562306a36Sopenharmony_ci	 * offset 2 bits and reading 32 bits of data.
123662306a36Sopenharmony_ci	 */
123762306a36Sopenharmony_ci	spin_lock_irqsave(&pdata->xpcs_lock, flags);
123862306a36Sopenharmony_ci	XPCS32_IOWRITE(pdata, PCS_V1_WINDOW_SELECT, mmd_address >> 8);
123962306a36Sopenharmony_ci	mmd_data = XPCS32_IOREAD(pdata, (mmd_address & 0xff) << 2);
124062306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	return mmd_data;
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_cistatic void xgbe_write_mmd_regs_v1(struct xgbe_prv_data *pdata, int prtad,
124662306a36Sopenharmony_ci				   int mmd_reg, int mmd_data)
124762306a36Sopenharmony_ci{
124862306a36Sopenharmony_ci	unsigned int mmd_address;
124962306a36Sopenharmony_ci	unsigned long flags;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	if (mmd_reg & XGBE_ADDR_C45)
125262306a36Sopenharmony_ci		mmd_address = mmd_reg & ~XGBE_ADDR_C45;
125362306a36Sopenharmony_ci	else
125462306a36Sopenharmony_ci		mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	/* The PCS registers are accessed using mmio. The underlying APB3
125762306a36Sopenharmony_ci	 * management interface uses indirect addressing to access the MMD
125862306a36Sopenharmony_ci	 * register sets. This requires accessing of the PCS register in two
125962306a36Sopenharmony_ci	 * phases, an address phase and a data phase.
126062306a36Sopenharmony_ci	 *
126162306a36Sopenharmony_ci	 * The mmio interface is based on 32-bit offsets and values. All
126262306a36Sopenharmony_ci	 * register offsets must therefore be adjusted by left shifting the
126362306a36Sopenharmony_ci	 * offset 2 bits and writing 32 bits of data.
126462306a36Sopenharmony_ci	 */
126562306a36Sopenharmony_ci	spin_lock_irqsave(&pdata->xpcs_lock, flags);
126662306a36Sopenharmony_ci	XPCS32_IOWRITE(pdata, PCS_V1_WINDOW_SELECT, mmd_address >> 8);
126762306a36Sopenharmony_ci	XPCS32_IOWRITE(pdata, (mmd_address & 0xff) << 2, mmd_data);
126862306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
126962306a36Sopenharmony_ci}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
127262306a36Sopenharmony_ci			      int mmd_reg)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	switch (pdata->vdata->xpcs_access) {
127562306a36Sopenharmony_ci	case XGBE_XPCS_ACCESS_V1:
127662306a36Sopenharmony_ci		return xgbe_read_mmd_regs_v1(pdata, prtad, mmd_reg);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	case XGBE_XPCS_ACCESS_V2:
127962306a36Sopenharmony_ci	default:
128062306a36Sopenharmony_ci		return xgbe_read_mmd_regs_v2(pdata, prtad, mmd_reg);
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
128562306a36Sopenharmony_ci				int mmd_reg, int mmd_data)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	switch (pdata->vdata->xpcs_access) {
128862306a36Sopenharmony_ci	case XGBE_XPCS_ACCESS_V1:
128962306a36Sopenharmony_ci		return xgbe_write_mmd_regs_v1(pdata, prtad, mmd_reg, mmd_data);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	case XGBE_XPCS_ACCESS_V2:
129262306a36Sopenharmony_ci	default:
129362306a36Sopenharmony_ci		return xgbe_write_mmd_regs_v2(pdata, prtad, mmd_reg, mmd_data);
129462306a36Sopenharmony_ci	}
129562306a36Sopenharmony_ci}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_cistatic unsigned int xgbe_create_mdio_sca_c22(int port, int reg)
129862306a36Sopenharmony_ci{
129962306a36Sopenharmony_ci	unsigned int mdio_sca;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	mdio_sca = 0;
130262306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, RA, reg);
130362306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, PA, port);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	return mdio_sca;
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic unsigned int xgbe_create_mdio_sca_c45(int port, unsigned int da, int reg)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	unsigned int mdio_sca;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	mdio_sca = 0;
131362306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, RA, reg);
131462306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, PA, port);
131562306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, da);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	return mdio_sca;
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_cistatic int xgbe_write_ext_mii_regs(struct xgbe_prv_data *pdata,
132162306a36Sopenharmony_ci				   unsigned int mdio_sca, u16 val)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	unsigned int mdio_sccd;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	reinit_completion(&pdata->mdio_complete);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	mdio_sccd = 0;
133062306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, DATA, val);
133162306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 1);
133262306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1);
133362306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&pdata->mdio_complete, HZ)) {
133662306a36Sopenharmony_ci		netdev_err(pdata->netdev, "mdio write operation timed out\n");
133762306a36Sopenharmony_ci		return -ETIMEDOUT;
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	return 0;
134162306a36Sopenharmony_ci}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_cistatic int xgbe_write_ext_mii_regs_c22(struct xgbe_prv_data *pdata, int addr,
134462306a36Sopenharmony_ci				       int reg, u16 val)
134562306a36Sopenharmony_ci{
134662306a36Sopenharmony_ci	unsigned int mdio_sca;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	mdio_sca = xgbe_create_mdio_sca_c22(addr, reg);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	return xgbe_write_ext_mii_regs(pdata, mdio_sca, val);
135162306a36Sopenharmony_ci}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_cistatic int xgbe_write_ext_mii_regs_c45(struct xgbe_prv_data *pdata, int addr,
135462306a36Sopenharmony_ci				       int devad, int reg, u16 val)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	unsigned int mdio_sca;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	mdio_sca = xgbe_create_mdio_sca_c45(addr, devad, reg);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	return xgbe_write_ext_mii_regs(pdata, mdio_sca, val);
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_cistatic int xgbe_read_ext_mii_regs(struct xgbe_prv_data *pdata,
136462306a36Sopenharmony_ci				  unsigned int mdio_sca)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	unsigned int mdio_sccd;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	reinit_completion(&pdata->mdio_complete);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	mdio_sccd = 0;
137362306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 3);
137462306a36Sopenharmony_ci	XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1);
137562306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&pdata->mdio_complete, HZ)) {
137862306a36Sopenharmony_ci		netdev_err(pdata->netdev, "mdio read operation timed out\n");
137962306a36Sopenharmony_ci		return -ETIMEDOUT;
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	return XGMAC_IOREAD_BITS(pdata, MAC_MDIOSCCDR, DATA);
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_cistatic int xgbe_read_ext_mii_regs_c22(struct xgbe_prv_data *pdata, int addr,
138662306a36Sopenharmony_ci				      int reg)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	unsigned int mdio_sca;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	mdio_sca = xgbe_create_mdio_sca_c22(addr, reg);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	return xgbe_read_ext_mii_regs(pdata, mdio_sca);
139362306a36Sopenharmony_ci}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_cistatic int xgbe_read_ext_mii_regs_c45(struct xgbe_prv_data *pdata, int addr,
139662306a36Sopenharmony_ci				      int devad, int reg)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	unsigned int mdio_sca;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	mdio_sca = xgbe_create_mdio_sca_c45(addr, devad, reg);
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	return xgbe_read_ext_mii_regs(pdata, mdio_sca);
140362306a36Sopenharmony_ci}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_cistatic int xgbe_set_ext_mii_mode(struct xgbe_prv_data *pdata, unsigned int port,
140662306a36Sopenharmony_ci				 enum xgbe_mdio_mode mode)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	unsigned int reg_val = XGMAC_IOREAD(pdata, MAC_MDIOCL22R);
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	switch (mode) {
141162306a36Sopenharmony_ci	case XGBE_MDIO_MODE_CL22:
141262306a36Sopenharmony_ci		if (port > XGMAC_MAX_C22_PORT)
141362306a36Sopenharmony_ci			return -EINVAL;
141462306a36Sopenharmony_ci		reg_val |= (1 << port);
141562306a36Sopenharmony_ci		break;
141662306a36Sopenharmony_ci	case XGBE_MDIO_MODE_CL45:
141762306a36Sopenharmony_ci		break;
141862306a36Sopenharmony_ci	default:
141962306a36Sopenharmony_ci		return -EINVAL;
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_MDIOCL22R, reg_val);
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	return 0;
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cistatic int xgbe_tx_complete(struct xgbe_ring_desc *rdesc)
142862306a36Sopenharmony_ci{
142962306a36Sopenharmony_ci	return !XGMAC_GET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN);
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_cistatic int xgbe_disable_rx_csum(struct xgbe_prv_data *pdata)
143362306a36Sopenharmony_ci{
143462306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, IPC, 0);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	return 0;
143762306a36Sopenharmony_ci}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_cistatic int xgbe_enable_rx_csum(struct xgbe_prv_data *pdata)
144062306a36Sopenharmony_ci{
144162306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, IPC, 1);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	return 0;
144462306a36Sopenharmony_ci}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_cistatic void xgbe_tx_desc_reset(struct xgbe_ring_data *rdata)
144762306a36Sopenharmony_ci{
144862306a36Sopenharmony_ci	struct xgbe_ring_desc *rdesc = rdata->rdesc;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	/* Reset the Tx descriptor
145162306a36Sopenharmony_ci	 *   Set buffer 1 (lo) address to zero
145262306a36Sopenharmony_ci	 *   Set buffer 1 (hi) address to zero
145362306a36Sopenharmony_ci	 *   Reset all other control bits (IC, TTSE, B2L & B1L)
145462306a36Sopenharmony_ci	 *   Reset all other control bits (OWN, CTXT, FD, LD, CPC, CIC, etc)
145562306a36Sopenharmony_ci	 */
145662306a36Sopenharmony_ci	rdesc->desc0 = 0;
145762306a36Sopenharmony_ci	rdesc->desc1 = 0;
145862306a36Sopenharmony_ci	rdesc->desc2 = 0;
145962306a36Sopenharmony_ci	rdesc->desc3 = 0;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	/* Make sure ownership is written to the descriptor */
146262306a36Sopenharmony_ci	dma_wmb();
146362306a36Sopenharmony_ci}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_cistatic void xgbe_tx_desc_init(struct xgbe_channel *channel)
146662306a36Sopenharmony_ci{
146762306a36Sopenharmony_ci	struct xgbe_ring *ring = channel->tx_ring;
146862306a36Sopenharmony_ci	struct xgbe_ring_data *rdata;
146962306a36Sopenharmony_ci	int i;
147062306a36Sopenharmony_ci	int start_index = ring->cur;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	DBGPR("-->tx_desc_init\n");
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	/* Initialze all descriptors */
147562306a36Sopenharmony_ci	for (i = 0; i < ring->rdesc_count; i++) {
147662306a36Sopenharmony_ci		rdata = XGBE_GET_DESC_DATA(ring, i);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci		/* Initialize Tx descriptor */
147962306a36Sopenharmony_ci		xgbe_tx_desc_reset(rdata);
148062306a36Sopenharmony_ci	}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	/* Update the total number of Tx descriptors */
148362306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_TDRLR, ring->rdesc_count - 1);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	/* Update the starting address of descriptor ring */
148662306a36Sopenharmony_ci	rdata = XGBE_GET_DESC_DATA(ring, start_index);
148762306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_TDLR_HI,
148862306a36Sopenharmony_ci			  upper_32_bits(rdata->rdesc_dma));
148962306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_TDLR_LO,
149062306a36Sopenharmony_ci			  lower_32_bits(rdata->rdesc_dma));
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	DBGPR("<--tx_desc_init\n");
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_cistatic void xgbe_rx_desc_reset(struct xgbe_prv_data *pdata,
149662306a36Sopenharmony_ci			       struct xgbe_ring_data *rdata, unsigned int index)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	struct xgbe_ring_desc *rdesc = rdata->rdesc;
149962306a36Sopenharmony_ci	unsigned int rx_usecs = pdata->rx_usecs;
150062306a36Sopenharmony_ci	unsigned int rx_frames = pdata->rx_frames;
150162306a36Sopenharmony_ci	unsigned int inte;
150262306a36Sopenharmony_ci	dma_addr_t hdr_dma, buf_dma;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	if (!rx_usecs && !rx_frames) {
150562306a36Sopenharmony_ci		/* No coalescing, interrupt for every descriptor */
150662306a36Sopenharmony_ci		inte = 1;
150762306a36Sopenharmony_ci	} else {
150862306a36Sopenharmony_ci		/* Set interrupt based on Rx frame coalescing setting */
150962306a36Sopenharmony_ci		if (rx_frames && !((index + 1) % rx_frames))
151062306a36Sopenharmony_ci			inte = 1;
151162306a36Sopenharmony_ci		else
151262306a36Sopenharmony_ci			inte = 0;
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	/* Reset the Rx descriptor
151662306a36Sopenharmony_ci	 *   Set buffer 1 (lo) address to header dma address (lo)
151762306a36Sopenharmony_ci	 *   Set buffer 1 (hi) address to header dma address (hi)
151862306a36Sopenharmony_ci	 *   Set buffer 2 (lo) address to buffer dma address (lo)
151962306a36Sopenharmony_ci	 *   Set buffer 2 (hi) address to buffer dma address (hi) and
152062306a36Sopenharmony_ci	 *     set control bits OWN and INTE
152162306a36Sopenharmony_ci	 */
152262306a36Sopenharmony_ci	hdr_dma = rdata->rx.hdr.dma_base + rdata->rx.hdr.dma_off;
152362306a36Sopenharmony_ci	buf_dma = rdata->rx.buf.dma_base + rdata->rx.buf.dma_off;
152462306a36Sopenharmony_ci	rdesc->desc0 = cpu_to_le32(lower_32_bits(hdr_dma));
152562306a36Sopenharmony_ci	rdesc->desc1 = cpu_to_le32(upper_32_bits(hdr_dma));
152662306a36Sopenharmony_ci	rdesc->desc2 = cpu_to_le32(lower_32_bits(buf_dma));
152762306a36Sopenharmony_ci	rdesc->desc3 = cpu_to_le32(upper_32_bits(buf_dma));
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, inte);
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	/* Since the Rx DMA engine is likely running, make sure everything
153262306a36Sopenharmony_ci	 * is written to the descriptor(s) before setting the OWN bit
153362306a36Sopenharmony_ci	 * for the descriptor
153462306a36Sopenharmony_ci	 */
153562306a36Sopenharmony_ci	dma_wmb();
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN, 1);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	/* Make sure ownership is written to the descriptor */
154062306a36Sopenharmony_ci	dma_wmb();
154162306a36Sopenharmony_ci}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_cistatic void xgbe_rx_desc_init(struct xgbe_channel *channel)
154462306a36Sopenharmony_ci{
154562306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = channel->pdata;
154662306a36Sopenharmony_ci	struct xgbe_ring *ring = channel->rx_ring;
154762306a36Sopenharmony_ci	struct xgbe_ring_data *rdata;
154862306a36Sopenharmony_ci	unsigned int start_index = ring->cur;
154962306a36Sopenharmony_ci	unsigned int i;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	DBGPR("-->rx_desc_init\n");
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	/* Initialize all descriptors */
155462306a36Sopenharmony_ci	for (i = 0; i < ring->rdesc_count; i++) {
155562306a36Sopenharmony_ci		rdata = XGBE_GET_DESC_DATA(ring, i);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci		/* Initialize Rx descriptor */
155862306a36Sopenharmony_ci		xgbe_rx_desc_reset(pdata, rdata, i);
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	/* Update the total number of Rx descriptors */
156262306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_RDRLR, ring->rdesc_count - 1);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	/* Update the starting address of descriptor ring */
156562306a36Sopenharmony_ci	rdata = XGBE_GET_DESC_DATA(ring, start_index);
156662306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_RDLR_HI,
156762306a36Sopenharmony_ci			  upper_32_bits(rdata->rdesc_dma));
156862306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_RDLR_LO,
156962306a36Sopenharmony_ci			  lower_32_bits(rdata->rdesc_dma));
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	/* Update the Rx Descriptor Tail Pointer */
157262306a36Sopenharmony_ci	rdata = XGBE_GET_DESC_DATA(ring, start_index + ring->rdesc_count - 1);
157362306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO,
157462306a36Sopenharmony_ci			  lower_32_bits(rdata->rdesc_dma));
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	DBGPR("<--rx_desc_init\n");
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic void xgbe_update_tstamp_addend(struct xgbe_prv_data *pdata,
158062306a36Sopenharmony_ci				      unsigned int addend)
158162306a36Sopenharmony_ci{
158262306a36Sopenharmony_ci	unsigned int count = 10000;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	/* Set the addend register value and tell the device */
158562306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_TSAR, addend);
158662306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSADDREG, 1);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	/* Wait for addend update to complete */
158962306a36Sopenharmony_ci	while (--count && XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSADDREG))
159062306a36Sopenharmony_ci		udelay(5);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	if (!count)
159362306a36Sopenharmony_ci		netdev_err(pdata->netdev,
159462306a36Sopenharmony_ci			   "timed out updating timestamp addend register\n");
159562306a36Sopenharmony_ci}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_cistatic void xgbe_set_tstamp_time(struct xgbe_prv_data *pdata, unsigned int sec,
159862306a36Sopenharmony_ci				 unsigned int nsec)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	unsigned int count = 10000;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	/* Set the time values and tell the device */
160362306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_STSUR, sec);
160462306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_STNUR, nsec);
160562306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSINIT, 1);
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	/* Wait for time update to complete */
160862306a36Sopenharmony_ci	while (--count && XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSINIT))
160962306a36Sopenharmony_ci		udelay(5);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	if (!count)
161262306a36Sopenharmony_ci		netdev_err(pdata->netdev, "timed out initializing timestamp\n");
161362306a36Sopenharmony_ci}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_cistatic u64 xgbe_get_tstamp_time(struct xgbe_prv_data *pdata)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	u64 nsec;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	nsec = XGMAC_IOREAD(pdata, MAC_STSR);
162062306a36Sopenharmony_ci	nsec *= NSEC_PER_SEC;
162162306a36Sopenharmony_ci	nsec += XGMAC_IOREAD(pdata, MAC_STNR);
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	return nsec;
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_cistatic u64 xgbe_get_tx_tstamp(struct xgbe_prv_data *pdata)
162762306a36Sopenharmony_ci{
162862306a36Sopenharmony_ci	unsigned int tx_snr, tx_ssr;
162962306a36Sopenharmony_ci	u64 nsec;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	if (pdata->vdata->tx_tstamp_workaround) {
163262306a36Sopenharmony_ci		tx_snr = XGMAC_IOREAD(pdata, MAC_TXSNR);
163362306a36Sopenharmony_ci		tx_ssr = XGMAC_IOREAD(pdata, MAC_TXSSR);
163462306a36Sopenharmony_ci	} else {
163562306a36Sopenharmony_ci		tx_ssr = XGMAC_IOREAD(pdata, MAC_TXSSR);
163662306a36Sopenharmony_ci		tx_snr = XGMAC_IOREAD(pdata, MAC_TXSNR);
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (XGMAC_GET_BITS(tx_snr, MAC_TXSNR, TXTSSTSMIS))
164062306a36Sopenharmony_ci		return 0;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	nsec = tx_ssr;
164362306a36Sopenharmony_ci	nsec *= NSEC_PER_SEC;
164462306a36Sopenharmony_ci	nsec += tx_snr;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	return nsec;
164762306a36Sopenharmony_ci}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_cistatic void xgbe_get_rx_tstamp(struct xgbe_packet_data *packet,
165062306a36Sopenharmony_ci			       struct xgbe_ring_desc *rdesc)
165162306a36Sopenharmony_ci{
165262306a36Sopenharmony_ci	u64 nsec;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSA) &&
165562306a36Sopenharmony_ci	    !XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSD)) {
165662306a36Sopenharmony_ci		nsec = le32_to_cpu(rdesc->desc1);
165762306a36Sopenharmony_ci		nsec <<= 32;
165862306a36Sopenharmony_ci		nsec |= le32_to_cpu(rdesc->desc0);
165962306a36Sopenharmony_ci		if (nsec != 0xffffffffffffffffULL) {
166062306a36Sopenharmony_ci			packet->rx_tstamp = nsec;
166162306a36Sopenharmony_ci			XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
166262306a36Sopenharmony_ci				       RX_TSTAMP, 1);
166362306a36Sopenharmony_ci		}
166462306a36Sopenharmony_ci	}
166562306a36Sopenharmony_ci}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_cistatic int xgbe_config_tstamp(struct xgbe_prv_data *pdata,
166862306a36Sopenharmony_ci			      unsigned int mac_tscr)
166962306a36Sopenharmony_ci{
167062306a36Sopenharmony_ci	/* Set one nano-second accuracy */
167162306a36Sopenharmony_ci	XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCTRLSSR, 1);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	/* Set fine timestamp update */
167462306a36Sopenharmony_ci	XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCFUPDT, 1);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	/* Overwrite earlier timestamps */
167762306a36Sopenharmony_ci	XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TXTSSTSM, 1);
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_TSCR, mac_tscr);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	/* Exit if timestamping is not enabled */
168262306a36Sopenharmony_ci	if (!XGMAC_GET_BITS(mac_tscr, MAC_TSCR, TSENA))
168362306a36Sopenharmony_ci		return 0;
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	/* Initialize time registers */
168662306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, XGBE_TSTAMP_SSINC);
168762306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, XGBE_TSTAMP_SNSINC);
168862306a36Sopenharmony_ci	xgbe_update_tstamp_addend(pdata, pdata->tstamp_addend);
168962306a36Sopenharmony_ci	xgbe_set_tstamp_time(pdata, 0, 0);
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	/* Initialize the timecounter */
169262306a36Sopenharmony_ci	timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc,
169362306a36Sopenharmony_ci			 ktime_to_ns(ktime_get_real()));
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	return 0;
169662306a36Sopenharmony_ci}
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_cistatic void xgbe_tx_start_xmit(struct xgbe_channel *channel,
169962306a36Sopenharmony_ci			       struct xgbe_ring *ring)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = channel->pdata;
170262306a36Sopenharmony_ci	struct xgbe_ring_data *rdata;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	/* Make sure everything is written before the register write */
170562306a36Sopenharmony_ci	wmb();
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	/* Issue a poll command to Tx DMA by writing address
170862306a36Sopenharmony_ci	 * of next immediate free descriptor */
170962306a36Sopenharmony_ci	rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
171062306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_TDTR_LO,
171162306a36Sopenharmony_ci			  lower_32_bits(rdata->rdesc_dma));
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	/* Start the Tx timer */
171462306a36Sopenharmony_ci	if (pdata->tx_usecs && !channel->tx_timer_active) {
171562306a36Sopenharmony_ci		channel->tx_timer_active = 1;
171662306a36Sopenharmony_ci		mod_timer(&channel->tx_timer,
171762306a36Sopenharmony_ci			  jiffies + usecs_to_jiffies(pdata->tx_usecs));
171862306a36Sopenharmony_ci	}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	ring->tx.xmit_more = 0;
172162306a36Sopenharmony_ci}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_cistatic void xgbe_dev_xmit(struct xgbe_channel *channel)
172462306a36Sopenharmony_ci{
172562306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = channel->pdata;
172662306a36Sopenharmony_ci	struct xgbe_ring *ring = channel->tx_ring;
172762306a36Sopenharmony_ci	struct xgbe_ring_data *rdata;
172862306a36Sopenharmony_ci	struct xgbe_ring_desc *rdesc;
172962306a36Sopenharmony_ci	struct xgbe_packet_data *packet = &ring->packet_data;
173062306a36Sopenharmony_ci	unsigned int tx_packets, tx_bytes;
173162306a36Sopenharmony_ci	unsigned int csum, tso, vlan, vxlan;
173262306a36Sopenharmony_ci	unsigned int tso_context, vlan_context;
173362306a36Sopenharmony_ci	unsigned int tx_set_ic;
173462306a36Sopenharmony_ci	int start_index = ring->cur;
173562306a36Sopenharmony_ci	int cur_index = ring->cur;
173662306a36Sopenharmony_ci	int i;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	DBGPR("-->xgbe_dev_xmit\n");
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	tx_packets = packet->tx_packets;
174162306a36Sopenharmony_ci	tx_bytes = packet->tx_bytes;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	csum = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
174462306a36Sopenharmony_ci			      CSUM_ENABLE);
174562306a36Sopenharmony_ci	tso = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
174662306a36Sopenharmony_ci			     TSO_ENABLE);
174762306a36Sopenharmony_ci	vlan = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
174862306a36Sopenharmony_ci			      VLAN_CTAG);
174962306a36Sopenharmony_ci	vxlan = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
175062306a36Sopenharmony_ci			       VXLAN);
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	if (tso && (packet->mss != ring->tx.cur_mss))
175362306a36Sopenharmony_ci		tso_context = 1;
175462306a36Sopenharmony_ci	else
175562306a36Sopenharmony_ci		tso_context = 0;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	if (vlan && (packet->vlan_ctag != ring->tx.cur_vlan_ctag))
175862306a36Sopenharmony_ci		vlan_context = 1;
175962306a36Sopenharmony_ci	else
176062306a36Sopenharmony_ci		vlan_context = 0;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	/* Determine if an interrupt should be generated for this Tx:
176362306a36Sopenharmony_ci	 *   Interrupt:
176462306a36Sopenharmony_ci	 *     - Tx frame count exceeds the frame count setting
176562306a36Sopenharmony_ci	 *     - Addition of Tx frame count to the frame count since the
176662306a36Sopenharmony_ci	 *       last interrupt was set exceeds the frame count setting
176762306a36Sopenharmony_ci	 *   No interrupt:
176862306a36Sopenharmony_ci	 *     - No frame count setting specified (ethtool -C ethX tx-frames 0)
176962306a36Sopenharmony_ci	 *     - Addition of Tx frame count to the frame count since the
177062306a36Sopenharmony_ci	 *       last interrupt was set does not exceed the frame count setting
177162306a36Sopenharmony_ci	 */
177262306a36Sopenharmony_ci	ring->coalesce_count += tx_packets;
177362306a36Sopenharmony_ci	if (!pdata->tx_frames)
177462306a36Sopenharmony_ci		tx_set_ic = 0;
177562306a36Sopenharmony_ci	else if (tx_packets > pdata->tx_frames)
177662306a36Sopenharmony_ci		tx_set_ic = 1;
177762306a36Sopenharmony_ci	else if ((ring->coalesce_count % pdata->tx_frames) < tx_packets)
177862306a36Sopenharmony_ci		tx_set_ic = 1;
177962306a36Sopenharmony_ci	else
178062306a36Sopenharmony_ci		tx_set_ic = 0;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	rdata = XGBE_GET_DESC_DATA(ring, cur_index);
178362306a36Sopenharmony_ci	rdesc = rdata->rdesc;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	/* Create a context descriptor if this is a TSO packet */
178662306a36Sopenharmony_ci	if (tso_context || vlan_context) {
178762306a36Sopenharmony_ci		if (tso_context) {
178862306a36Sopenharmony_ci			netif_dbg(pdata, tx_queued, pdata->netdev,
178962306a36Sopenharmony_ci				  "TSO context descriptor, mss=%u\n",
179062306a36Sopenharmony_ci				  packet->mss);
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci			/* Set the MSS size */
179362306a36Sopenharmony_ci			XGMAC_SET_BITS_LE(rdesc->desc2, TX_CONTEXT_DESC2,
179462306a36Sopenharmony_ci					  MSS, packet->mss);
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci			/* Mark it as a CONTEXT descriptor */
179762306a36Sopenharmony_ci			XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3,
179862306a36Sopenharmony_ci					  CTXT, 1);
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci			/* Indicate this descriptor contains the MSS */
180162306a36Sopenharmony_ci			XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3,
180262306a36Sopenharmony_ci					  TCMSSV, 1);
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci			ring->tx.cur_mss = packet->mss;
180562306a36Sopenharmony_ci		}
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci		if (vlan_context) {
180862306a36Sopenharmony_ci			netif_dbg(pdata, tx_queued, pdata->netdev,
180962306a36Sopenharmony_ci				  "VLAN context descriptor, ctag=%u\n",
181062306a36Sopenharmony_ci				  packet->vlan_ctag);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci			/* Mark it as a CONTEXT descriptor */
181362306a36Sopenharmony_ci			XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3,
181462306a36Sopenharmony_ci					  CTXT, 1);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci			/* Set the VLAN tag */
181762306a36Sopenharmony_ci			XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3,
181862306a36Sopenharmony_ci					  VT, packet->vlan_ctag);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci			/* Indicate this descriptor contains the VLAN tag */
182162306a36Sopenharmony_ci			XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3,
182262306a36Sopenharmony_ci					  VLTV, 1);
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci			ring->tx.cur_vlan_ctag = packet->vlan_ctag;
182562306a36Sopenharmony_ci		}
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci		cur_index++;
182862306a36Sopenharmony_ci		rdata = XGBE_GET_DESC_DATA(ring, cur_index);
182962306a36Sopenharmony_ci		rdesc = rdata->rdesc;
183062306a36Sopenharmony_ci	}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	/* Update buffer address (for TSO this is the header) */
183362306a36Sopenharmony_ci	rdesc->desc0 =  cpu_to_le32(lower_32_bits(rdata->skb_dma));
183462306a36Sopenharmony_ci	rdesc->desc1 =  cpu_to_le32(upper_32_bits(rdata->skb_dma));
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	/* Update the buffer length */
183762306a36Sopenharmony_ci	XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, HL_B1L,
183862306a36Sopenharmony_ci			  rdata->skb_dma_len);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	/* VLAN tag insertion check */
184162306a36Sopenharmony_ci	if (vlan)
184262306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, VTIR,
184362306a36Sopenharmony_ci				  TX_NORMAL_DESC2_VLAN_INSERT);
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	/* Timestamp enablement check */
184662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP))
184762306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, TTSE, 1);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	/* Mark it as First Descriptor */
185062306a36Sopenharmony_ci	XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, FD, 1);
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	/* Mark it as a NORMAL descriptor */
185362306a36Sopenharmony_ci	XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT, 0);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	/* Set OWN bit if not the first descriptor */
185662306a36Sopenharmony_ci	if (cur_index != start_index)
185762306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1);
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	if (tso) {
186062306a36Sopenharmony_ci		/* Enable TSO */
186162306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, TSE, 1);
186262306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, TCPPL,
186362306a36Sopenharmony_ci				  packet->tcp_payload_len);
186462306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, TCPHDRLEN,
186562306a36Sopenharmony_ci				  packet->tcp_header_len / 4);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci		pdata->ext_stats.tx_tso_packets += tx_packets;
186862306a36Sopenharmony_ci	} else {
186962306a36Sopenharmony_ci		/* Enable CRC and Pad Insertion */
187062306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CPC, 0);
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci		/* Enable HW CSUM */
187362306a36Sopenharmony_ci		if (csum)
187462306a36Sopenharmony_ci			XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3,
187562306a36Sopenharmony_ci					  CIC, 0x3);
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci		/* Set the total length to be transmitted */
187862306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, FL,
187962306a36Sopenharmony_ci				  packet->length);
188062306a36Sopenharmony_ci	}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	if (vxlan) {
188362306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, VNP,
188462306a36Sopenharmony_ci				  TX_NORMAL_DESC3_VXLAN_PACKET);
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci		pdata->ext_stats.tx_vxlan_packets += packet->tx_packets;
188762306a36Sopenharmony_ci	}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	for (i = cur_index - start_index + 1; i < packet->rdesc_count; i++) {
189062306a36Sopenharmony_ci		cur_index++;
189162306a36Sopenharmony_ci		rdata = XGBE_GET_DESC_DATA(ring, cur_index);
189262306a36Sopenharmony_ci		rdesc = rdata->rdesc;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci		/* Update buffer address */
189562306a36Sopenharmony_ci		rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->skb_dma));
189662306a36Sopenharmony_ci		rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->skb_dma));
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci		/* Update the buffer length */
189962306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, HL_B1L,
190062306a36Sopenharmony_ci				  rdata->skb_dma_len);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci		/* Set OWN bit */
190362306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci		/* Mark it as NORMAL descriptor */
190662306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT, 0);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci		/* Enable HW CSUM */
190962306a36Sopenharmony_ci		if (csum)
191062306a36Sopenharmony_ci			XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3,
191162306a36Sopenharmony_ci					  CIC, 0x3);
191262306a36Sopenharmony_ci	}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	/* Set LAST bit for the last descriptor */
191562306a36Sopenharmony_ci	XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, LD, 1);
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	/* Set IC bit based on Tx coalescing settings */
191862306a36Sopenharmony_ci	if (tx_set_ic)
191962306a36Sopenharmony_ci		XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	/* Save the Tx info to report back during cleanup */
192262306a36Sopenharmony_ci	rdata->tx.packets = tx_packets;
192362306a36Sopenharmony_ci	rdata->tx.bytes = tx_bytes;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	pdata->ext_stats.txq_packets[channel->queue_index] += tx_packets;
192662306a36Sopenharmony_ci	pdata->ext_stats.txq_bytes[channel->queue_index] += tx_bytes;
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	/* In case the Tx DMA engine is running, make sure everything
192962306a36Sopenharmony_ci	 * is written to the descriptor(s) before setting the OWN bit
193062306a36Sopenharmony_ci	 * for the first descriptor
193162306a36Sopenharmony_ci	 */
193262306a36Sopenharmony_ci	dma_wmb();
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	/* Set OWN bit for the first descriptor */
193562306a36Sopenharmony_ci	rdata = XGBE_GET_DESC_DATA(ring, start_index);
193662306a36Sopenharmony_ci	rdesc = rdata->rdesc;
193762306a36Sopenharmony_ci	XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	if (netif_msg_tx_queued(pdata))
194062306a36Sopenharmony_ci		xgbe_dump_tx_desc(pdata, ring, start_index,
194162306a36Sopenharmony_ci				  packet->rdesc_count, 1);
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	/* Make sure ownership is written to the descriptor */
194462306a36Sopenharmony_ci	smp_wmb();
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	ring->cur = cur_index + 1;
194762306a36Sopenharmony_ci	if (!netdev_xmit_more() ||
194862306a36Sopenharmony_ci	    netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev,
194962306a36Sopenharmony_ci						   channel->queue_index)))
195062306a36Sopenharmony_ci		xgbe_tx_start_xmit(channel, ring);
195162306a36Sopenharmony_ci	else
195262306a36Sopenharmony_ci		ring->tx.xmit_more = 1;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	DBGPR("  %s: descriptors %u to %u written\n",
195562306a36Sopenharmony_ci	      channel->name, start_index & (ring->rdesc_count - 1),
195662306a36Sopenharmony_ci	      (ring->cur - 1) & (ring->rdesc_count - 1));
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	DBGPR("<--xgbe_dev_xmit\n");
195962306a36Sopenharmony_ci}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_cistatic int xgbe_dev_read(struct xgbe_channel *channel)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = channel->pdata;
196462306a36Sopenharmony_ci	struct xgbe_ring *ring = channel->rx_ring;
196562306a36Sopenharmony_ci	struct xgbe_ring_data *rdata;
196662306a36Sopenharmony_ci	struct xgbe_ring_desc *rdesc;
196762306a36Sopenharmony_ci	struct xgbe_packet_data *packet = &ring->packet_data;
196862306a36Sopenharmony_ci	struct net_device *netdev = pdata->netdev;
196962306a36Sopenharmony_ci	unsigned int err, etlt, l34t;
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	DBGPR("-->xgbe_dev_read: cur = %d\n", ring->cur);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
197462306a36Sopenharmony_ci	rdesc = rdata->rdesc;
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	/* Check for data availability */
197762306a36Sopenharmony_ci	if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN))
197862306a36Sopenharmony_ci		return 1;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	/* Make sure descriptor fields are read after reading the OWN bit */
198162306a36Sopenharmony_ci	dma_rmb();
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	if (netif_msg_rx_status(pdata))
198462306a36Sopenharmony_ci		xgbe_dump_rx_desc(pdata, ring, ring->cur);
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CTXT)) {
198762306a36Sopenharmony_ci		/* Timestamp Context Descriptor */
198862306a36Sopenharmony_ci		xgbe_get_rx_tstamp(packet, rdesc);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
199162306a36Sopenharmony_ci			       CONTEXT, 1);
199262306a36Sopenharmony_ci		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
199362306a36Sopenharmony_ci			       CONTEXT_NEXT, 0);
199462306a36Sopenharmony_ci		return 0;
199562306a36Sopenharmony_ci	}
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	/* Normal Descriptor, be sure Context Descriptor bit is off */
199862306a36Sopenharmony_ci	XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, CONTEXT, 0);
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	/* Indicate if a Context Descriptor is next */
200162306a36Sopenharmony_ci	if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CDA))
200262306a36Sopenharmony_ci		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
200362306a36Sopenharmony_ci			       CONTEXT_NEXT, 1);
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	/* Get the header length */
200662306a36Sopenharmony_ci	if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, FD)) {
200762306a36Sopenharmony_ci		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
200862306a36Sopenharmony_ci			       FIRST, 1);
200962306a36Sopenharmony_ci		rdata->rx.hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
201062306a36Sopenharmony_ci						      RX_NORMAL_DESC2, HL);
201162306a36Sopenharmony_ci		if (rdata->rx.hdr_len)
201262306a36Sopenharmony_ci			pdata->ext_stats.rx_split_header_packets++;
201362306a36Sopenharmony_ci	} else {
201462306a36Sopenharmony_ci		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
201562306a36Sopenharmony_ci			       FIRST, 0);
201662306a36Sopenharmony_ci	}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	/* Get the RSS hash */
201962306a36Sopenharmony_ci	if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, RSV)) {
202062306a36Sopenharmony_ci		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
202162306a36Sopenharmony_ci			       RSS_HASH, 1);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci		packet->rss_hash = le32_to_cpu(rdesc->desc1);
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci		l34t = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, L34T);
202662306a36Sopenharmony_ci		switch (l34t) {
202762306a36Sopenharmony_ci		case RX_DESC3_L34T_IPV4_TCP:
202862306a36Sopenharmony_ci		case RX_DESC3_L34T_IPV4_UDP:
202962306a36Sopenharmony_ci		case RX_DESC3_L34T_IPV6_TCP:
203062306a36Sopenharmony_ci		case RX_DESC3_L34T_IPV6_UDP:
203162306a36Sopenharmony_ci			packet->rss_hash_type = PKT_HASH_TYPE_L4;
203262306a36Sopenharmony_ci			break;
203362306a36Sopenharmony_ci		default:
203462306a36Sopenharmony_ci			packet->rss_hash_type = PKT_HASH_TYPE_L3;
203562306a36Sopenharmony_ci		}
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	/* Not all the data has been transferred for this packet */
203962306a36Sopenharmony_ci	if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD))
204062306a36Sopenharmony_ci		return 0;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	/* This is the last of the data for this packet */
204362306a36Sopenharmony_ci	XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
204462306a36Sopenharmony_ci		       LAST, 1);
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	/* Get the packet length */
204762306a36Sopenharmony_ci	rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	/* Set checksum done indicator as appropriate */
205062306a36Sopenharmony_ci	if (netdev->features & NETIF_F_RXCSUM) {
205162306a36Sopenharmony_ci		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
205262306a36Sopenharmony_ci			       CSUM_DONE, 1);
205362306a36Sopenharmony_ci		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
205462306a36Sopenharmony_ci			       TNPCSUM_DONE, 1);
205562306a36Sopenharmony_ci	}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/* Set the tunneled packet indicator */
205862306a36Sopenharmony_ci	if (XGMAC_GET_BITS_LE(rdesc->desc2, RX_NORMAL_DESC2, TNP)) {
205962306a36Sopenharmony_ci		XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
206062306a36Sopenharmony_ci			       TNP, 1);
206162306a36Sopenharmony_ci		pdata->ext_stats.rx_vxlan_packets++;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci		l34t = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, L34T);
206462306a36Sopenharmony_ci		switch (l34t) {
206562306a36Sopenharmony_ci		case RX_DESC3_L34T_IPV4_UNKNOWN:
206662306a36Sopenharmony_ci		case RX_DESC3_L34T_IPV6_UNKNOWN:
206762306a36Sopenharmony_ci			XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
206862306a36Sopenharmony_ci				       TNPCSUM_DONE, 0);
206962306a36Sopenharmony_ci			break;
207062306a36Sopenharmony_ci		}
207162306a36Sopenharmony_ci	}
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	/* Check for errors (only valid in last descriptor) */
207462306a36Sopenharmony_ci	err = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ES);
207562306a36Sopenharmony_ci	etlt = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ETLT);
207662306a36Sopenharmony_ci	netif_dbg(pdata, rx_status, netdev, "err=%u, etlt=%#x\n", err, etlt);
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	if (!err || !etlt) {
207962306a36Sopenharmony_ci		/* No error if err is 0 or etlt is 0 */
208062306a36Sopenharmony_ci		if ((etlt == 0x09) &&
208162306a36Sopenharmony_ci		    (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
208262306a36Sopenharmony_ci			XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
208362306a36Sopenharmony_ci				       VLAN_CTAG, 1);
208462306a36Sopenharmony_ci			packet->vlan_ctag = XGMAC_GET_BITS_LE(rdesc->desc0,
208562306a36Sopenharmony_ci							      RX_NORMAL_DESC0,
208662306a36Sopenharmony_ci							      OVT);
208762306a36Sopenharmony_ci			netif_dbg(pdata, rx_status, netdev, "vlan-ctag=%#06x\n",
208862306a36Sopenharmony_ci				  packet->vlan_ctag);
208962306a36Sopenharmony_ci		}
209062306a36Sopenharmony_ci	} else {
209162306a36Sopenharmony_ci		unsigned int tnp = XGMAC_GET_BITS(packet->attributes,
209262306a36Sopenharmony_ci						  RX_PACKET_ATTRIBUTES, TNP);
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci		if ((etlt == 0x05) || (etlt == 0x06)) {
209562306a36Sopenharmony_ci			XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
209662306a36Sopenharmony_ci				       CSUM_DONE, 0);
209762306a36Sopenharmony_ci			XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
209862306a36Sopenharmony_ci				       TNPCSUM_DONE, 0);
209962306a36Sopenharmony_ci			pdata->ext_stats.rx_csum_errors++;
210062306a36Sopenharmony_ci		} else if (tnp && ((etlt == 0x09) || (etlt == 0x0a))) {
210162306a36Sopenharmony_ci			XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
210262306a36Sopenharmony_ci				       CSUM_DONE, 0);
210362306a36Sopenharmony_ci			XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
210462306a36Sopenharmony_ci				       TNPCSUM_DONE, 0);
210562306a36Sopenharmony_ci			pdata->ext_stats.rx_vxlan_csum_errors++;
210662306a36Sopenharmony_ci		} else {
210762306a36Sopenharmony_ci			XGMAC_SET_BITS(packet->errors, RX_PACKET_ERRORS,
210862306a36Sopenharmony_ci				       FRAME, 1);
210962306a36Sopenharmony_ci		}
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	pdata->ext_stats.rxq_packets[channel->queue_index]++;
211362306a36Sopenharmony_ci	pdata->ext_stats.rxq_bytes[channel->queue_index] += rdata->rx.len;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	DBGPR("<--xgbe_dev_read: %s - descriptor=%u (cur=%d)\n", channel->name,
211662306a36Sopenharmony_ci	      ring->cur & (ring->rdesc_count - 1), ring->cur);
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	return 0;
211962306a36Sopenharmony_ci}
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_cistatic int xgbe_is_context_desc(struct xgbe_ring_desc *rdesc)
212262306a36Sopenharmony_ci{
212362306a36Sopenharmony_ci	/* Rx and Tx share CTXT bit, so check TDES3.CTXT bit */
212462306a36Sopenharmony_ci	return XGMAC_GET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT);
212562306a36Sopenharmony_ci}
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_cistatic int xgbe_is_last_desc(struct xgbe_ring_desc *rdesc)
212862306a36Sopenharmony_ci{
212962306a36Sopenharmony_ci	/* Rx and Tx share LD bit, so check TDES3.LD bit */
213062306a36Sopenharmony_ci	return XGMAC_GET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, LD);
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_cistatic int xgbe_enable_int(struct xgbe_channel *channel,
213462306a36Sopenharmony_ci			   enum xgbe_int int_id)
213562306a36Sopenharmony_ci{
213662306a36Sopenharmony_ci	switch (int_id) {
213762306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_TI:
213862306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TIE, 1);
213962306a36Sopenharmony_ci		break;
214062306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_TPS:
214162306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TXSE, 1);
214262306a36Sopenharmony_ci		break;
214362306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_TBU:
214462306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TBUE, 1);
214562306a36Sopenharmony_ci		break;
214662306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_RI:
214762306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RIE, 1);
214862306a36Sopenharmony_ci		break;
214962306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_RBU:
215062306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RBUE, 1);
215162306a36Sopenharmony_ci		break;
215262306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_RPS:
215362306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RSE, 1);
215462306a36Sopenharmony_ci		break;
215562306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_TI_RI:
215662306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TIE, 1);
215762306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RIE, 1);
215862306a36Sopenharmony_ci		break;
215962306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_FBE:
216062306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, FBEE, 1);
216162306a36Sopenharmony_ci		break;
216262306a36Sopenharmony_ci	case XGMAC_INT_DMA_ALL:
216362306a36Sopenharmony_ci		channel->curr_ier |= channel->saved_ier;
216462306a36Sopenharmony_ci		break;
216562306a36Sopenharmony_ci	default:
216662306a36Sopenharmony_ci		return -1;
216762306a36Sopenharmony_ci	}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, channel->curr_ier);
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	return 0;
217262306a36Sopenharmony_ci}
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_cistatic int xgbe_disable_int(struct xgbe_channel *channel,
217562306a36Sopenharmony_ci			    enum xgbe_int int_id)
217662306a36Sopenharmony_ci{
217762306a36Sopenharmony_ci	switch (int_id) {
217862306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_TI:
217962306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TIE, 0);
218062306a36Sopenharmony_ci		break;
218162306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_TPS:
218262306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TXSE, 0);
218362306a36Sopenharmony_ci		break;
218462306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_TBU:
218562306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TBUE, 0);
218662306a36Sopenharmony_ci		break;
218762306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_RI:
218862306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RIE, 0);
218962306a36Sopenharmony_ci		break;
219062306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_RBU:
219162306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RBUE, 0);
219262306a36Sopenharmony_ci		break;
219362306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_RPS:
219462306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RSE, 0);
219562306a36Sopenharmony_ci		break;
219662306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_TI_RI:
219762306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TIE, 0);
219862306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RIE, 0);
219962306a36Sopenharmony_ci		break;
220062306a36Sopenharmony_ci	case XGMAC_INT_DMA_CH_SR_FBE:
220162306a36Sopenharmony_ci		XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, FBEE, 0);
220262306a36Sopenharmony_ci		break;
220362306a36Sopenharmony_ci	case XGMAC_INT_DMA_ALL:
220462306a36Sopenharmony_ci		channel->saved_ier = channel->curr_ier;
220562306a36Sopenharmony_ci		channel->curr_ier = 0;
220662306a36Sopenharmony_ci		break;
220762306a36Sopenharmony_ci	default:
220862306a36Sopenharmony_ci		return -1;
220962306a36Sopenharmony_ci	}
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, channel->curr_ier);
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	return 0;
221462306a36Sopenharmony_ci}
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_cistatic int __xgbe_exit(struct xgbe_prv_data *pdata)
221762306a36Sopenharmony_ci{
221862306a36Sopenharmony_ci	unsigned int count = 2000;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	DBGPR("-->xgbe_exit\n");
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	/* Issue a software reset */
222362306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, DMA_MR, SWR, 1);
222462306a36Sopenharmony_ci	usleep_range(10, 15);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	/* Poll Until Poll Condition */
222762306a36Sopenharmony_ci	while (--count && XGMAC_IOREAD_BITS(pdata, DMA_MR, SWR))
222862306a36Sopenharmony_ci		usleep_range(500, 600);
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	if (!count)
223162306a36Sopenharmony_ci		return -EBUSY;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	DBGPR("<--xgbe_exit\n");
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	return 0;
223662306a36Sopenharmony_ci}
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_cistatic int xgbe_exit(struct xgbe_prv_data *pdata)
223962306a36Sopenharmony_ci{
224062306a36Sopenharmony_ci	int ret;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	/* To guard against possible incorrectly generated interrupts,
224362306a36Sopenharmony_ci	 * issue the software reset twice.
224462306a36Sopenharmony_ci	 */
224562306a36Sopenharmony_ci	ret = __xgbe_exit(pdata);
224662306a36Sopenharmony_ci	if (ret)
224762306a36Sopenharmony_ci		return ret;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	return __xgbe_exit(pdata);
225062306a36Sopenharmony_ci}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_cistatic int xgbe_flush_tx_queues(struct xgbe_prv_data *pdata)
225362306a36Sopenharmony_ci{
225462306a36Sopenharmony_ci	unsigned int i, count;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER) < 0x21)
225762306a36Sopenharmony_ci		return 0;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	for (i = 0; i < pdata->tx_q_count; i++)
226062306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, FTQ, 1);
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	/* Poll Until Poll Condition */
226362306a36Sopenharmony_ci	for (i = 0; i < pdata->tx_q_count; i++) {
226462306a36Sopenharmony_ci		count = 2000;
226562306a36Sopenharmony_ci		while (--count && XGMAC_MTL_IOREAD_BITS(pdata, i,
226662306a36Sopenharmony_ci							MTL_Q_TQOMR, FTQ))
226762306a36Sopenharmony_ci			usleep_range(500, 600);
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci		if (!count)
227062306a36Sopenharmony_ci			return -EBUSY;
227162306a36Sopenharmony_ci	}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	return 0;
227462306a36Sopenharmony_ci}
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_cistatic void xgbe_config_dma_bus(struct xgbe_prv_data *pdata)
227762306a36Sopenharmony_ci{
227862306a36Sopenharmony_ci	unsigned int sbmr;
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	sbmr = XGMAC_IOREAD(pdata, DMA_SBMR);
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	/* Set enhanced addressing mode */
228362306a36Sopenharmony_ci	XGMAC_SET_BITS(sbmr, DMA_SBMR, EAME, 1);
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	/* Set the System Bus mode */
228662306a36Sopenharmony_ci	XGMAC_SET_BITS(sbmr, DMA_SBMR, UNDEF, 1);
228762306a36Sopenharmony_ci	XGMAC_SET_BITS(sbmr, DMA_SBMR, BLEN, pdata->blen >> 2);
228862306a36Sopenharmony_ci	XGMAC_SET_BITS(sbmr, DMA_SBMR, AAL, pdata->aal);
228962306a36Sopenharmony_ci	XGMAC_SET_BITS(sbmr, DMA_SBMR, RD_OSR_LMT, pdata->rd_osr_limit - 1);
229062306a36Sopenharmony_ci	XGMAC_SET_BITS(sbmr, DMA_SBMR, WR_OSR_LMT, pdata->wr_osr_limit - 1);
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, DMA_SBMR, sbmr);
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	/* Set descriptor fetching threshold */
229562306a36Sopenharmony_ci	if (pdata->vdata->tx_desc_prefetch)
229662306a36Sopenharmony_ci		XGMAC_IOWRITE_BITS(pdata, DMA_TXEDMACR, TDPS,
229762306a36Sopenharmony_ci				   pdata->vdata->tx_desc_prefetch);
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	if (pdata->vdata->rx_desc_prefetch)
230062306a36Sopenharmony_ci		XGMAC_IOWRITE_BITS(pdata, DMA_RXEDMACR, RDPS,
230162306a36Sopenharmony_ci				   pdata->vdata->rx_desc_prefetch);
230262306a36Sopenharmony_ci}
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_cistatic void xgbe_config_dma_cache(struct xgbe_prv_data *pdata)
230562306a36Sopenharmony_ci{
230662306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, DMA_AXIARCR, pdata->arcr);
230762306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, DMA_AXIAWCR, pdata->awcr);
230862306a36Sopenharmony_ci	if (pdata->awarcr)
230962306a36Sopenharmony_ci		XGMAC_IOWRITE(pdata, DMA_AXIAWARCR, pdata->awarcr);
231062306a36Sopenharmony_ci}
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_cistatic void xgbe_config_mtl_mode(struct xgbe_prv_data *pdata)
231362306a36Sopenharmony_ci{
231462306a36Sopenharmony_ci	unsigned int i;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	/* Set Tx to weighted round robin scheduling algorithm */
231762306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MTL_OMR, ETSALG, MTL_ETSALG_WRR);
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	/* Set Tx traffic classes to use WRR algorithm with equal weights */
232062306a36Sopenharmony_ci	for (i = 0; i < pdata->hw_feat.tc_cnt; i++) {
232162306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA,
232262306a36Sopenharmony_ci				       MTL_TSA_ETS);
232362306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_QWR, QW, 1);
232462306a36Sopenharmony_ci	}
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	/* Set Rx to strict priority algorithm */
232762306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MTL_OMR, RAA, MTL_RAA_SP);
232862306a36Sopenharmony_ci}
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_cistatic void xgbe_queue_flow_control_threshold(struct xgbe_prv_data *pdata,
233162306a36Sopenharmony_ci					      unsigned int queue,
233262306a36Sopenharmony_ci					      unsigned int q_fifo_size)
233362306a36Sopenharmony_ci{
233462306a36Sopenharmony_ci	unsigned int frame_fifo_size;
233562306a36Sopenharmony_ci	unsigned int rfa, rfd;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	frame_fifo_size = XGMAC_FLOW_CONTROL_ALIGN(xgbe_get_max_frame(pdata));
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	if (pdata->pfcq[queue] && (q_fifo_size > pdata->pfc_rfa)) {
234062306a36Sopenharmony_ci		/* PFC is active for this queue */
234162306a36Sopenharmony_ci		rfa = pdata->pfc_rfa;
234262306a36Sopenharmony_ci		rfd = rfa + frame_fifo_size;
234362306a36Sopenharmony_ci		if (rfd > XGMAC_FLOW_CONTROL_MAX)
234462306a36Sopenharmony_ci			rfd = XGMAC_FLOW_CONTROL_MAX;
234562306a36Sopenharmony_ci		if (rfa >= XGMAC_FLOW_CONTROL_MAX)
234662306a36Sopenharmony_ci			rfa = XGMAC_FLOW_CONTROL_MAX - XGMAC_FLOW_CONTROL_UNIT;
234762306a36Sopenharmony_ci	} else {
234862306a36Sopenharmony_ci		/* This path deals with just maximum frame sizes which are
234962306a36Sopenharmony_ci		 * limited to a jumbo frame of 9,000 (plus headers, etc.)
235062306a36Sopenharmony_ci		 * so we can never exceed the maximum allowable RFA/RFD
235162306a36Sopenharmony_ci		 * values.
235262306a36Sopenharmony_ci		 */
235362306a36Sopenharmony_ci		if (q_fifo_size <= 2048) {
235462306a36Sopenharmony_ci			/* rx_rfd to zero to signal no flow control */
235562306a36Sopenharmony_ci			pdata->rx_rfa[queue] = 0;
235662306a36Sopenharmony_ci			pdata->rx_rfd[queue] = 0;
235762306a36Sopenharmony_ci			return;
235862306a36Sopenharmony_ci		}
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci		if (q_fifo_size <= 4096) {
236162306a36Sopenharmony_ci			/* Between 2048 and 4096 */
236262306a36Sopenharmony_ci			pdata->rx_rfa[queue] = 0;	/* Full - 1024 bytes */
236362306a36Sopenharmony_ci			pdata->rx_rfd[queue] = 1;	/* Full - 1536 bytes */
236462306a36Sopenharmony_ci			return;
236562306a36Sopenharmony_ci		}
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci		if (q_fifo_size <= frame_fifo_size) {
236862306a36Sopenharmony_ci			/* Between 4096 and max-frame */
236962306a36Sopenharmony_ci			pdata->rx_rfa[queue] = 2;	/* Full - 2048 bytes */
237062306a36Sopenharmony_ci			pdata->rx_rfd[queue] = 5;	/* Full - 3584 bytes */
237162306a36Sopenharmony_ci			return;
237262306a36Sopenharmony_ci		}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci		if (q_fifo_size <= (frame_fifo_size * 3)) {
237562306a36Sopenharmony_ci			/* Between max-frame and 3 max-frames,
237662306a36Sopenharmony_ci			 * trigger if we get just over a frame of data and
237762306a36Sopenharmony_ci			 * resume when we have just under half a frame left.
237862306a36Sopenharmony_ci			 */
237962306a36Sopenharmony_ci			rfa = q_fifo_size - frame_fifo_size;
238062306a36Sopenharmony_ci			rfd = rfa + (frame_fifo_size / 2);
238162306a36Sopenharmony_ci		} else {
238262306a36Sopenharmony_ci			/* Above 3 max-frames - trigger when just over
238362306a36Sopenharmony_ci			 * 2 frames of space available
238462306a36Sopenharmony_ci			 */
238562306a36Sopenharmony_ci			rfa = frame_fifo_size * 2;
238662306a36Sopenharmony_ci			rfa += XGMAC_FLOW_CONTROL_UNIT;
238762306a36Sopenharmony_ci			rfd = rfa + frame_fifo_size;
238862306a36Sopenharmony_ci		}
238962306a36Sopenharmony_ci	}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	pdata->rx_rfa[queue] = XGMAC_FLOW_CONTROL_VALUE(rfa);
239262306a36Sopenharmony_ci	pdata->rx_rfd[queue] = XGMAC_FLOW_CONTROL_VALUE(rfd);
239362306a36Sopenharmony_ci}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_cistatic void xgbe_calculate_flow_control_threshold(struct xgbe_prv_data *pdata,
239662306a36Sopenharmony_ci						  unsigned int *fifo)
239762306a36Sopenharmony_ci{
239862306a36Sopenharmony_ci	unsigned int q_fifo_size;
239962306a36Sopenharmony_ci	unsigned int i;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count; i++) {
240262306a36Sopenharmony_ci		q_fifo_size = (fifo[i] + 1) * XGMAC_FIFO_UNIT;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci		xgbe_queue_flow_control_threshold(pdata, i, q_fifo_size);
240562306a36Sopenharmony_ci	}
240662306a36Sopenharmony_ci}
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_cistatic void xgbe_config_flow_control_threshold(struct xgbe_prv_data *pdata)
240962306a36Sopenharmony_ci{
241062306a36Sopenharmony_ci	unsigned int i;
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count; i++) {
241362306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQFCR, RFA,
241462306a36Sopenharmony_ci				       pdata->rx_rfa[i]);
241562306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQFCR, RFD,
241662306a36Sopenharmony_ci				       pdata->rx_rfd[i]);
241762306a36Sopenharmony_ci	}
241862306a36Sopenharmony_ci}
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_cistatic unsigned int xgbe_get_tx_fifo_size(struct xgbe_prv_data *pdata)
242162306a36Sopenharmony_ci{
242262306a36Sopenharmony_ci	/* The configured value may not be the actual amount of fifo RAM */
242362306a36Sopenharmony_ci	return min_t(unsigned int, pdata->tx_max_fifo_size,
242462306a36Sopenharmony_ci		     pdata->hw_feat.tx_fifo_size);
242562306a36Sopenharmony_ci}
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_cistatic unsigned int xgbe_get_rx_fifo_size(struct xgbe_prv_data *pdata)
242862306a36Sopenharmony_ci{
242962306a36Sopenharmony_ci	/* The configured value may not be the actual amount of fifo RAM */
243062306a36Sopenharmony_ci	return min_t(unsigned int, pdata->rx_max_fifo_size,
243162306a36Sopenharmony_ci		     pdata->hw_feat.rx_fifo_size);
243262306a36Sopenharmony_ci}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_cistatic void xgbe_calculate_equal_fifo(unsigned int fifo_size,
243562306a36Sopenharmony_ci				      unsigned int queue_count,
243662306a36Sopenharmony_ci				      unsigned int *fifo)
243762306a36Sopenharmony_ci{
243862306a36Sopenharmony_ci	unsigned int q_fifo_size;
243962306a36Sopenharmony_ci	unsigned int p_fifo;
244062306a36Sopenharmony_ci	unsigned int i;
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	q_fifo_size = fifo_size / queue_count;
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	/* Calculate the fifo setting by dividing the queue's fifo size
244562306a36Sopenharmony_ci	 * by the fifo allocation increment (with 0 representing the
244662306a36Sopenharmony_ci	 * base allocation increment so decrement the result by 1).
244762306a36Sopenharmony_ci	 */
244862306a36Sopenharmony_ci	p_fifo = q_fifo_size / XGMAC_FIFO_UNIT;
244962306a36Sopenharmony_ci	if (p_fifo)
245062306a36Sopenharmony_ci		p_fifo--;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	/* Distribute the fifo equally amongst the queues */
245362306a36Sopenharmony_ci	for (i = 0; i < queue_count; i++)
245462306a36Sopenharmony_ci		fifo[i] = p_fifo;
245562306a36Sopenharmony_ci}
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_cistatic unsigned int xgbe_set_nonprio_fifos(unsigned int fifo_size,
245862306a36Sopenharmony_ci					   unsigned int queue_count,
245962306a36Sopenharmony_ci					   unsigned int *fifo)
246062306a36Sopenharmony_ci{
246162306a36Sopenharmony_ci	unsigned int i;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	BUILD_BUG_ON_NOT_POWER_OF_2(XGMAC_FIFO_MIN_ALLOC);
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	if (queue_count <= IEEE_8021QAZ_MAX_TCS)
246662306a36Sopenharmony_ci		return fifo_size;
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	/* Rx queues 9 and up are for specialized packets,
246962306a36Sopenharmony_ci	 * such as PTP or DCB control packets, etc. and
247062306a36Sopenharmony_ci	 * don't require a large fifo
247162306a36Sopenharmony_ci	 */
247262306a36Sopenharmony_ci	for (i = IEEE_8021QAZ_MAX_TCS; i < queue_count; i++) {
247362306a36Sopenharmony_ci		fifo[i] = (XGMAC_FIFO_MIN_ALLOC / XGMAC_FIFO_UNIT) - 1;
247462306a36Sopenharmony_ci		fifo_size -= XGMAC_FIFO_MIN_ALLOC;
247562306a36Sopenharmony_ci	}
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	return fifo_size;
247862306a36Sopenharmony_ci}
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_cistatic unsigned int xgbe_get_pfc_delay(struct xgbe_prv_data *pdata)
248162306a36Sopenharmony_ci{
248262306a36Sopenharmony_ci	unsigned int delay;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	/* If a delay has been provided, use that */
248562306a36Sopenharmony_ci	if (pdata->pfc->delay)
248662306a36Sopenharmony_ci		return pdata->pfc->delay / 8;
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	/* Allow for two maximum size frames */
248962306a36Sopenharmony_ci	delay = xgbe_get_max_frame(pdata);
249062306a36Sopenharmony_ci	delay += XGMAC_ETH_PREAMBLE;
249162306a36Sopenharmony_ci	delay *= 2;
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	/* Allow for PFC frame */
249462306a36Sopenharmony_ci	delay += XGMAC_PFC_DATA_LEN;
249562306a36Sopenharmony_ci	delay += ETH_HLEN + ETH_FCS_LEN;
249662306a36Sopenharmony_ci	delay += XGMAC_ETH_PREAMBLE;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	/* Allow for miscellaneous delays (LPI exit, cable, etc.) */
249962306a36Sopenharmony_ci	delay += XGMAC_PFC_DELAYS;
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	return delay;
250262306a36Sopenharmony_ci}
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_cistatic unsigned int xgbe_get_pfc_queues(struct xgbe_prv_data *pdata)
250562306a36Sopenharmony_ci{
250662306a36Sopenharmony_ci	unsigned int count, prio_queues;
250762306a36Sopenharmony_ci	unsigned int i;
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	if (!pdata->pfc->pfc_en)
251062306a36Sopenharmony_ci		return 0;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	count = 0;
251362306a36Sopenharmony_ci	prio_queues = XGMAC_PRIO_QUEUES(pdata->rx_q_count);
251462306a36Sopenharmony_ci	for (i = 0; i < prio_queues; i++) {
251562306a36Sopenharmony_ci		if (!xgbe_is_pfc_queue(pdata, i))
251662306a36Sopenharmony_ci			continue;
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci		pdata->pfcq[i] = 1;
251962306a36Sopenharmony_ci		count++;
252062306a36Sopenharmony_ci	}
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	return count;
252362306a36Sopenharmony_ci}
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_cistatic void xgbe_calculate_dcb_fifo(struct xgbe_prv_data *pdata,
252662306a36Sopenharmony_ci				    unsigned int fifo_size,
252762306a36Sopenharmony_ci				    unsigned int *fifo)
252862306a36Sopenharmony_ci{
252962306a36Sopenharmony_ci	unsigned int q_fifo_size, rem_fifo, addn_fifo;
253062306a36Sopenharmony_ci	unsigned int prio_queues;
253162306a36Sopenharmony_ci	unsigned int pfc_count;
253262306a36Sopenharmony_ci	unsigned int i;
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	q_fifo_size = XGMAC_FIFO_ALIGN(xgbe_get_max_frame(pdata));
253562306a36Sopenharmony_ci	prio_queues = XGMAC_PRIO_QUEUES(pdata->rx_q_count);
253662306a36Sopenharmony_ci	pfc_count = xgbe_get_pfc_queues(pdata);
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	if (!pfc_count || ((q_fifo_size * prio_queues) > fifo_size)) {
253962306a36Sopenharmony_ci		/* No traffic classes with PFC enabled or can't do lossless */
254062306a36Sopenharmony_ci		xgbe_calculate_equal_fifo(fifo_size, prio_queues, fifo);
254162306a36Sopenharmony_ci		return;
254262306a36Sopenharmony_ci	}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	/* Calculate how much fifo we have to play with */
254562306a36Sopenharmony_ci	rem_fifo = fifo_size - (q_fifo_size * prio_queues);
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	/* Calculate how much more than base fifo PFC needs, which also
254862306a36Sopenharmony_ci	 * becomes the threshold activation point (RFA)
254962306a36Sopenharmony_ci	 */
255062306a36Sopenharmony_ci	pdata->pfc_rfa = xgbe_get_pfc_delay(pdata);
255162306a36Sopenharmony_ci	pdata->pfc_rfa = XGMAC_FLOW_CONTROL_ALIGN(pdata->pfc_rfa);
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	if (pdata->pfc_rfa > q_fifo_size) {
255462306a36Sopenharmony_ci		addn_fifo = pdata->pfc_rfa - q_fifo_size;
255562306a36Sopenharmony_ci		addn_fifo = XGMAC_FIFO_ALIGN(addn_fifo);
255662306a36Sopenharmony_ci	} else {
255762306a36Sopenharmony_ci		addn_fifo = 0;
255862306a36Sopenharmony_ci	}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci	/* Calculate DCB fifo settings:
256162306a36Sopenharmony_ci	 *   - distribute remaining fifo between the VLAN priority
256262306a36Sopenharmony_ci	 *     queues based on traffic class PFC enablement and overall
256362306a36Sopenharmony_ci	 *     priority (0 is lowest priority, so start at highest)
256462306a36Sopenharmony_ci	 */
256562306a36Sopenharmony_ci	i = prio_queues;
256662306a36Sopenharmony_ci	while (i > 0) {
256762306a36Sopenharmony_ci		i--;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci		fifo[i] = (q_fifo_size / XGMAC_FIFO_UNIT) - 1;
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci		if (!pdata->pfcq[i] || !addn_fifo)
257262306a36Sopenharmony_ci			continue;
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci		if (addn_fifo > rem_fifo) {
257562306a36Sopenharmony_ci			netdev_warn(pdata->netdev,
257662306a36Sopenharmony_ci				    "RXq%u cannot set needed fifo size\n", i);
257762306a36Sopenharmony_ci			if (!rem_fifo)
257862306a36Sopenharmony_ci				continue;
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci			addn_fifo = rem_fifo;
258162306a36Sopenharmony_ci		}
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci		fifo[i] += (addn_fifo / XGMAC_FIFO_UNIT);
258462306a36Sopenharmony_ci		rem_fifo -= addn_fifo;
258562306a36Sopenharmony_ci	}
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	if (rem_fifo) {
258862306a36Sopenharmony_ci		unsigned int inc_fifo = rem_fifo / prio_queues;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci		/* Distribute remaining fifo across queues */
259162306a36Sopenharmony_ci		for (i = 0; i < prio_queues; i++)
259262306a36Sopenharmony_ci			fifo[i] += (inc_fifo / XGMAC_FIFO_UNIT);
259362306a36Sopenharmony_ci	}
259462306a36Sopenharmony_ci}
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_cistatic void xgbe_config_tx_fifo_size(struct xgbe_prv_data *pdata)
259762306a36Sopenharmony_ci{
259862306a36Sopenharmony_ci	unsigned int fifo_size;
259962306a36Sopenharmony_ci	unsigned int fifo[XGBE_MAX_QUEUES];
260062306a36Sopenharmony_ci	unsigned int i;
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	fifo_size = xgbe_get_tx_fifo_size(pdata);
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	xgbe_calculate_equal_fifo(fifo_size, pdata->tx_q_count, fifo);
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	for (i = 0; i < pdata->tx_q_count; i++)
260762306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TQS, fifo[i]);
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	netif_info(pdata, drv, pdata->netdev,
261062306a36Sopenharmony_ci		   "%d Tx hardware queues, %d byte fifo per queue\n",
261162306a36Sopenharmony_ci		   pdata->tx_q_count, ((fifo[0] + 1) * XGMAC_FIFO_UNIT));
261262306a36Sopenharmony_ci}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_cistatic void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata)
261562306a36Sopenharmony_ci{
261662306a36Sopenharmony_ci	unsigned int fifo_size;
261762306a36Sopenharmony_ci	unsigned int fifo[XGBE_MAX_QUEUES];
261862306a36Sopenharmony_ci	unsigned int prio_queues;
261962306a36Sopenharmony_ci	unsigned int i;
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	/* Clear any DCB related fifo/queue information */
262262306a36Sopenharmony_ci	memset(pdata->pfcq, 0, sizeof(pdata->pfcq));
262362306a36Sopenharmony_ci	pdata->pfc_rfa = 0;
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	fifo_size = xgbe_get_rx_fifo_size(pdata);
262662306a36Sopenharmony_ci	prio_queues = XGMAC_PRIO_QUEUES(pdata->rx_q_count);
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	/* Assign a minimum fifo to the non-VLAN priority queues */
262962306a36Sopenharmony_ci	fifo_size = xgbe_set_nonprio_fifos(fifo_size, pdata->rx_q_count, fifo);
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	if (pdata->pfc && pdata->ets)
263262306a36Sopenharmony_ci		xgbe_calculate_dcb_fifo(pdata, fifo_size, fifo);
263362306a36Sopenharmony_ci	else
263462306a36Sopenharmony_ci		xgbe_calculate_equal_fifo(fifo_size, prio_queues, fifo);
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count; i++)
263762306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RQS, fifo[i]);
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	xgbe_calculate_flow_control_threshold(pdata, fifo);
264062306a36Sopenharmony_ci	xgbe_config_flow_control_threshold(pdata);
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_ci	if (pdata->pfc && pdata->ets && pdata->pfc->pfc_en) {
264362306a36Sopenharmony_ci		netif_info(pdata, drv, pdata->netdev,
264462306a36Sopenharmony_ci			   "%u Rx hardware queues\n", pdata->rx_q_count);
264562306a36Sopenharmony_ci		for (i = 0; i < pdata->rx_q_count; i++)
264662306a36Sopenharmony_ci			netif_info(pdata, drv, pdata->netdev,
264762306a36Sopenharmony_ci				   "RxQ%u, %u byte fifo queue\n", i,
264862306a36Sopenharmony_ci				   ((fifo[i] + 1) * XGMAC_FIFO_UNIT));
264962306a36Sopenharmony_ci	} else {
265062306a36Sopenharmony_ci		netif_info(pdata, drv, pdata->netdev,
265162306a36Sopenharmony_ci			   "%u Rx hardware queues, %u byte fifo per queue\n",
265262306a36Sopenharmony_ci			   pdata->rx_q_count,
265362306a36Sopenharmony_ci			   ((fifo[0] + 1) * XGMAC_FIFO_UNIT));
265462306a36Sopenharmony_ci	}
265562306a36Sopenharmony_ci}
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_cistatic void xgbe_config_queue_mapping(struct xgbe_prv_data *pdata)
265862306a36Sopenharmony_ci{
265962306a36Sopenharmony_ci	unsigned int qptc, qptc_extra, queue;
266062306a36Sopenharmony_ci	unsigned int prio_queues;
266162306a36Sopenharmony_ci	unsigned int ppq, ppq_extra, prio;
266262306a36Sopenharmony_ci	unsigned int mask;
266362306a36Sopenharmony_ci	unsigned int i, j, reg, reg_val;
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	/* Map the MTL Tx Queues to Traffic Classes
266662306a36Sopenharmony_ci	 *   Note: Tx Queues >= Traffic Classes
266762306a36Sopenharmony_ci	 */
266862306a36Sopenharmony_ci	qptc = pdata->tx_q_count / pdata->hw_feat.tc_cnt;
266962306a36Sopenharmony_ci	qptc_extra = pdata->tx_q_count % pdata->hw_feat.tc_cnt;
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	for (i = 0, queue = 0; i < pdata->hw_feat.tc_cnt; i++) {
267262306a36Sopenharmony_ci		for (j = 0; j < qptc; j++) {
267362306a36Sopenharmony_ci			netif_dbg(pdata, drv, pdata->netdev,
267462306a36Sopenharmony_ci				  "TXq%u mapped to TC%u\n", queue, i);
267562306a36Sopenharmony_ci			XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR,
267662306a36Sopenharmony_ci					       Q2TCMAP, i);
267762306a36Sopenharmony_ci			pdata->q2tc_map[queue++] = i;
267862306a36Sopenharmony_ci		}
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci		if (i < qptc_extra) {
268162306a36Sopenharmony_ci			netif_dbg(pdata, drv, pdata->netdev,
268262306a36Sopenharmony_ci				  "TXq%u mapped to TC%u\n", queue, i);
268362306a36Sopenharmony_ci			XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR,
268462306a36Sopenharmony_ci					       Q2TCMAP, i);
268562306a36Sopenharmony_ci			pdata->q2tc_map[queue++] = i;
268662306a36Sopenharmony_ci		}
268762306a36Sopenharmony_ci	}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	/* Map the 8 VLAN priority values to available MTL Rx queues */
269062306a36Sopenharmony_ci	prio_queues = XGMAC_PRIO_QUEUES(pdata->rx_q_count);
269162306a36Sopenharmony_ci	ppq = IEEE_8021QAZ_MAX_TCS / prio_queues;
269262306a36Sopenharmony_ci	ppq_extra = IEEE_8021QAZ_MAX_TCS % prio_queues;
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	reg = MAC_RQC2R;
269562306a36Sopenharmony_ci	reg_val = 0;
269662306a36Sopenharmony_ci	for (i = 0, prio = 0; i < prio_queues;) {
269762306a36Sopenharmony_ci		mask = 0;
269862306a36Sopenharmony_ci		for (j = 0; j < ppq; j++) {
269962306a36Sopenharmony_ci			netif_dbg(pdata, drv, pdata->netdev,
270062306a36Sopenharmony_ci				  "PRIO%u mapped to RXq%u\n", prio, i);
270162306a36Sopenharmony_ci			mask |= (1 << prio);
270262306a36Sopenharmony_ci			pdata->prio2q_map[prio++] = i;
270362306a36Sopenharmony_ci		}
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci		if (i < ppq_extra) {
270662306a36Sopenharmony_ci			netif_dbg(pdata, drv, pdata->netdev,
270762306a36Sopenharmony_ci				  "PRIO%u mapped to RXq%u\n", prio, i);
270862306a36Sopenharmony_ci			mask |= (1 << prio);
270962306a36Sopenharmony_ci			pdata->prio2q_map[prio++] = i;
271062306a36Sopenharmony_ci		}
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci		reg_val |= (mask << ((i++ % MAC_RQC2_Q_PER_REG) << 3));
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci		if ((i % MAC_RQC2_Q_PER_REG) && (i != prio_queues))
271562306a36Sopenharmony_ci			continue;
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci		XGMAC_IOWRITE(pdata, reg, reg_val);
271862306a36Sopenharmony_ci		reg += MAC_RQC2_INC;
271962306a36Sopenharmony_ci		reg_val = 0;
272062306a36Sopenharmony_ci	}
272162306a36Sopenharmony_ci
272262306a36Sopenharmony_ci	/* Select dynamic mapping of MTL Rx queue to DMA Rx channel */
272362306a36Sopenharmony_ci	reg = MTL_RQDCM0R;
272462306a36Sopenharmony_ci	reg_val = 0;
272562306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count;) {
272662306a36Sopenharmony_ci		reg_val |= (0x80 << ((i++ % MTL_RQDCM_Q_PER_REG) << 3));
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci		if ((i % MTL_RQDCM_Q_PER_REG) && (i != pdata->rx_q_count))
272962306a36Sopenharmony_ci			continue;
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci		XGMAC_IOWRITE(pdata, reg, reg_val);
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci		reg += MTL_RQDCM_INC;
273462306a36Sopenharmony_ci		reg_val = 0;
273562306a36Sopenharmony_ci	}
273662306a36Sopenharmony_ci}
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_cistatic void xgbe_config_tc(struct xgbe_prv_data *pdata)
273962306a36Sopenharmony_ci{
274062306a36Sopenharmony_ci	unsigned int offset, queue, prio;
274162306a36Sopenharmony_ci	u8 i;
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	netdev_reset_tc(pdata->netdev);
274462306a36Sopenharmony_ci	if (!pdata->num_tcs)
274562306a36Sopenharmony_ci		return;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	netdev_set_num_tc(pdata->netdev, pdata->num_tcs);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	for (i = 0, queue = 0, offset = 0; i < pdata->num_tcs; i++) {
275062306a36Sopenharmony_ci		while ((queue < pdata->tx_q_count) &&
275162306a36Sopenharmony_ci		       (pdata->q2tc_map[queue] == i))
275262306a36Sopenharmony_ci			queue++;
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci		netif_dbg(pdata, drv, pdata->netdev, "TC%u using TXq%u-%u\n",
275562306a36Sopenharmony_ci			  i, offset, queue - 1);
275662306a36Sopenharmony_ci		netdev_set_tc_queue(pdata->netdev, i, queue - offset, offset);
275762306a36Sopenharmony_ci		offset = queue;
275862306a36Sopenharmony_ci	}
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	if (!pdata->ets)
276162306a36Sopenharmony_ci		return;
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
276462306a36Sopenharmony_ci		netdev_set_prio_tc_map(pdata->netdev, prio,
276562306a36Sopenharmony_ci				       pdata->ets->prio_tc[prio]);
276662306a36Sopenharmony_ci}
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_cistatic void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata)
276962306a36Sopenharmony_ci{
277062306a36Sopenharmony_ci	struct ieee_ets *ets = pdata->ets;
277162306a36Sopenharmony_ci	unsigned int total_weight, min_weight, weight;
277262306a36Sopenharmony_ci	unsigned int mask, reg, reg_val;
277362306a36Sopenharmony_ci	unsigned int i, prio;
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	if (!ets)
277662306a36Sopenharmony_ci		return;
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	/* Set Tx to deficit weighted round robin scheduling algorithm (when
277962306a36Sopenharmony_ci	 * traffic class is using ETS algorithm)
278062306a36Sopenharmony_ci	 */
278162306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MTL_OMR, ETSALG, MTL_ETSALG_DWRR);
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	/* Set Traffic Class algorithms */
278462306a36Sopenharmony_ci	total_weight = pdata->netdev->mtu * pdata->hw_feat.tc_cnt;
278562306a36Sopenharmony_ci	min_weight = total_weight / 100;
278662306a36Sopenharmony_ci	if (!min_weight)
278762306a36Sopenharmony_ci		min_weight = 1;
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ci	for (i = 0; i < pdata->hw_feat.tc_cnt; i++) {
279062306a36Sopenharmony_ci		/* Map the priorities to the traffic class */
279162306a36Sopenharmony_ci		mask = 0;
279262306a36Sopenharmony_ci		for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) {
279362306a36Sopenharmony_ci			if (ets->prio_tc[prio] == i)
279462306a36Sopenharmony_ci				mask |= (1 << prio);
279562306a36Sopenharmony_ci		}
279662306a36Sopenharmony_ci		mask &= 0xff;
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci		netif_dbg(pdata, drv, pdata->netdev, "TC%u PRIO mask=%#x\n",
279962306a36Sopenharmony_ci			  i, mask);
280062306a36Sopenharmony_ci		reg = MTL_TCPM0R + (MTL_TCPM_INC * (i / MTL_TCPM_TC_PER_REG));
280162306a36Sopenharmony_ci		reg_val = XGMAC_IOREAD(pdata, reg);
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci		reg_val &= ~(0xff << ((i % MTL_TCPM_TC_PER_REG) << 3));
280462306a36Sopenharmony_ci		reg_val |= (mask << ((i % MTL_TCPM_TC_PER_REG) << 3));
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci		XGMAC_IOWRITE(pdata, reg, reg_val);
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci		/* Set the traffic class algorithm */
280962306a36Sopenharmony_ci		switch (ets->tc_tsa[i]) {
281062306a36Sopenharmony_ci		case IEEE_8021QAZ_TSA_STRICT:
281162306a36Sopenharmony_ci			netif_dbg(pdata, drv, pdata->netdev,
281262306a36Sopenharmony_ci				  "TC%u using SP\n", i);
281362306a36Sopenharmony_ci			XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA,
281462306a36Sopenharmony_ci					       MTL_TSA_SP);
281562306a36Sopenharmony_ci			break;
281662306a36Sopenharmony_ci		case IEEE_8021QAZ_TSA_ETS:
281762306a36Sopenharmony_ci			weight = total_weight * ets->tc_tx_bw[i] / 100;
281862306a36Sopenharmony_ci			weight = clamp(weight, min_weight, total_weight);
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci			netif_dbg(pdata, drv, pdata->netdev,
282162306a36Sopenharmony_ci				  "TC%u using DWRR (weight %u)\n", i, weight);
282262306a36Sopenharmony_ci			XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA,
282362306a36Sopenharmony_ci					       MTL_TSA_ETS);
282462306a36Sopenharmony_ci			XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_QWR, QW,
282562306a36Sopenharmony_ci					       weight);
282662306a36Sopenharmony_ci			break;
282762306a36Sopenharmony_ci		}
282862306a36Sopenharmony_ci	}
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	xgbe_config_tc(pdata);
283162306a36Sopenharmony_ci}
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_cistatic void xgbe_config_dcb_pfc(struct xgbe_prv_data *pdata)
283462306a36Sopenharmony_ci{
283562306a36Sopenharmony_ci	if (!test_bit(XGBE_DOWN, &pdata->dev_state)) {
283662306a36Sopenharmony_ci		/* Just stop the Tx queues while Rx fifo is changed */
283762306a36Sopenharmony_ci		netif_tx_stop_all_queues(pdata->netdev);
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci		/* Suspend Rx so that fifo's can be adjusted */
284062306a36Sopenharmony_ci		pdata->hw_if.disable_rx(pdata);
284162306a36Sopenharmony_ci	}
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci	xgbe_config_rx_fifo_size(pdata);
284462306a36Sopenharmony_ci	xgbe_config_flow_control(pdata);
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	if (!test_bit(XGBE_DOWN, &pdata->dev_state)) {
284762306a36Sopenharmony_ci		/* Resume Rx */
284862306a36Sopenharmony_ci		pdata->hw_if.enable_rx(pdata);
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci		/* Resume Tx queues */
285162306a36Sopenharmony_ci		netif_tx_start_all_queues(pdata->netdev);
285262306a36Sopenharmony_ci	}
285362306a36Sopenharmony_ci}
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_cistatic void xgbe_config_mac_address(struct xgbe_prv_data *pdata)
285662306a36Sopenharmony_ci{
285762306a36Sopenharmony_ci	xgbe_set_mac_address(pdata, pdata->netdev->dev_addr);
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	/* Filtering is done using perfect filtering and hash filtering */
286062306a36Sopenharmony_ci	if (pdata->hw_feat.hash_table_size) {
286162306a36Sopenharmony_ci		XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 1);
286262306a36Sopenharmony_ci		XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 1);
286362306a36Sopenharmony_ci		XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HMC, 1);
286462306a36Sopenharmony_ci	}
286562306a36Sopenharmony_ci}
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_cistatic void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata)
286862306a36Sopenharmony_ci{
286962306a36Sopenharmony_ci	unsigned int val;
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	val = (pdata->netdev->mtu > XGMAC_STD_PACKET_MTU) ? 1 : 0;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, JE, val);
287462306a36Sopenharmony_ci}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_cistatic void xgbe_config_mac_speed(struct xgbe_prv_data *pdata)
287762306a36Sopenharmony_ci{
287862306a36Sopenharmony_ci	xgbe_set_speed(pdata, pdata->phy_speed);
287962306a36Sopenharmony_ci}
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_cistatic void xgbe_config_checksum_offload(struct xgbe_prv_data *pdata)
288262306a36Sopenharmony_ci{
288362306a36Sopenharmony_ci	if (pdata->netdev->features & NETIF_F_RXCSUM)
288462306a36Sopenharmony_ci		xgbe_enable_rx_csum(pdata);
288562306a36Sopenharmony_ci	else
288662306a36Sopenharmony_ci		xgbe_disable_rx_csum(pdata);
288762306a36Sopenharmony_ci}
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_cistatic void xgbe_config_vlan_support(struct xgbe_prv_data *pdata)
289062306a36Sopenharmony_ci{
289162306a36Sopenharmony_ci	/* Indicate that VLAN Tx CTAGs come from context descriptors */
289262306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, CSVL, 0);
289362306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, VLTI, 1);
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ci	/* Set the current VLAN Hash Table register value */
289662306a36Sopenharmony_ci	xgbe_update_vlan_hash_table(pdata);
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
289962306a36Sopenharmony_ci		xgbe_enable_rx_vlan_filtering(pdata);
290062306a36Sopenharmony_ci	else
290162306a36Sopenharmony_ci		xgbe_disable_rx_vlan_filtering(pdata);
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci	if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
290462306a36Sopenharmony_ci		xgbe_enable_rx_vlan_stripping(pdata);
290562306a36Sopenharmony_ci	else
290662306a36Sopenharmony_ci		xgbe_disable_rx_vlan_stripping(pdata);
290762306a36Sopenharmony_ci}
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_cistatic u64 xgbe_mmc_read(struct xgbe_prv_data *pdata, unsigned int reg_lo)
291062306a36Sopenharmony_ci{
291162306a36Sopenharmony_ci	bool read_hi;
291262306a36Sopenharmony_ci	u64 val;
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	if (pdata->vdata->mmc_64bit) {
291562306a36Sopenharmony_ci		switch (reg_lo) {
291662306a36Sopenharmony_ci		/* These registers are always 32 bit */
291762306a36Sopenharmony_ci		case MMC_RXRUNTERROR:
291862306a36Sopenharmony_ci		case MMC_RXJABBERERROR:
291962306a36Sopenharmony_ci		case MMC_RXUNDERSIZE_G:
292062306a36Sopenharmony_ci		case MMC_RXOVERSIZE_G:
292162306a36Sopenharmony_ci		case MMC_RXWATCHDOGERROR:
292262306a36Sopenharmony_ci			read_hi = false;
292362306a36Sopenharmony_ci			break;
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci		default:
292662306a36Sopenharmony_ci			read_hi = true;
292762306a36Sopenharmony_ci		}
292862306a36Sopenharmony_ci	} else {
292962306a36Sopenharmony_ci		switch (reg_lo) {
293062306a36Sopenharmony_ci		/* These registers are always 64 bit */
293162306a36Sopenharmony_ci		case MMC_TXOCTETCOUNT_GB_LO:
293262306a36Sopenharmony_ci		case MMC_TXOCTETCOUNT_G_LO:
293362306a36Sopenharmony_ci		case MMC_RXOCTETCOUNT_GB_LO:
293462306a36Sopenharmony_ci		case MMC_RXOCTETCOUNT_G_LO:
293562306a36Sopenharmony_ci			read_hi = true;
293662306a36Sopenharmony_ci			break;
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci		default:
293962306a36Sopenharmony_ci			read_hi = false;
294062306a36Sopenharmony_ci		}
294162306a36Sopenharmony_ci	}
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci	val = XGMAC_IOREAD(pdata, reg_lo);
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci	if (read_hi)
294662306a36Sopenharmony_ci		val |= ((u64)XGMAC_IOREAD(pdata, reg_lo + 4) << 32);
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_ci	return val;
294962306a36Sopenharmony_ci}
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_cistatic void xgbe_tx_mmc_int(struct xgbe_prv_data *pdata)
295262306a36Sopenharmony_ci{
295362306a36Sopenharmony_ci	struct xgbe_mmc_stats *stats = &pdata->mmc_stats;
295462306a36Sopenharmony_ci	unsigned int mmc_isr = XGMAC_IOREAD(pdata, MMC_TISR);
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXOCTETCOUNT_GB))
295762306a36Sopenharmony_ci		stats->txoctetcount_gb +=
295862306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXOCTETCOUNT_GB_LO);
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXFRAMECOUNT_GB))
296162306a36Sopenharmony_ci		stats->txframecount_gb +=
296262306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXFRAMECOUNT_GB_LO);
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXBROADCASTFRAMES_G))
296562306a36Sopenharmony_ci		stats->txbroadcastframes_g +=
296662306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXBROADCASTFRAMES_G_LO);
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXMULTICASTFRAMES_G))
296962306a36Sopenharmony_ci		stats->txmulticastframes_g +=
297062306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXMULTICASTFRAMES_G_LO);
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX64OCTETS_GB))
297362306a36Sopenharmony_ci		stats->tx64octets_gb +=
297462306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TX64OCTETS_GB_LO);
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX65TO127OCTETS_GB))
297762306a36Sopenharmony_ci		stats->tx65to127octets_gb +=
297862306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TX65TO127OCTETS_GB_LO);
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX128TO255OCTETS_GB))
298162306a36Sopenharmony_ci		stats->tx128to255octets_gb +=
298262306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TX128TO255OCTETS_GB_LO);
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX256TO511OCTETS_GB))
298562306a36Sopenharmony_ci		stats->tx256to511octets_gb +=
298662306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TX256TO511OCTETS_GB_LO);
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX512TO1023OCTETS_GB))
298962306a36Sopenharmony_ci		stats->tx512to1023octets_gb +=
299062306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TX512TO1023OCTETS_GB_LO);
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX1024TOMAXOCTETS_GB))
299362306a36Sopenharmony_ci		stats->tx1024tomaxoctets_gb +=
299462306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TX1024TOMAXOCTETS_GB_LO);
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXUNICASTFRAMES_GB))
299762306a36Sopenharmony_ci		stats->txunicastframes_gb +=
299862306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXUNICASTFRAMES_GB_LO);
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXMULTICASTFRAMES_GB))
300162306a36Sopenharmony_ci		stats->txmulticastframes_gb +=
300262306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXMULTICASTFRAMES_GB_LO);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXBROADCASTFRAMES_GB))
300562306a36Sopenharmony_ci		stats->txbroadcastframes_g +=
300662306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXBROADCASTFRAMES_GB_LO);
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXUNDERFLOWERROR))
300962306a36Sopenharmony_ci		stats->txunderflowerror +=
301062306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXUNDERFLOWERROR_LO);
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXOCTETCOUNT_G))
301362306a36Sopenharmony_ci		stats->txoctetcount_g +=
301462306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXOCTETCOUNT_G_LO);
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXFRAMECOUNT_G))
301762306a36Sopenharmony_ci		stats->txframecount_g +=
301862306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXFRAMECOUNT_G_LO);
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXPAUSEFRAMES))
302162306a36Sopenharmony_ci		stats->txpauseframes +=
302262306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXPAUSEFRAMES_LO);
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXVLANFRAMES_G))
302562306a36Sopenharmony_ci		stats->txvlanframes_g +=
302662306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_TXVLANFRAMES_G_LO);
302762306a36Sopenharmony_ci}
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_cistatic void xgbe_rx_mmc_int(struct xgbe_prv_data *pdata)
303062306a36Sopenharmony_ci{
303162306a36Sopenharmony_ci	struct xgbe_mmc_stats *stats = &pdata->mmc_stats;
303262306a36Sopenharmony_ci	unsigned int mmc_isr = XGMAC_IOREAD(pdata, MMC_RISR);
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXFRAMECOUNT_GB))
303562306a36Sopenharmony_ci		stats->rxframecount_gb +=
303662306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXFRAMECOUNT_GB_LO);
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOCTETCOUNT_GB))
303962306a36Sopenharmony_ci		stats->rxoctetcount_gb +=
304062306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXOCTETCOUNT_GB_LO);
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOCTETCOUNT_G))
304362306a36Sopenharmony_ci		stats->rxoctetcount_g +=
304462306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXOCTETCOUNT_G_LO);
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXBROADCASTFRAMES_G))
304762306a36Sopenharmony_ci		stats->rxbroadcastframes_g +=
304862306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXBROADCASTFRAMES_G_LO);
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXMULTICASTFRAMES_G))
305162306a36Sopenharmony_ci		stats->rxmulticastframes_g +=
305262306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXMULTICASTFRAMES_G_LO);
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXCRCERROR))
305562306a36Sopenharmony_ci		stats->rxcrcerror +=
305662306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXCRCERROR_LO);
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXRUNTERROR))
305962306a36Sopenharmony_ci		stats->rxrunterror +=
306062306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXRUNTERROR);
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXJABBERERROR))
306362306a36Sopenharmony_ci		stats->rxjabbererror +=
306462306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXJABBERERROR);
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXUNDERSIZE_G))
306762306a36Sopenharmony_ci		stats->rxundersize_g +=
306862306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXUNDERSIZE_G);
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOVERSIZE_G))
307162306a36Sopenharmony_ci		stats->rxoversize_g +=
307262306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXOVERSIZE_G);
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX64OCTETS_GB))
307562306a36Sopenharmony_ci		stats->rx64octets_gb +=
307662306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RX64OCTETS_GB_LO);
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX65TO127OCTETS_GB))
307962306a36Sopenharmony_ci		stats->rx65to127octets_gb +=
308062306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RX65TO127OCTETS_GB_LO);
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX128TO255OCTETS_GB))
308362306a36Sopenharmony_ci		stats->rx128to255octets_gb +=
308462306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RX128TO255OCTETS_GB_LO);
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX256TO511OCTETS_GB))
308762306a36Sopenharmony_ci		stats->rx256to511octets_gb +=
308862306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RX256TO511OCTETS_GB_LO);
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX512TO1023OCTETS_GB))
309162306a36Sopenharmony_ci		stats->rx512to1023octets_gb +=
309262306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RX512TO1023OCTETS_GB_LO);
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX1024TOMAXOCTETS_GB))
309562306a36Sopenharmony_ci		stats->rx1024tomaxoctets_gb +=
309662306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RX1024TOMAXOCTETS_GB_LO);
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXUNICASTFRAMES_G))
309962306a36Sopenharmony_ci		stats->rxunicastframes_g +=
310062306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXUNICASTFRAMES_G_LO);
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXLENGTHERROR))
310362306a36Sopenharmony_ci		stats->rxlengtherror +=
310462306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXLENGTHERROR_LO);
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOUTOFRANGETYPE))
310762306a36Sopenharmony_ci		stats->rxoutofrangetype +=
310862306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXOUTOFRANGETYPE_LO);
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXPAUSEFRAMES))
311162306a36Sopenharmony_ci		stats->rxpauseframes +=
311262306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXPAUSEFRAMES_LO);
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXFIFOOVERFLOW))
311562306a36Sopenharmony_ci		stats->rxfifooverflow +=
311662306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXFIFOOVERFLOW_LO);
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXVLANFRAMES_GB))
311962306a36Sopenharmony_ci		stats->rxvlanframes_gb +=
312062306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXVLANFRAMES_GB_LO);
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXWATCHDOGERROR))
312362306a36Sopenharmony_ci		stats->rxwatchdogerror +=
312462306a36Sopenharmony_ci			xgbe_mmc_read(pdata, MMC_RXWATCHDOGERROR);
312562306a36Sopenharmony_ci}
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_cistatic void xgbe_read_mmc_stats(struct xgbe_prv_data *pdata)
312862306a36Sopenharmony_ci{
312962306a36Sopenharmony_ci	struct xgbe_mmc_stats *stats = &pdata->mmc_stats;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	/* Freeze counters */
313262306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MMC_CR, MCF, 1);
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	stats->txoctetcount_gb +=
313562306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXOCTETCOUNT_GB_LO);
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_ci	stats->txframecount_gb +=
313862306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXFRAMECOUNT_GB_LO);
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci	stats->txbroadcastframes_g +=
314162306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXBROADCASTFRAMES_G_LO);
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_ci	stats->txmulticastframes_g +=
314462306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXMULTICASTFRAMES_G_LO);
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	stats->tx64octets_gb +=
314762306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TX64OCTETS_GB_LO);
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	stats->tx65to127octets_gb +=
315062306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TX65TO127OCTETS_GB_LO);
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	stats->tx128to255octets_gb +=
315362306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TX128TO255OCTETS_GB_LO);
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	stats->tx256to511octets_gb +=
315662306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TX256TO511OCTETS_GB_LO);
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	stats->tx512to1023octets_gb +=
315962306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TX512TO1023OCTETS_GB_LO);
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci	stats->tx1024tomaxoctets_gb +=
316262306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TX1024TOMAXOCTETS_GB_LO);
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci	stats->txunicastframes_gb +=
316562306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXUNICASTFRAMES_GB_LO);
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci	stats->txmulticastframes_gb +=
316862306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXMULTICASTFRAMES_GB_LO);
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_ci	stats->txbroadcastframes_g +=
317162306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXBROADCASTFRAMES_GB_LO);
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci	stats->txunderflowerror +=
317462306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXUNDERFLOWERROR_LO);
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci	stats->txoctetcount_g +=
317762306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXOCTETCOUNT_G_LO);
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci	stats->txframecount_g +=
318062306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXFRAMECOUNT_G_LO);
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	stats->txpauseframes +=
318362306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXPAUSEFRAMES_LO);
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	stats->txvlanframes_g +=
318662306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_TXVLANFRAMES_G_LO);
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	stats->rxframecount_gb +=
318962306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXFRAMECOUNT_GB_LO);
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	stats->rxoctetcount_gb +=
319262306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXOCTETCOUNT_GB_LO);
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	stats->rxoctetcount_g +=
319562306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXOCTETCOUNT_G_LO);
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci	stats->rxbroadcastframes_g +=
319862306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXBROADCASTFRAMES_G_LO);
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_ci	stats->rxmulticastframes_g +=
320162306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXMULTICASTFRAMES_G_LO);
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci	stats->rxcrcerror +=
320462306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXCRCERROR_LO);
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	stats->rxrunterror +=
320762306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXRUNTERROR);
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	stats->rxjabbererror +=
321062306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXJABBERERROR);
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci	stats->rxundersize_g +=
321362306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXUNDERSIZE_G);
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	stats->rxoversize_g +=
321662306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXOVERSIZE_G);
321762306a36Sopenharmony_ci
321862306a36Sopenharmony_ci	stats->rx64octets_gb +=
321962306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RX64OCTETS_GB_LO);
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	stats->rx65to127octets_gb +=
322262306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RX65TO127OCTETS_GB_LO);
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	stats->rx128to255octets_gb +=
322562306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RX128TO255OCTETS_GB_LO);
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci	stats->rx256to511octets_gb +=
322862306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RX256TO511OCTETS_GB_LO);
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	stats->rx512to1023octets_gb +=
323162306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RX512TO1023OCTETS_GB_LO);
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	stats->rx1024tomaxoctets_gb +=
323462306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RX1024TOMAXOCTETS_GB_LO);
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci	stats->rxunicastframes_g +=
323762306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXUNICASTFRAMES_G_LO);
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci	stats->rxlengtherror +=
324062306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXLENGTHERROR_LO);
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci	stats->rxoutofrangetype +=
324362306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXOUTOFRANGETYPE_LO);
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_ci	stats->rxpauseframes +=
324662306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXPAUSEFRAMES_LO);
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci	stats->rxfifooverflow +=
324962306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXFIFOOVERFLOW_LO);
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	stats->rxvlanframes_gb +=
325262306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXVLANFRAMES_GB_LO);
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	stats->rxwatchdogerror +=
325562306a36Sopenharmony_ci		xgbe_mmc_read(pdata, MMC_RXWATCHDOGERROR);
325662306a36Sopenharmony_ci
325762306a36Sopenharmony_ci	/* Un-freeze counters */
325862306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MMC_CR, MCF, 0);
325962306a36Sopenharmony_ci}
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_cistatic void xgbe_config_mmc(struct xgbe_prv_data *pdata)
326262306a36Sopenharmony_ci{
326362306a36Sopenharmony_ci	/* Set counters to reset on read */
326462306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MMC_CR, ROR, 1);
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	/* Reset the counters */
326762306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MMC_CR, CR, 1);
326862306a36Sopenharmony_ci}
326962306a36Sopenharmony_ci
327062306a36Sopenharmony_cistatic void xgbe_txq_prepare_tx_stop(struct xgbe_prv_data *pdata,
327162306a36Sopenharmony_ci				     unsigned int queue)
327262306a36Sopenharmony_ci{
327362306a36Sopenharmony_ci	unsigned int tx_status;
327462306a36Sopenharmony_ci	unsigned long tx_timeout;
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	/* The Tx engine cannot be stopped if it is actively processing
327762306a36Sopenharmony_ci	 * packets. Wait for the Tx queue to empty the Tx fifo.  Don't
327862306a36Sopenharmony_ci	 * wait forever though...
327962306a36Sopenharmony_ci	 */
328062306a36Sopenharmony_ci	tx_timeout = jiffies + (XGBE_DMA_STOP_TIMEOUT * HZ);
328162306a36Sopenharmony_ci	while (time_before(jiffies, tx_timeout)) {
328262306a36Sopenharmony_ci		tx_status = XGMAC_MTL_IOREAD(pdata, queue, MTL_Q_TQDR);
328362306a36Sopenharmony_ci		if ((XGMAC_GET_BITS(tx_status, MTL_Q_TQDR, TRCSTS) != 1) &&
328462306a36Sopenharmony_ci		    (XGMAC_GET_BITS(tx_status, MTL_Q_TQDR, TXQSTS) == 0))
328562306a36Sopenharmony_ci			break;
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci		usleep_range(500, 1000);
328862306a36Sopenharmony_ci	}
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	if (!time_before(jiffies, tx_timeout))
329162306a36Sopenharmony_ci		netdev_info(pdata->netdev,
329262306a36Sopenharmony_ci			    "timed out waiting for Tx queue %u to empty\n",
329362306a36Sopenharmony_ci			    queue);
329462306a36Sopenharmony_ci}
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_cistatic void xgbe_prepare_tx_stop(struct xgbe_prv_data *pdata,
329762306a36Sopenharmony_ci				 unsigned int queue)
329862306a36Sopenharmony_ci{
329962306a36Sopenharmony_ci	unsigned int tx_dsr, tx_pos, tx_qidx;
330062306a36Sopenharmony_ci	unsigned int tx_status;
330162306a36Sopenharmony_ci	unsigned long tx_timeout;
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_ci	if (XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER) > 0x20)
330462306a36Sopenharmony_ci		return xgbe_txq_prepare_tx_stop(pdata, queue);
330562306a36Sopenharmony_ci
330662306a36Sopenharmony_ci	/* Calculate the status register to read and the position within */
330762306a36Sopenharmony_ci	if (queue < DMA_DSRX_FIRST_QUEUE) {
330862306a36Sopenharmony_ci		tx_dsr = DMA_DSR0;
330962306a36Sopenharmony_ci		tx_pos = (queue * DMA_DSR_Q_WIDTH) + DMA_DSR0_TPS_START;
331062306a36Sopenharmony_ci	} else {
331162306a36Sopenharmony_ci		tx_qidx = queue - DMA_DSRX_FIRST_QUEUE;
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci		tx_dsr = DMA_DSR1 + ((tx_qidx / DMA_DSRX_QPR) * DMA_DSRX_INC);
331462306a36Sopenharmony_ci		tx_pos = ((tx_qidx % DMA_DSRX_QPR) * DMA_DSR_Q_WIDTH) +
331562306a36Sopenharmony_ci			 DMA_DSRX_TPS_START;
331662306a36Sopenharmony_ci	}
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	/* The Tx engine cannot be stopped if it is actively processing
331962306a36Sopenharmony_ci	 * descriptors. Wait for the Tx engine to enter the stopped or
332062306a36Sopenharmony_ci	 * suspended state.  Don't wait forever though...
332162306a36Sopenharmony_ci	 */
332262306a36Sopenharmony_ci	tx_timeout = jiffies + (XGBE_DMA_STOP_TIMEOUT * HZ);
332362306a36Sopenharmony_ci	while (time_before(jiffies, tx_timeout)) {
332462306a36Sopenharmony_ci		tx_status = XGMAC_IOREAD(pdata, tx_dsr);
332562306a36Sopenharmony_ci		tx_status = GET_BITS(tx_status, tx_pos, DMA_DSR_TPS_WIDTH);
332662306a36Sopenharmony_ci		if ((tx_status == DMA_TPS_STOPPED) ||
332762306a36Sopenharmony_ci		    (tx_status == DMA_TPS_SUSPENDED))
332862306a36Sopenharmony_ci			break;
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ci		usleep_range(500, 1000);
333162306a36Sopenharmony_ci	}
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	if (!time_before(jiffies, tx_timeout))
333462306a36Sopenharmony_ci		netdev_info(pdata->netdev,
333562306a36Sopenharmony_ci			    "timed out waiting for Tx DMA channel %u to stop\n",
333662306a36Sopenharmony_ci			    queue);
333762306a36Sopenharmony_ci}
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_cistatic void xgbe_enable_tx(struct xgbe_prv_data *pdata)
334062306a36Sopenharmony_ci{
334162306a36Sopenharmony_ci	unsigned int i;
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci	/* Enable each Tx DMA channel */
334462306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
334562306a36Sopenharmony_ci		if (!pdata->channel[i]->tx_ring)
334662306a36Sopenharmony_ci			break;
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, ST, 1);
334962306a36Sopenharmony_ci	}
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci	/* Enable each Tx queue */
335262306a36Sopenharmony_ci	for (i = 0; i < pdata->tx_q_count; i++)
335362306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN,
335462306a36Sopenharmony_ci				       MTL_Q_ENABLED);
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci	/* Enable MAC Tx */
335762306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 1);
335862306a36Sopenharmony_ci}
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_cistatic void xgbe_disable_tx(struct xgbe_prv_data *pdata)
336162306a36Sopenharmony_ci{
336262306a36Sopenharmony_ci	unsigned int i;
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	/* Prepare for Tx DMA channel stop */
336562306a36Sopenharmony_ci	for (i = 0; i < pdata->tx_q_count; i++)
336662306a36Sopenharmony_ci		xgbe_prepare_tx_stop(pdata, i);
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	/* Disable MAC Tx */
336962306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0);
337062306a36Sopenharmony_ci
337162306a36Sopenharmony_ci	/* Disable each Tx queue */
337262306a36Sopenharmony_ci	for (i = 0; i < pdata->tx_q_count; i++)
337362306a36Sopenharmony_ci		XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN, 0);
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	/* Disable each Tx DMA channel */
337662306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
337762306a36Sopenharmony_ci		if (!pdata->channel[i]->tx_ring)
337862306a36Sopenharmony_ci			break;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, ST, 0);
338162306a36Sopenharmony_ci	}
338262306a36Sopenharmony_ci}
338362306a36Sopenharmony_ci
338462306a36Sopenharmony_cistatic void xgbe_prepare_rx_stop(struct xgbe_prv_data *pdata,
338562306a36Sopenharmony_ci				 unsigned int queue)
338662306a36Sopenharmony_ci{
338762306a36Sopenharmony_ci	unsigned int rx_status;
338862306a36Sopenharmony_ci	unsigned long rx_timeout;
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci	/* The Rx engine cannot be stopped if it is actively processing
339162306a36Sopenharmony_ci	 * packets. Wait for the Rx queue to empty the Rx fifo.  Don't
339262306a36Sopenharmony_ci	 * wait forever though...
339362306a36Sopenharmony_ci	 */
339462306a36Sopenharmony_ci	rx_timeout = jiffies + (XGBE_DMA_STOP_TIMEOUT * HZ);
339562306a36Sopenharmony_ci	while (time_before(jiffies, rx_timeout)) {
339662306a36Sopenharmony_ci		rx_status = XGMAC_MTL_IOREAD(pdata, queue, MTL_Q_RQDR);
339762306a36Sopenharmony_ci		if ((XGMAC_GET_BITS(rx_status, MTL_Q_RQDR, PRXQ) == 0) &&
339862306a36Sopenharmony_ci		    (XGMAC_GET_BITS(rx_status, MTL_Q_RQDR, RXQSTS) == 0))
339962306a36Sopenharmony_ci			break;
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci		usleep_range(500, 1000);
340262306a36Sopenharmony_ci	}
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_ci	if (!time_before(jiffies, rx_timeout))
340562306a36Sopenharmony_ci		netdev_info(pdata->netdev,
340662306a36Sopenharmony_ci			    "timed out waiting for Rx queue %u to empty\n",
340762306a36Sopenharmony_ci			    queue);
340862306a36Sopenharmony_ci}
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_cistatic void xgbe_enable_rx(struct xgbe_prv_data *pdata)
341162306a36Sopenharmony_ci{
341262306a36Sopenharmony_ci	unsigned int reg_val, i;
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci	/* Enable each Rx DMA channel */
341562306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
341662306a36Sopenharmony_ci		if (!pdata->channel[i]->rx_ring)
341762306a36Sopenharmony_ci			break;
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, SR, 1);
342062306a36Sopenharmony_ci	}
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci	/* Enable each Rx queue */
342362306a36Sopenharmony_ci	reg_val = 0;
342462306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count; i++)
342562306a36Sopenharmony_ci		reg_val |= (0x02 << (i << 1));
342662306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_RQC0R, reg_val);
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	/* Enable MAC Rx */
342962306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, DCRCC, 1);
343062306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, CST, 1);
343162306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, ACS, 1);
343262306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, RE, 1);
343362306a36Sopenharmony_ci}
343462306a36Sopenharmony_ci
343562306a36Sopenharmony_cistatic void xgbe_disable_rx(struct xgbe_prv_data *pdata)
343662306a36Sopenharmony_ci{
343762306a36Sopenharmony_ci	unsigned int i;
343862306a36Sopenharmony_ci
343962306a36Sopenharmony_ci	/* Disable MAC Rx */
344062306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, DCRCC, 0);
344162306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, CST, 0);
344262306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, ACS, 0);
344362306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_RCR, RE, 0);
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	/* Prepare for Rx DMA channel stop */
344662306a36Sopenharmony_ci	for (i = 0; i < pdata->rx_q_count; i++)
344762306a36Sopenharmony_ci		xgbe_prepare_rx_stop(pdata, i);
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	/* Disable each Rx queue */
345062306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_RQC0R, 0);
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	/* Disable each Rx DMA channel */
345362306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
345462306a36Sopenharmony_ci		if (!pdata->channel[i]->rx_ring)
345562306a36Sopenharmony_ci			break;
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, SR, 0);
345862306a36Sopenharmony_ci	}
345962306a36Sopenharmony_ci}
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_cistatic void xgbe_powerup_tx(struct xgbe_prv_data *pdata)
346262306a36Sopenharmony_ci{
346362306a36Sopenharmony_ci	unsigned int i;
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ci	/* Enable each Tx DMA channel */
346662306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
346762306a36Sopenharmony_ci		if (!pdata->channel[i]->tx_ring)
346862306a36Sopenharmony_ci			break;
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, ST, 1);
347162306a36Sopenharmony_ci	}
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_ci	/* Enable MAC Tx */
347462306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 1);
347562306a36Sopenharmony_ci}
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_cistatic void xgbe_powerdown_tx(struct xgbe_prv_data *pdata)
347862306a36Sopenharmony_ci{
347962306a36Sopenharmony_ci	unsigned int i;
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_ci	/* Prepare for Tx DMA channel stop */
348262306a36Sopenharmony_ci	for (i = 0; i < pdata->tx_q_count; i++)
348362306a36Sopenharmony_ci		xgbe_prepare_tx_stop(pdata, i);
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	/* Disable MAC Tx */
348662306a36Sopenharmony_ci	XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0);
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_ci	/* Disable each Tx DMA channel */
348962306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
349062306a36Sopenharmony_ci		if (!pdata->channel[i]->tx_ring)
349162306a36Sopenharmony_ci			break;
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, ST, 0);
349462306a36Sopenharmony_ci	}
349562306a36Sopenharmony_ci}
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_cistatic void xgbe_powerup_rx(struct xgbe_prv_data *pdata)
349862306a36Sopenharmony_ci{
349962306a36Sopenharmony_ci	unsigned int i;
350062306a36Sopenharmony_ci
350162306a36Sopenharmony_ci	/* Enable each Rx DMA channel */
350262306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
350362306a36Sopenharmony_ci		if (!pdata->channel[i]->rx_ring)
350462306a36Sopenharmony_ci			break;
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, SR, 1);
350762306a36Sopenharmony_ci	}
350862306a36Sopenharmony_ci}
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_cistatic void xgbe_powerdown_rx(struct xgbe_prv_data *pdata)
351162306a36Sopenharmony_ci{
351262306a36Sopenharmony_ci	unsigned int i;
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci	/* Disable each Rx DMA channel */
351562306a36Sopenharmony_ci	for (i = 0; i < pdata->channel_count; i++) {
351662306a36Sopenharmony_ci		if (!pdata->channel[i]->rx_ring)
351762306a36Sopenharmony_ci			break;
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci		XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, SR, 0);
352062306a36Sopenharmony_ci	}
352162306a36Sopenharmony_ci}
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_cistatic int xgbe_init(struct xgbe_prv_data *pdata)
352462306a36Sopenharmony_ci{
352562306a36Sopenharmony_ci	struct xgbe_desc_if *desc_if = &pdata->desc_if;
352662306a36Sopenharmony_ci	int ret;
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci	DBGPR("-->xgbe_init\n");
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci	/* Flush Tx queues */
353162306a36Sopenharmony_ci	ret = xgbe_flush_tx_queues(pdata);
353262306a36Sopenharmony_ci	if (ret) {
353362306a36Sopenharmony_ci		netdev_err(pdata->netdev, "error flushing TX queues\n");
353462306a36Sopenharmony_ci		return ret;
353562306a36Sopenharmony_ci	}
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_ci	/*
353862306a36Sopenharmony_ci	 * Initialize DMA related features
353962306a36Sopenharmony_ci	 */
354062306a36Sopenharmony_ci	xgbe_config_dma_bus(pdata);
354162306a36Sopenharmony_ci	xgbe_config_dma_cache(pdata);
354262306a36Sopenharmony_ci	xgbe_config_osp_mode(pdata);
354362306a36Sopenharmony_ci	xgbe_config_pbl_val(pdata);
354462306a36Sopenharmony_ci	xgbe_config_rx_coalesce(pdata);
354562306a36Sopenharmony_ci	xgbe_config_tx_coalesce(pdata);
354662306a36Sopenharmony_ci	xgbe_config_rx_buffer_size(pdata);
354762306a36Sopenharmony_ci	xgbe_config_tso_mode(pdata);
354862306a36Sopenharmony_ci	xgbe_config_sph_mode(pdata);
354962306a36Sopenharmony_ci	xgbe_config_rss(pdata);
355062306a36Sopenharmony_ci	desc_if->wrapper_tx_desc_init(pdata);
355162306a36Sopenharmony_ci	desc_if->wrapper_rx_desc_init(pdata);
355262306a36Sopenharmony_ci	xgbe_enable_dma_interrupts(pdata);
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci	/*
355562306a36Sopenharmony_ci	 * Initialize MTL related features
355662306a36Sopenharmony_ci	 */
355762306a36Sopenharmony_ci	xgbe_config_mtl_mode(pdata);
355862306a36Sopenharmony_ci	xgbe_config_queue_mapping(pdata);
355962306a36Sopenharmony_ci	xgbe_config_tsf_mode(pdata, pdata->tx_sf_mode);
356062306a36Sopenharmony_ci	xgbe_config_rsf_mode(pdata, pdata->rx_sf_mode);
356162306a36Sopenharmony_ci	xgbe_config_tx_threshold(pdata, pdata->tx_threshold);
356262306a36Sopenharmony_ci	xgbe_config_rx_threshold(pdata, pdata->rx_threshold);
356362306a36Sopenharmony_ci	xgbe_config_tx_fifo_size(pdata);
356462306a36Sopenharmony_ci	xgbe_config_rx_fifo_size(pdata);
356562306a36Sopenharmony_ci	/*TODO: Error Packet and undersized good Packet forwarding enable
356662306a36Sopenharmony_ci		(FEP and FUP)
356762306a36Sopenharmony_ci	 */
356862306a36Sopenharmony_ci	xgbe_config_dcb_tc(pdata);
356962306a36Sopenharmony_ci	xgbe_enable_mtl_interrupts(pdata);
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci	/*
357262306a36Sopenharmony_ci	 * Initialize MAC related features
357362306a36Sopenharmony_ci	 */
357462306a36Sopenharmony_ci	xgbe_config_mac_address(pdata);
357562306a36Sopenharmony_ci	xgbe_config_rx_mode(pdata);
357662306a36Sopenharmony_ci	xgbe_config_jumbo_enable(pdata);
357762306a36Sopenharmony_ci	xgbe_config_flow_control(pdata);
357862306a36Sopenharmony_ci	xgbe_config_mac_speed(pdata);
357962306a36Sopenharmony_ci	xgbe_config_checksum_offload(pdata);
358062306a36Sopenharmony_ci	xgbe_config_vlan_support(pdata);
358162306a36Sopenharmony_ci	xgbe_config_mmc(pdata);
358262306a36Sopenharmony_ci	xgbe_enable_mac_interrupts(pdata);
358362306a36Sopenharmony_ci
358462306a36Sopenharmony_ci	/*
358562306a36Sopenharmony_ci	 * Initialize ECC related features
358662306a36Sopenharmony_ci	 */
358762306a36Sopenharmony_ci	xgbe_enable_ecc_interrupts(pdata);
358862306a36Sopenharmony_ci
358962306a36Sopenharmony_ci	DBGPR("<--xgbe_init\n");
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	return 0;
359262306a36Sopenharmony_ci}
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_civoid xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
359562306a36Sopenharmony_ci{
359662306a36Sopenharmony_ci	DBGPR("-->xgbe_init_function_ptrs\n");
359762306a36Sopenharmony_ci
359862306a36Sopenharmony_ci	hw_if->tx_complete = xgbe_tx_complete;
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci	hw_if->set_mac_address = xgbe_set_mac_address;
360162306a36Sopenharmony_ci	hw_if->config_rx_mode = xgbe_config_rx_mode;
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci	hw_if->enable_rx_csum = xgbe_enable_rx_csum;
360462306a36Sopenharmony_ci	hw_if->disable_rx_csum = xgbe_disable_rx_csum;
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci	hw_if->enable_rx_vlan_stripping = xgbe_enable_rx_vlan_stripping;
360762306a36Sopenharmony_ci	hw_if->disable_rx_vlan_stripping = xgbe_disable_rx_vlan_stripping;
360862306a36Sopenharmony_ci	hw_if->enable_rx_vlan_filtering = xgbe_enable_rx_vlan_filtering;
360962306a36Sopenharmony_ci	hw_if->disable_rx_vlan_filtering = xgbe_disable_rx_vlan_filtering;
361062306a36Sopenharmony_ci	hw_if->update_vlan_hash_table = xgbe_update_vlan_hash_table;
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci	hw_if->read_mmd_regs = xgbe_read_mmd_regs;
361362306a36Sopenharmony_ci	hw_if->write_mmd_regs = xgbe_write_mmd_regs;
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci	hw_if->set_speed = xgbe_set_speed;
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	hw_if->set_ext_mii_mode = xgbe_set_ext_mii_mode;
361862306a36Sopenharmony_ci	hw_if->read_ext_mii_regs_c22 = xgbe_read_ext_mii_regs_c22;
361962306a36Sopenharmony_ci	hw_if->write_ext_mii_regs_c22 = xgbe_write_ext_mii_regs_c22;
362062306a36Sopenharmony_ci	hw_if->read_ext_mii_regs_c45 = xgbe_read_ext_mii_regs_c45;
362162306a36Sopenharmony_ci	hw_if->write_ext_mii_regs_c45 = xgbe_write_ext_mii_regs_c45;
362262306a36Sopenharmony_ci
362362306a36Sopenharmony_ci	hw_if->set_gpio = xgbe_set_gpio;
362462306a36Sopenharmony_ci	hw_if->clr_gpio = xgbe_clr_gpio;
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	hw_if->enable_tx = xgbe_enable_tx;
362762306a36Sopenharmony_ci	hw_if->disable_tx = xgbe_disable_tx;
362862306a36Sopenharmony_ci	hw_if->enable_rx = xgbe_enable_rx;
362962306a36Sopenharmony_ci	hw_if->disable_rx = xgbe_disable_rx;
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci	hw_if->powerup_tx = xgbe_powerup_tx;
363262306a36Sopenharmony_ci	hw_if->powerdown_tx = xgbe_powerdown_tx;
363362306a36Sopenharmony_ci	hw_if->powerup_rx = xgbe_powerup_rx;
363462306a36Sopenharmony_ci	hw_if->powerdown_rx = xgbe_powerdown_rx;
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_ci	hw_if->dev_xmit = xgbe_dev_xmit;
363762306a36Sopenharmony_ci	hw_if->dev_read = xgbe_dev_read;
363862306a36Sopenharmony_ci	hw_if->enable_int = xgbe_enable_int;
363962306a36Sopenharmony_ci	hw_if->disable_int = xgbe_disable_int;
364062306a36Sopenharmony_ci	hw_if->init = xgbe_init;
364162306a36Sopenharmony_ci	hw_if->exit = xgbe_exit;
364262306a36Sopenharmony_ci
364362306a36Sopenharmony_ci	/* Descriptor related Sequences have to be initialized here */
364462306a36Sopenharmony_ci	hw_if->tx_desc_init = xgbe_tx_desc_init;
364562306a36Sopenharmony_ci	hw_if->rx_desc_init = xgbe_rx_desc_init;
364662306a36Sopenharmony_ci	hw_if->tx_desc_reset = xgbe_tx_desc_reset;
364762306a36Sopenharmony_ci	hw_if->rx_desc_reset = xgbe_rx_desc_reset;
364862306a36Sopenharmony_ci	hw_if->is_last_desc = xgbe_is_last_desc;
364962306a36Sopenharmony_ci	hw_if->is_context_desc = xgbe_is_context_desc;
365062306a36Sopenharmony_ci	hw_if->tx_start_xmit = xgbe_tx_start_xmit;
365162306a36Sopenharmony_ci
365262306a36Sopenharmony_ci	/* For FLOW ctrl */
365362306a36Sopenharmony_ci	hw_if->config_tx_flow_control = xgbe_config_tx_flow_control;
365462306a36Sopenharmony_ci	hw_if->config_rx_flow_control = xgbe_config_rx_flow_control;
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	/* For RX coalescing */
365762306a36Sopenharmony_ci	hw_if->config_rx_coalesce = xgbe_config_rx_coalesce;
365862306a36Sopenharmony_ci	hw_if->config_tx_coalesce = xgbe_config_tx_coalesce;
365962306a36Sopenharmony_ci	hw_if->usec_to_riwt = xgbe_usec_to_riwt;
366062306a36Sopenharmony_ci	hw_if->riwt_to_usec = xgbe_riwt_to_usec;
366162306a36Sopenharmony_ci
366262306a36Sopenharmony_ci	/* For RX and TX threshold config */
366362306a36Sopenharmony_ci	hw_if->config_rx_threshold = xgbe_config_rx_threshold;
366462306a36Sopenharmony_ci	hw_if->config_tx_threshold = xgbe_config_tx_threshold;
366562306a36Sopenharmony_ci
366662306a36Sopenharmony_ci	/* For RX and TX Store and Forward Mode config */
366762306a36Sopenharmony_ci	hw_if->config_rsf_mode = xgbe_config_rsf_mode;
366862306a36Sopenharmony_ci	hw_if->config_tsf_mode = xgbe_config_tsf_mode;
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	/* For TX DMA Operating on Second Frame config */
367162306a36Sopenharmony_ci	hw_if->config_osp_mode = xgbe_config_osp_mode;
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_ci	/* For MMC statistics support */
367462306a36Sopenharmony_ci	hw_if->tx_mmc_int = xgbe_tx_mmc_int;
367562306a36Sopenharmony_ci	hw_if->rx_mmc_int = xgbe_rx_mmc_int;
367662306a36Sopenharmony_ci	hw_if->read_mmc_stats = xgbe_read_mmc_stats;
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ci	/* For PTP config */
367962306a36Sopenharmony_ci	hw_if->config_tstamp = xgbe_config_tstamp;
368062306a36Sopenharmony_ci	hw_if->update_tstamp_addend = xgbe_update_tstamp_addend;
368162306a36Sopenharmony_ci	hw_if->set_tstamp_time = xgbe_set_tstamp_time;
368262306a36Sopenharmony_ci	hw_if->get_tstamp_time = xgbe_get_tstamp_time;
368362306a36Sopenharmony_ci	hw_if->get_tx_tstamp = xgbe_get_tx_tstamp;
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci	/* For Data Center Bridging config */
368662306a36Sopenharmony_ci	hw_if->config_tc = xgbe_config_tc;
368762306a36Sopenharmony_ci	hw_if->config_dcb_tc = xgbe_config_dcb_tc;
368862306a36Sopenharmony_ci	hw_if->config_dcb_pfc = xgbe_config_dcb_pfc;
368962306a36Sopenharmony_ci
369062306a36Sopenharmony_ci	/* For Receive Side Scaling */
369162306a36Sopenharmony_ci	hw_if->enable_rss = xgbe_enable_rss;
369262306a36Sopenharmony_ci	hw_if->disable_rss = xgbe_disable_rss;
369362306a36Sopenharmony_ci	hw_if->set_rss_hash_key = xgbe_set_rss_hash_key;
369462306a36Sopenharmony_ci	hw_if->set_rss_lookup_table = xgbe_set_rss_lookup_table;
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci	/* For ECC */
369762306a36Sopenharmony_ci	hw_if->disable_ecc_ded = xgbe_disable_ecc_ded;
369862306a36Sopenharmony_ci	hw_if->disable_ecc_sec = xgbe_disable_ecc_sec;
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	/* For VXLAN */
370162306a36Sopenharmony_ci	hw_if->enable_vxlan = xgbe_enable_vxlan;
370262306a36Sopenharmony_ci	hw_if->disable_vxlan = xgbe_disable_vxlan;
370362306a36Sopenharmony_ci	hw_if->set_vxlan_id = xgbe_set_vxlan_id;
370462306a36Sopenharmony_ci
370562306a36Sopenharmony_ci	DBGPR("<--xgbe_init_function_ptrs\n");
370662306a36Sopenharmony_ci}
3707