162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c)  2018 Intel Corporation */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/delay.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "igc_hw.h"
762306a36Sopenharmony_ci#include "igc_i225.h"
862306a36Sopenharmony_ci#include "igc_mac.h"
962306a36Sopenharmony_ci#include "igc_base.h"
1062306a36Sopenharmony_ci#include "igc.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/**
1362306a36Sopenharmony_ci * igc_reset_hw_base - Reset hardware
1462306a36Sopenharmony_ci * @hw: pointer to the HW structure
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * This resets the hardware into a known state.  This is a
1762306a36Sopenharmony_ci * function pointer entry point called by the api module.
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_cistatic s32 igc_reset_hw_base(struct igc_hw *hw)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	s32 ret_val;
2262306a36Sopenharmony_ci	u32 ctrl;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	/* Prevent the PCI-E bus from sticking if there is no TLP connection
2562306a36Sopenharmony_ci	 * on the last TLP read/write transaction when MAC is reset.
2662306a36Sopenharmony_ci	 */
2762306a36Sopenharmony_ci	ret_val = igc_disable_pcie_master(hw);
2862306a36Sopenharmony_ci	if (ret_val)
2962306a36Sopenharmony_ci		hw_dbg("PCI-E Master disable polling has failed\n");
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	hw_dbg("Masking off all interrupts\n");
3262306a36Sopenharmony_ci	wr32(IGC_IMC, 0xffffffff);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	wr32(IGC_RCTL, 0);
3562306a36Sopenharmony_ci	wr32(IGC_TCTL, IGC_TCTL_PSP);
3662306a36Sopenharmony_ci	wrfl();
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	usleep_range(10000, 20000);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	ctrl = rd32(IGC_CTRL);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	hw_dbg("Issuing a global reset to MAC\n");
4362306a36Sopenharmony_ci	wr32(IGC_CTRL, ctrl | IGC_CTRL_RST);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	ret_val = igc_get_auto_rd_done(hw);
4662306a36Sopenharmony_ci	if (ret_val) {
4762306a36Sopenharmony_ci		/* When auto config read does not complete, do not
4862306a36Sopenharmony_ci		 * return with an error. This can happen in situations
4962306a36Sopenharmony_ci		 * where there is no eeprom and prevents getting link.
5062306a36Sopenharmony_ci		 */
5162306a36Sopenharmony_ci		hw_dbg("Auto Read Done did not complete\n");
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	/* Clear any pending interrupt events. */
5562306a36Sopenharmony_ci	wr32(IGC_IMC, 0xffffffff);
5662306a36Sopenharmony_ci	rd32(IGC_ICR);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return ret_val;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/**
6262306a36Sopenharmony_ci * igc_init_nvm_params_base - Init NVM func ptrs.
6362306a36Sopenharmony_ci * @hw: pointer to the HW structure
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_cistatic s32 igc_init_nvm_params_base(struct igc_hw *hw)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	struct igc_nvm_info *nvm = &hw->nvm;
6862306a36Sopenharmony_ci	u32 eecd = rd32(IGC_EECD);
6962306a36Sopenharmony_ci	u16 size;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>
7262306a36Sopenharmony_ci		     IGC_EECD_SIZE_EX_SHIFT);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* Added to a constant, "size" becomes the left-shift value
7562306a36Sopenharmony_ci	 * for setting word_size.
7662306a36Sopenharmony_ci	 */
7762306a36Sopenharmony_ci	size += NVM_WORD_SIZE_BASE_SHIFT;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* Just in case size is out of range, cap it to the largest
8062306a36Sopenharmony_ci	 * EEPROM size supported
8162306a36Sopenharmony_ci	 */
8262306a36Sopenharmony_ci	if (size > 15)
8362306a36Sopenharmony_ci		size = 15;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	nvm->type = igc_nvm_eeprom_spi;
8662306a36Sopenharmony_ci	nvm->word_size = BIT(size);
8762306a36Sopenharmony_ci	nvm->opcode_bits = 8;
8862306a36Sopenharmony_ci	nvm->delay_usec = 1;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8;
9162306a36Sopenharmony_ci	nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ?
9262306a36Sopenharmony_ci			    16 : 8;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (nvm->word_size == BIT(15))
9562306a36Sopenharmony_ci		nvm->page_size = 128;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return 0;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/**
10162306a36Sopenharmony_ci * igc_setup_copper_link_base - Configure copper link settings
10262306a36Sopenharmony_ci * @hw: pointer to the HW structure
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci * Configures the link for auto-neg or forced speed and duplex.  Then we check
10562306a36Sopenharmony_ci * for link, once link is established calls to configure collision distance
10662306a36Sopenharmony_ci * and flow control are called.
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_cistatic s32 igc_setup_copper_link_base(struct igc_hw *hw)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	s32  ret_val = 0;
11162306a36Sopenharmony_ci	u32 ctrl;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	ctrl = rd32(IGC_CTRL);
11462306a36Sopenharmony_ci	ctrl |= IGC_CTRL_SLU;
11562306a36Sopenharmony_ci	ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
11662306a36Sopenharmony_ci	wr32(IGC_CTRL, ctrl);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	ret_val = igc_setup_copper_link(hw);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return ret_val;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/**
12462306a36Sopenharmony_ci * igc_init_mac_params_base - Init MAC func ptrs.
12562306a36Sopenharmony_ci * @hw: pointer to the HW structure
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cistatic s32 igc_init_mac_params_base(struct igc_hw *hw)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct igc_dev_spec_base *dev_spec = &hw->dev_spec._base;
13062306a36Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* Set mta register count */
13362306a36Sopenharmony_ci	mac->mta_reg_count = 128;
13462306a36Sopenharmony_ci	mac->rar_entry_count = IGC_RAR_ENTRIES;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* reset */
13762306a36Sopenharmony_ci	mac->ops.reset_hw = igc_reset_hw_base;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
14062306a36Sopenharmony_ci	mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* Allow a single clear of the SW semaphore on I225 */
14362306a36Sopenharmony_ci	if (mac->type == igc_i225)
14462306a36Sopenharmony_ci		dev_spec->clear_semaphore_once = true;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* physical interface link setup */
14762306a36Sopenharmony_ci	mac->ops.setup_physical_interface = igc_setup_copper_link_base;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return 0;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/**
15362306a36Sopenharmony_ci * igc_init_phy_params_base - Init PHY func ptrs.
15462306a36Sopenharmony_ci * @hw: pointer to the HW structure
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_cistatic s32 igc_init_phy_params_base(struct igc_hw *hw)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct igc_phy_info *phy = &hw->phy;
15962306a36Sopenharmony_ci	s32 ret_val = 0;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;
16262306a36Sopenharmony_ci	phy->reset_delay_us	= 100;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* set lan id */
16562306a36Sopenharmony_ci	hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>
16662306a36Sopenharmony_ci			IGC_STATUS_FUNC_SHIFT;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* Make sure the PHY is in a good state. Several people have reported
16962306a36Sopenharmony_ci	 * firmware leaving the PHY's page select register set to something
17062306a36Sopenharmony_ci	 * other than the default of zero, which causes the PHY ID read to
17162306a36Sopenharmony_ci	 * access something other than the intended register.
17262306a36Sopenharmony_ci	 */
17362306a36Sopenharmony_ci	ret_val = hw->phy.ops.reset(hw);
17462306a36Sopenharmony_ci	if (ret_val) {
17562306a36Sopenharmony_ci		hw_dbg("Error resetting the PHY\n");
17662306a36Sopenharmony_ci		goto out;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	ret_val = igc_get_phy_id(hw);
18062306a36Sopenharmony_ci	if (ret_val)
18162306a36Sopenharmony_ci		return ret_val;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	igc_check_for_copper_link(hw);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ciout:
18662306a36Sopenharmony_ci	return ret_val;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic s32 igc_get_invariants_base(struct igc_hw *hw)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
19262306a36Sopenharmony_ci	s32 ret_val = 0;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	switch (hw->device_id) {
19562306a36Sopenharmony_ci	case IGC_DEV_ID_I225_LM:
19662306a36Sopenharmony_ci	case IGC_DEV_ID_I225_V:
19762306a36Sopenharmony_ci	case IGC_DEV_ID_I225_I:
19862306a36Sopenharmony_ci	case IGC_DEV_ID_I220_V:
19962306a36Sopenharmony_ci	case IGC_DEV_ID_I225_K:
20062306a36Sopenharmony_ci	case IGC_DEV_ID_I225_K2:
20162306a36Sopenharmony_ci	case IGC_DEV_ID_I226_K:
20262306a36Sopenharmony_ci	case IGC_DEV_ID_I225_LMVP:
20362306a36Sopenharmony_ci	case IGC_DEV_ID_I226_LMVP:
20462306a36Sopenharmony_ci	case IGC_DEV_ID_I225_IT:
20562306a36Sopenharmony_ci	case IGC_DEV_ID_I226_LM:
20662306a36Sopenharmony_ci	case IGC_DEV_ID_I226_V:
20762306a36Sopenharmony_ci	case IGC_DEV_ID_I226_IT:
20862306a36Sopenharmony_ci	case IGC_DEV_ID_I221_V:
20962306a36Sopenharmony_ci	case IGC_DEV_ID_I226_BLANK_NVM:
21062306a36Sopenharmony_ci	case IGC_DEV_ID_I225_BLANK_NVM:
21162306a36Sopenharmony_ci		mac->type = igc_i225;
21262306a36Sopenharmony_ci		break;
21362306a36Sopenharmony_ci	default:
21462306a36Sopenharmony_ci		return -IGC_ERR_MAC_INIT;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	hw->phy.media_type = igc_media_type_copper;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* mac initialization and operations */
22062306a36Sopenharmony_ci	ret_val = igc_init_mac_params_base(hw);
22162306a36Sopenharmony_ci	if (ret_val)
22262306a36Sopenharmony_ci		goto out;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* NVM initialization */
22562306a36Sopenharmony_ci	ret_val = igc_init_nvm_params_base(hw);
22662306a36Sopenharmony_ci	switch (hw->mac.type) {
22762306a36Sopenharmony_ci	case igc_i225:
22862306a36Sopenharmony_ci		ret_val = igc_init_nvm_params_i225(hw);
22962306a36Sopenharmony_ci		break;
23062306a36Sopenharmony_ci	default:
23162306a36Sopenharmony_ci		break;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* setup PHY parameters */
23562306a36Sopenharmony_ci	ret_val = igc_init_phy_params_base(hw);
23662306a36Sopenharmony_ci	if (ret_val)
23762306a36Sopenharmony_ci		goto out;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciout:
24062306a36Sopenharmony_ci	return ret_val;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci/**
24462306a36Sopenharmony_ci * igc_acquire_phy_base - Acquire rights to access PHY
24562306a36Sopenharmony_ci * @hw: pointer to the HW structure
24662306a36Sopenharmony_ci *
24762306a36Sopenharmony_ci * Acquire access rights to the correct PHY.  This is a
24862306a36Sopenharmony_ci * function pointer entry point called by the api module.
24962306a36Sopenharmony_ci */
25062306a36Sopenharmony_cistatic s32 igc_acquire_phy_base(struct igc_hw *hw)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	u16 mask = IGC_SWFW_PHY0_SM;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return hw->mac.ops.acquire_swfw_sync(hw, mask);
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci/**
25862306a36Sopenharmony_ci * igc_release_phy_base - Release rights to access PHY
25962306a36Sopenharmony_ci * @hw: pointer to the HW structure
26062306a36Sopenharmony_ci *
26162306a36Sopenharmony_ci * A wrapper to release access rights to the correct PHY.  This is a
26262306a36Sopenharmony_ci * function pointer entry point called by the api module.
26362306a36Sopenharmony_ci */
26462306a36Sopenharmony_cistatic void igc_release_phy_base(struct igc_hw *hw)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	u16 mask = IGC_SWFW_PHY0_SM;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	hw->mac.ops.release_swfw_sync(hw, mask);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/**
27262306a36Sopenharmony_ci * igc_init_hw_base - Initialize hardware
27362306a36Sopenharmony_ci * @hw: pointer to the HW structure
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci * This inits the hardware readying it for operation.
27662306a36Sopenharmony_ci */
27762306a36Sopenharmony_cistatic s32 igc_init_hw_base(struct igc_hw *hw)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct igc_mac_info *mac = &hw->mac;
28062306a36Sopenharmony_ci	u16 i, rar_count = mac->rar_entry_count;
28162306a36Sopenharmony_ci	s32 ret_val = 0;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/* Setup the receive address */
28462306a36Sopenharmony_ci	igc_init_rx_addrs(hw, rar_count);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* Zero out the Multicast HASH table */
28762306a36Sopenharmony_ci	hw_dbg("Zeroing the MTA\n");
28862306a36Sopenharmony_ci	for (i = 0; i < mac->mta_reg_count; i++)
28962306a36Sopenharmony_ci		array_wr32(IGC_MTA, i, 0);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* Zero out the Unicast HASH table */
29262306a36Sopenharmony_ci	hw_dbg("Zeroing the UTA\n");
29362306a36Sopenharmony_ci	for (i = 0; i < mac->uta_reg_count; i++)
29462306a36Sopenharmony_ci		array_wr32(IGC_UTA, i, 0);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* Setup link and flow control */
29762306a36Sopenharmony_ci	ret_val = igc_setup_link(hw);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* Clear all of the statistics registers (clear on read).  It is
30062306a36Sopenharmony_ci	 * important that we do this after we have tried to establish link
30162306a36Sopenharmony_ci	 * because the symbol error count will increment wildly if there
30262306a36Sopenharmony_ci	 * is no link.
30362306a36Sopenharmony_ci	 */
30462306a36Sopenharmony_ci	igc_clear_hw_cntrs_base(hw);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return ret_val;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci/**
31062306a36Sopenharmony_ci * igc_power_down_phy_copper_base - Remove link during PHY power down
31162306a36Sopenharmony_ci * @hw: pointer to the HW structure
31262306a36Sopenharmony_ci *
31362306a36Sopenharmony_ci * In the case of a PHY power down to save power, or to turn off link during a
31462306a36Sopenharmony_ci * driver unload, or wake on lan is not enabled, remove the link.
31562306a36Sopenharmony_ci */
31662306a36Sopenharmony_civoid igc_power_down_phy_copper_base(struct igc_hw *hw)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	/* If the management interface is not enabled, then power down */
31962306a36Sopenharmony_ci	if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw)))
32062306a36Sopenharmony_ci		igc_power_down_phy_copper(hw);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci/**
32462306a36Sopenharmony_ci * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable
32562306a36Sopenharmony_ci * @hw: pointer to the HW structure
32662306a36Sopenharmony_ci *
32762306a36Sopenharmony_ci * After Rx enable, if manageability is enabled then there is likely some
32862306a36Sopenharmony_ci * bad data at the start of the fifo and possibly in the DMA fifo.  This
32962306a36Sopenharmony_ci * function clears the fifos and flushes any packets that came in as rx was
33062306a36Sopenharmony_ci * being enabled.
33162306a36Sopenharmony_ci */
33262306a36Sopenharmony_civoid igc_rx_fifo_flush_base(struct igc_hw *hw)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
33562306a36Sopenharmony_ci	int i, ms_wait;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* disable IPv6 options as per hardware errata */
33862306a36Sopenharmony_ci	rfctl = rd32(IGC_RFCTL);
33962306a36Sopenharmony_ci	rfctl |= IGC_RFCTL_IPV6_EX_DIS;
34062306a36Sopenharmony_ci	wr32(IGC_RFCTL, rfctl);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (!(rd32(IGC_MANC) & IGC_MANC_RCV_TCO_EN))
34362306a36Sopenharmony_ci		return;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Disable all Rx queues */
34662306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
34762306a36Sopenharmony_ci		rxdctl[i] = rd32(IGC_RXDCTL(i));
34862306a36Sopenharmony_ci		wr32(IGC_RXDCTL(i),
34962306a36Sopenharmony_ci		     rxdctl[i] & ~IGC_RXDCTL_QUEUE_ENABLE);
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci	/* Poll all queues to verify they have shut down */
35262306a36Sopenharmony_ci	for (ms_wait = 0; ms_wait < 10; ms_wait++) {
35362306a36Sopenharmony_ci		usleep_range(1000, 2000);
35462306a36Sopenharmony_ci		rx_enabled = 0;
35562306a36Sopenharmony_ci		for (i = 0; i < 4; i++)
35662306a36Sopenharmony_ci			rx_enabled |= rd32(IGC_RXDCTL(i));
35762306a36Sopenharmony_ci		if (!(rx_enabled & IGC_RXDCTL_QUEUE_ENABLE))
35862306a36Sopenharmony_ci			break;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (ms_wait == 10)
36262306a36Sopenharmony_ci		hw_dbg("Queue disable timed out after 10ms\n");
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
36562306a36Sopenharmony_ci	 * incoming packets are rejected.  Set enable and wait 2ms so that
36662306a36Sopenharmony_ci	 * any packet that was coming in as RCTL.EN was set is flushed
36762306a36Sopenharmony_ci	 */
36862306a36Sopenharmony_ci	wr32(IGC_RFCTL, rfctl & ~IGC_RFCTL_LEF);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	rlpml = rd32(IGC_RLPML);
37162306a36Sopenharmony_ci	wr32(IGC_RLPML, 0);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	rctl = rd32(IGC_RCTL);
37462306a36Sopenharmony_ci	temp_rctl = rctl & ~(IGC_RCTL_EN | IGC_RCTL_SBP);
37562306a36Sopenharmony_ci	temp_rctl |= IGC_RCTL_LPE;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	wr32(IGC_RCTL, temp_rctl);
37862306a36Sopenharmony_ci	wr32(IGC_RCTL, temp_rctl | IGC_RCTL_EN);
37962306a36Sopenharmony_ci	wrfl();
38062306a36Sopenharmony_ci	usleep_range(2000, 3000);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/* Enable Rx queues that were previously enabled and restore our
38362306a36Sopenharmony_ci	 * previous state
38462306a36Sopenharmony_ci	 */
38562306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
38662306a36Sopenharmony_ci		wr32(IGC_RXDCTL(i), rxdctl[i]);
38762306a36Sopenharmony_ci	wr32(IGC_RCTL, rctl);
38862306a36Sopenharmony_ci	wrfl();
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	wr32(IGC_RLPML, rlpml);
39162306a36Sopenharmony_ci	wr32(IGC_RFCTL, rfctl);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* Flush receive errors generated by workaround */
39462306a36Sopenharmony_ci	rd32(IGC_ROC);
39562306a36Sopenharmony_ci	rd32(IGC_RNBC);
39662306a36Sopenharmony_ci	rd32(IGC_MPC);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cibool igc_is_device_id_i225(struct igc_hw *hw)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	switch (hw->device_id) {
40262306a36Sopenharmony_ci	case IGC_DEV_ID_I225_LM:
40362306a36Sopenharmony_ci	case IGC_DEV_ID_I225_V:
40462306a36Sopenharmony_ci	case IGC_DEV_ID_I225_I:
40562306a36Sopenharmony_ci	case IGC_DEV_ID_I225_K:
40662306a36Sopenharmony_ci	case IGC_DEV_ID_I225_K2:
40762306a36Sopenharmony_ci	case IGC_DEV_ID_I225_LMVP:
40862306a36Sopenharmony_ci	case IGC_DEV_ID_I225_IT:
40962306a36Sopenharmony_ci		return true;
41062306a36Sopenharmony_ci	default:
41162306a36Sopenharmony_ci		return false;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cibool igc_is_device_id_i226(struct igc_hw *hw)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	switch (hw->device_id) {
41862306a36Sopenharmony_ci	case IGC_DEV_ID_I226_LM:
41962306a36Sopenharmony_ci	case IGC_DEV_ID_I226_V:
42062306a36Sopenharmony_ci	case IGC_DEV_ID_I226_K:
42162306a36Sopenharmony_ci	case IGC_DEV_ID_I226_IT:
42262306a36Sopenharmony_ci		return true;
42362306a36Sopenharmony_ci	default:
42462306a36Sopenharmony_ci		return false;
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic struct igc_mac_operations igc_mac_ops_base = {
42962306a36Sopenharmony_ci	.init_hw		= igc_init_hw_base,
43062306a36Sopenharmony_ci	.check_for_link		= igc_check_for_copper_link,
43162306a36Sopenharmony_ci	.rar_set		= igc_rar_set,
43262306a36Sopenharmony_ci	.read_mac_addr		= igc_read_mac_addr,
43362306a36Sopenharmony_ci	.get_speed_and_duplex	= igc_get_speed_and_duplex_copper,
43462306a36Sopenharmony_ci};
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic const struct igc_phy_operations igc_phy_ops_base = {
43762306a36Sopenharmony_ci	.acquire		= igc_acquire_phy_base,
43862306a36Sopenharmony_ci	.release		= igc_release_phy_base,
43962306a36Sopenharmony_ci	.reset			= igc_phy_hw_reset,
44062306a36Sopenharmony_ci	.read_reg		= igc_read_phy_reg_gpy,
44162306a36Sopenharmony_ci	.write_reg		= igc_write_phy_reg_gpy,
44262306a36Sopenharmony_ci};
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ciconst struct igc_info igc_base_info = {
44562306a36Sopenharmony_ci	.get_invariants		= igc_get_invariants_base,
44662306a36Sopenharmony_ci	.mac_ops		= &igc_mac_ops_base,
44762306a36Sopenharmony_ci	.phy_ops		= &igc_phy_ops_base,
44862306a36Sopenharmony_ci};
449