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