18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c)  2018 Intel Corporation */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/delay.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "igc_hw.h"
78c2ecf20Sopenharmony_ci#include "igc_i225.h"
88c2ecf20Sopenharmony_ci#include "igc_mac.h"
98c2ecf20Sopenharmony_ci#include "igc_base.h"
108c2ecf20Sopenharmony_ci#include "igc.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/**
138c2ecf20Sopenharmony_ci * igc_reset_hw_base - Reset hardware
148c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * This resets the hardware into a known state.  This is a
178c2ecf20Sopenharmony_ci * function pointer entry point called by the api module.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_cistatic s32 igc_reset_hw_base(struct igc_hw *hw)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	s32 ret_val;
228c2ecf20Sopenharmony_ci	u32 ctrl;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	/* Prevent the PCI-E bus from sticking if there is no TLP connection
258c2ecf20Sopenharmony_ci	 * on the last TLP read/write transaction when MAC is reset.
268c2ecf20Sopenharmony_ci	 */
278c2ecf20Sopenharmony_ci	ret_val = igc_disable_pcie_master(hw);
288c2ecf20Sopenharmony_ci	if (ret_val)
298c2ecf20Sopenharmony_ci		hw_dbg("PCI-E Master disable polling has failed\n");
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	hw_dbg("Masking off all interrupts\n");
328c2ecf20Sopenharmony_ci	wr32(IGC_IMC, 0xffffffff);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	wr32(IGC_RCTL, 0);
358c2ecf20Sopenharmony_ci	wr32(IGC_TCTL, IGC_TCTL_PSP);
368c2ecf20Sopenharmony_ci	wrfl();
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	usleep_range(10000, 20000);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	ctrl = rd32(IGC_CTRL);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	hw_dbg("Issuing a global reset to MAC\n");
438c2ecf20Sopenharmony_ci	wr32(IGC_CTRL, ctrl | IGC_CTRL_DEV_RST);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	ret_val = igc_get_auto_rd_done(hw);
468c2ecf20Sopenharmony_ci	if (ret_val) {
478c2ecf20Sopenharmony_ci		/* When auto config read does not complete, do not
488c2ecf20Sopenharmony_ci		 * return with an error. This can happen in situations
498c2ecf20Sopenharmony_ci		 * where there is no eeprom and prevents getting link.
508c2ecf20Sopenharmony_ci		 */
518c2ecf20Sopenharmony_ci		hw_dbg("Auto Read Done did not complete\n");
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* Clear any pending interrupt events. */
558c2ecf20Sopenharmony_ci	wr32(IGC_IMC, 0xffffffff);
568c2ecf20Sopenharmony_ci	rd32(IGC_ICR);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return ret_val;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/**
628c2ecf20Sopenharmony_ci * igc_init_nvm_params_base - Init NVM func ptrs.
638c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
648c2ecf20Sopenharmony_ci */
658c2ecf20Sopenharmony_cistatic s32 igc_init_nvm_params_base(struct igc_hw *hw)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	struct igc_nvm_info *nvm = &hw->nvm;
688c2ecf20Sopenharmony_ci	u32 eecd = rd32(IGC_EECD);
698c2ecf20Sopenharmony_ci	u16 size;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>
728c2ecf20Sopenharmony_ci		     IGC_EECD_SIZE_EX_SHIFT);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* Added to a constant, "size" becomes the left-shift value
758c2ecf20Sopenharmony_ci	 * for setting word_size.
768c2ecf20Sopenharmony_ci	 */
778c2ecf20Sopenharmony_ci	size += NVM_WORD_SIZE_BASE_SHIFT;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/* Just in case size is out of range, cap it to the largest
808c2ecf20Sopenharmony_ci	 * EEPROM size supported
818c2ecf20Sopenharmony_ci	 */
828c2ecf20Sopenharmony_ci	if (size > 15)
838c2ecf20Sopenharmony_ci		size = 15;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	nvm->type = igc_nvm_eeprom_spi;
868c2ecf20Sopenharmony_ci	nvm->word_size = BIT(size);
878c2ecf20Sopenharmony_ci	nvm->opcode_bits = 8;
888c2ecf20Sopenharmony_ci	nvm->delay_usec = 1;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8;
918c2ecf20Sopenharmony_ci	nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ?
928c2ecf20Sopenharmony_ci			    16 : 8;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (nvm->word_size == BIT(15))
958c2ecf20Sopenharmony_ci		nvm->page_size = 128;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/**
1018c2ecf20Sopenharmony_ci * igc_setup_copper_link_base - Configure copper link settings
1028c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * Configures the link for auto-neg or forced speed and duplex.  Then we check
1058c2ecf20Sopenharmony_ci * for link, once link is established calls to configure collision distance
1068c2ecf20Sopenharmony_ci * and flow control are called.
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_cistatic s32 igc_setup_copper_link_base(struct igc_hw *hw)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	s32  ret_val = 0;
1118c2ecf20Sopenharmony_ci	u32 ctrl;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	ctrl = rd32(IGC_CTRL);
1148c2ecf20Sopenharmony_ci	ctrl |= IGC_CTRL_SLU;
1158c2ecf20Sopenharmony_ci	ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
1168c2ecf20Sopenharmony_ci	wr32(IGC_CTRL, ctrl);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	ret_val = igc_setup_copper_link(hw);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return ret_val;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/**
1248c2ecf20Sopenharmony_ci * igc_init_mac_params_base - Init MAC func ptrs.
1258c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
1268c2ecf20Sopenharmony_ci */
1278c2ecf20Sopenharmony_cistatic s32 igc_init_mac_params_base(struct igc_hw *hw)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct igc_dev_spec_base *dev_spec = &hw->dev_spec._base;
1308c2ecf20Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* Set mta register count */
1338c2ecf20Sopenharmony_ci	mac->mta_reg_count = 128;
1348c2ecf20Sopenharmony_ci	mac->rar_entry_count = IGC_RAR_ENTRIES;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* reset */
1378c2ecf20Sopenharmony_ci	mac->ops.reset_hw = igc_reset_hw_base;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
1408c2ecf20Sopenharmony_ci	mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* Allow a single clear of the SW semaphore on I225 */
1438c2ecf20Sopenharmony_ci	if (mac->type == igc_i225)
1448c2ecf20Sopenharmony_ci		dev_spec->clear_semaphore_once = true;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* physical interface link setup */
1478c2ecf20Sopenharmony_ci	mac->ops.setup_physical_interface = igc_setup_copper_link_base;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	return 0;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/**
1538c2ecf20Sopenharmony_ci * igc_init_phy_params_base - Init PHY func ptrs.
1548c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
1558c2ecf20Sopenharmony_ci */
1568c2ecf20Sopenharmony_cistatic s32 igc_init_phy_params_base(struct igc_hw *hw)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct igc_phy_info *phy = &hw->phy;
1598c2ecf20Sopenharmony_ci	s32 ret_val = 0;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (hw->phy.media_type != igc_media_type_copper) {
1628c2ecf20Sopenharmony_ci		phy->type = igc_phy_none;
1638c2ecf20Sopenharmony_ci		goto out;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;
1678c2ecf20Sopenharmony_ci	phy->reset_delay_us	= 100;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* set lan id */
1708c2ecf20Sopenharmony_ci	hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>
1718c2ecf20Sopenharmony_ci			IGC_STATUS_FUNC_SHIFT;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* Make sure the PHY is in a good state. Several people have reported
1748c2ecf20Sopenharmony_ci	 * firmware leaving the PHY's page select register set to something
1758c2ecf20Sopenharmony_ci	 * other than the default of zero, which causes the PHY ID read to
1768c2ecf20Sopenharmony_ci	 * access something other than the intended register.
1778c2ecf20Sopenharmony_ci	 */
1788c2ecf20Sopenharmony_ci	ret_val = hw->phy.ops.reset(hw);
1798c2ecf20Sopenharmony_ci	if (ret_val) {
1808c2ecf20Sopenharmony_ci		hw_dbg("Error resetting the PHY\n");
1818c2ecf20Sopenharmony_ci		goto out;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	ret_val = igc_get_phy_id(hw);
1858c2ecf20Sopenharmony_ci	if (ret_val)
1868c2ecf20Sopenharmony_ci		return ret_val;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	igc_check_for_copper_link(hw);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	phy->type = igc_phy_i225;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ciout:
1938c2ecf20Sopenharmony_ci	return ret_val;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic s32 igc_get_invariants_base(struct igc_hw *hw)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
1998c2ecf20Sopenharmony_ci	s32 ret_val = 0;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	switch (hw->device_id) {
2028c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I225_LM:
2038c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I225_V:
2048c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I225_I:
2058c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I220_V:
2068c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I225_K:
2078c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I225_K2:
2088c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I225_LMVP:
2098c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I225_IT:
2108c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I226_LM:
2118c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I226_V:
2128c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I226_IT:
2138c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I221_V:
2148c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I226_BLANK_NVM:
2158c2ecf20Sopenharmony_ci	case IGC_DEV_ID_I225_BLANK_NVM:
2168c2ecf20Sopenharmony_ci		mac->type = igc_i225;
2178c2ecf20Sopenharmony_ci		break;
2188c2ecf20Sopenharmony_ci	default:
2198c2ecf20Sopenharmony_ci		return -IGC_ERR_MAC_INIT;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	hw->phy.media_type = igc_media_type_copper;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* mac initialization and operations */
2258c2ecf20Sopenharmony_ci	ret_val = igc_init_mac_params_base(hw);
2268c2ecf20Sopenharmony_ci	if (ret_val)
2278c2ecf20Sopenharmony_ci		goto out;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* NVM initialization */
2308c2ecf20Sopenharmony_ci	ret_val = igc_init_nvm_params_base(hw);
2318c2ecf20Sopenharmony_ci	switch (hw->mac.type) {
2328c2ecf20Sopenharmony_ci	case igc_i225:
2338c2ecf20Sopenharmony_ci		ret_val = igc_init_nvm_params_i225(hw);
2348c2ecf20Sopenharmony_ci		break;
2358c2ecf20Sopenharmony_ci	default:
2368c2ecf20Sopenharmony_ci		break;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* setup PHY parameters */
2408c2ecf20Sopenharmony_ci	ret_val = igc_init_phy_params_base(hw);
2418c2ecf20Sopenharmony_ci	if (ret_val)
2428c2ecf20Sopenharmony_ci		goto out;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ciout:
2458c2ecf20Sopenharmony_ci	return ret_val;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/**
2498c2ecf20Sopenharmony_ci * igc_acquire_phy_base - Acquire rights to access PHY
2508c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * Acquire access rights to the correct PHY.  This is a
2538c2ecf20Sopenharmony_ci * function pointer entry point called by the api module.
2548c2ecf20Sopenharmony_ci */
2558c2ecf20Sopenharmony_cistatic s32 igc_acquire_phy_base(struct igc_hw *hw)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	u16 mask = IGC_SWFW_PHY0_SM;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return hw->mac.ops.acquire_swfw_sync(hw, mask);
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci/**
2638c2ecf20Sopenharmony_ci * igc_release_phy_base - Release rights to access PHY
2648c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
2658c2ecf20Sopenharmony_ci *
2668c2ecf20Sopenharmony_ci * A wrapper to release access rights to the correct PHY.  This is a
2678c2ecf20Sopenharmony_ci * function pointer entry point called by the api module.
2688c2ecf20Sopenharmony_ci */
2698c2ecf20Sopenharmony_cistatic void igc_release_phy_base(struct igc_hw *hw)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	u16 mask = IGC_SWFW_PHY0_SM;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	hw->mac.ops.release_swfw_sync(hw, mask);
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci/**
2778c2ecf20Sopenharmony_ci * igc_init_hw_base - Initialize hardware
2788c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
2798c2ecf20Sopenharmony_ci *
2808c2ecf20Sopenharmony_ci * This inits the hardware readying it for operation.
2818c2ecf20Sopenharmony_ci */
2828c2ecf20Sopenharmony_cistatic s32 igc_init_hw_base(struct igc_hw *hw)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
2858c2ecf20Sopenharmony_ci	u16 i, rar_count = mac->rar_entry_count;
2868c2ecf20Sopenharmony_ci	s32 ret_val = 0;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/* Setup the receive address */
2898c2ecf20Sopenharmony_ci	igc_init_rx_addrs(hw, rar_count);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* Zero out the Multicast HASH table */
2928c2ecf20Sopenharmony_ci	hw_dbg("Zeroing the MTA\n");
2938c2ecf20Sopenharmony_ci	for (i = 0; i < mac->mta_reg_count; i++)
2948c2ecf20Sopenharmony_ci		array_wr32(IGC_MTA, i, 0);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* Zero out the Unicast HASH table */
2978c2ecf20Sopenharmony_ci	hw_dbg("Zeroing the UTA\n");
2988c2ecf20Sopenharmony_ci	for (i = 0; i < mac->uta_reg_count; i++)
2998c2ecf20Sopenharmony_ci		array_wr32(IGC_UTA, i, 0);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* Setup link and flow control */
3028c2ecf20Sopenharmony_ci	ret_val = igc_setup_link(hw);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* Clear all of the statistics registers (clear on read).  It is
3058c2ecf20Sopenharmony_ci	 * important that we do this after we have tried to establish link
3068c2ecf20Sopenharmony_ci	 * because the symbol error count will increment wildly if there
3078c2ecf20Sopenharmony_ci	 * is no link.
3088c2ecf20Sopenharmony_ci	 */
3098c2ecf20Sopenharmony_ci	igc_clear_hw_cntrs_base(hw);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	return ret_val;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci/**
3158c2ecf20Sopenharmony_ci * igc_power_down_phy_copper_base - Remove link during PHY power down
3168c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
3178c2ecf20Sopenharmony_ci *
3188c2ecf20Sopenharmony_ci * In the case of a PHY power down to save power, or to turn off link during a
3198c2ecf20Sopenharmony_ci * driver unload, or wake on lan is not enabled, remove the link.
3208c2ecf20Sopenharmony_ci */
3218c2ecf20Sopenharmony_civoid igc_power_down_phy_copper_base(struct igc_hw *hw)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	/* If the management interface is not enabled, then power down */
3248c2ecf20Sopenharmony_ci	if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw)))
3258c2ecf20Sopenharmony_ci		igc_power_down_phy_copper(hw);
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/**
3298c2ecf20Sopenharmony_ci * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable
3308c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure
3318c2ecf20Sopenharmony_ci *
3328c2ecf20Sopenharmony_ci * After Rx enable, if manageability is enabled then there is likely some
3338c2ecf20Sopenharmony_ci * bad data at the start of the fifo and possibly in the DMA fifo.  This
3348c2ecf20Sopenharmony_ci * function clears the fifos and flushes any packets that came in as rx was
3358c2ecf20Sopenharmony_ci * being enabled.
3368c2ecf20Sopenharmony_ci */
3378c2ecf20Sopenharmony_civoid igc_rx_fifo_flush_base(struct igc_hw *hw)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
3408c2ecf20Sopenharmony_ci	int i, ms_wait;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* disable IPv6 options as per hardware errata */
3438c2ecf20Sopenharmony_ci	rfctl = rd32(IGC_RFCTL);
3448c2ecf20Sopenharmony_ci	rfctl |= IGC_RFCTL_IPV6_EX_DIS;
3458c2ecf20Sopenharmony_ci	wr32(IGC_RFCTL, rfctl);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (!(rd32(IGC_MANC) & IGC_MANC_RCV_TCO_EN))
3488c2ecf20Sopenharmony_ci		return;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/* Disable all Rx queues */
3518c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
3528c2ecf20Sopenharmony_ci		rxdctl[i] = rd32(IGC_RXDCTL(i));
3538c2ecf20Sopenharmony_ci		wr32(IGC_RXDCTL(i),
3548c2ecf20Sopenharmony_ci		     rxdctl[i] & ~IGC_RXDCTL_QUEUE_ENABLE);
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci	/* Poll all queues to verify they have shut down */
3578c2ecf20Sopenharmony_ci	for (ms_wait = 0; ms_wait < 10; ms_wait++) {
3588c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
3598c2ecf20Sopenharmony_ci		rx_enabled = 0;
3608c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++)
3618c2ecf20Sopenharmony_ci			rx_enabled |= rd32(IGC_RXDCTL(i));
3628c2ecf20Sopenharmony_ci		if (!(rx_enabled & IGC_RXDCTL_QUEUE_ENABLE))
3638c2ecf20Sopenharmony_ci			break;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (ms_wait == 10)
3678c2ecf20Sopenharmony_ci		hw_dbg("Queue disable timed out after 10ms\n");
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
3708c2ecf20Sopenharmony_ci	 * incoming packets are rejected.  Set enable and wait 2ms so that
3718c2ecf20Sopenharmony_ci	 * any packet that was coming in as RCTL.EN was set is flushed
3728c2ecf20Sopenharmony_ci	 */
3738c2ecf20Sopenharmony_ci	wr32(IGC_RFCTL, rfctl & ~IGC_RFCTL_LEF);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	rlpml = rd32(IGC_RLPML);
3768c2ecf20Sopenharmony_ci	wr32(IGC_RLPML, 0);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	rctl = rd32(IGC_RCTL);
3798c2ecf20Sopenharmony_ci	temp_rctl = rctl & ~(IGC_RCTL_EN | IGC_RCTL_SBP);
3808c2ecf20Sopenharmony_ci	temp_rctl |= IGC_RCTL_LPE;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	wr32(IGC_RCTL, temp_rctl);
3838c2ecf20Sopenharmony_ci	wr32(IGC_RCTL, temp_rctl | IGC_RCTL_EN);
3848c2ecf20Sopenharmony_ci	wrfl();
3858c2ecf20Sopenharmony_ci	usleep_range(2000, 3000);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* Enable Rx queues that were previously enabled and restore our
3888c2ecf20Sopenharmony_ci	 * previous state
3898c2ecf20Sopenharmony_ci	 */
3908c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
3918c2ecf20Sopenharmony_ci		wr32(IGC_RXDCTL(i), rxdctl[i]);
3928c2ecf20Sopenharmony_ci	wr32(IGC_RCTL, rctl);
3938c2ecf20Sopenharmony_ci	wrfl();
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	wr32(IGC_RLPML, rlpml);
3968c2ecf20Sopenharmony_ci	wr32(IGC_RFCTL, rfctl);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/* Flush receive errors generated by workaround */
3998c2ecf20Sopenharmony_ci	rd32(IGC_ROC);
4008c2ecf20Sopenharmony_ci	rd32(IGC_RNBC);
4018c2ecf20Sopenharmony_ci	rd32(IGC_MPC);
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic struct igc_mac_operations igc_mac_ops_base = {
4058c2ecf20Sopenharmony_ci	.init_hw		= igc_init_hw_base,
4068c2ecf20Sopenharmony_ci	.check_for_link		= igc_check_for_copper_link,
4078c2ecf20Sopenharmony_ci	.rar_set		= igc_rar_set,
4088c2ecf20Sopenharmony_ci	.read_mac_addr		= igc_read_mac_addr,
4098c2ecf20Sopenharmony_ci	.get_speed_and_duplex	= igc_get_speed_and_duplex_copper,
4108c2ecf20Sopenharmony_ci};
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic const struct igc_phy_operations igc_phy_ops_base = {
4138c2ecf20Sopenharmony_ci	.acquire		= igc_acquire_phy_base,
4148c2ecf20Sopenharmony_ci	.release		= igc_release_phy_base,
4158c2ecf20Sopenharmony_ci	.reset			= igc_phy_hw_reset,
4168c2ecf20Sopenharmony_ci	.read_reg		= igc_read_phy_reg_gpy,
4178c2ecf20Sopenharmony_ci	.write_reg		= igc_write_phy_reg_gpy,
4188c2ecf20Sopenharmony_ci};
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ciconst struct igc_info igc_base_info = {
4218c2ecf20Sopenharmony_ci	.get_invariants		= igc_get_invariants_base,
4228c2ecf20Sopenharmony_ci	.mac_ops		= &igc_mac_ops_base,
4238c2ecf20Sopenharmony_ci	.phy_ops		= &igc_phy_ops_base,
4248c2ecf20Sopenharmony_ci};
425