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