18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2018 Intel Corporation */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/pci.h> 58c2ecf20Sopenharmony_ci#include <linux/delay.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "igc_mac.h" 88c2ecf20Sopenharmony_ci#include "igc_hw.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/** 118c2ecf20Sopenharmony_ci * igc_disable_pcie_master - Disables PCI-express master access 128c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Returns 0 (0) if successful, else returns -10 158c2ecf20Sopenharmony_ci * (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused 168c2ecf20Sopenharmony_ci * the master requests to be disabled. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Disables PCI-Express master access and verifies there are no pending 198c2ecf20Sopenharmony_ci * requests. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_cis32 igc_disable_pcie_master(struct igc_hw *hw) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci s32 timeout = MASTER_DISABLE_TIMEOUT; 248c2ecf20Sopenharmony_ci s32 ret_val = 0; 258c2ecf20Sopenharmony_ci u32 ctrl; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci ctrl = rd32(IGC_CTRL); 288c2ecf20Sopenharmony_ci ctrl |= IGC_CTRL_GIO_MASTER_DISABLE; 298c2ecf20Sopenharmony_ci wr32(IGC_CTRL, ctrl); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci while (timeout) { 328c2ecf20Sopenharmony_ci if (!(rd32(IGC_STATUS) & 338c2ecf20Sopenharmony_ci IGC_STATUS_GIO_MASTER_ENABLE)) 348c2ecf20Sopenharmony_ci break; 358c2ecf20Sopenharmony_ci usleep_range(2000, 3000); 368c2ecf20Sopenharmony_ci timeout--; 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (!timeout) { 408c2ecf20Sopenharmony_ci hw_dbg("Master requests are pending.\n"); 418c2ecf20Sopenharmony_ci ret_val = -IGC_ERR_MASTER_REQUESTS_PENDING; 428c2ecf20Sopenharmony_ci goto out; 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciout: 468c2ecf20Sopenharmony_ci return ret_val; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/** 508c2ecf20Sopenharmony_ci * igc_init_rx_addrs - Initialize receive addresses 518c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 528c2ecf20Sopenharmony_ci * @rar_count: receive address registers 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * Setup the receive address registers by setting the base receive address 558c2ecf20Sopenharmony_ci * register to the devices MAC address and clearing all the other receive 568c2ecf20Sopenharmony_ci * address registers to 0. 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_civoid igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN] = {0}; 618c2ecf20Sopenharmony_ci u32 i; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* Setup the receive address */ 648c2ecf20Sopenharmony_ci hw_dbg("Programming MAC Address into RAR[0]\n"); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci hw->mac.ops.rar_set(hw, hw->mac.addr, 0); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Zero out the other (rar_entry_count - 1) receive addresses */ 698c2ecf20Sopenharmony_ci hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1); 708c2ecf20Sopenharmony_ci for (i = 1; i < rar_count; i++) 718c2ecf20Sopenharmony_ci hw->mac.ops.rar_set(hw, mac_addr, i); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/** 758c2ecf20Sopenharmony_ci * igc_set_fc_watermarks - Set flow control high/low watermarks 768c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * Sets the flow control high/low threshold (watermark) registers. If 798c2ecf20Sopenharmony_ci * flow control XON frame transmission is enabled, then set XON frame 808c2ecf20Sopenharmony_ci * transmission as well. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_cistatic s32 igc_set_fc_watermarks(struct igc_hw *hw) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci u32 fcrtl = 0, fcrth = 0; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* Set the flow control receive threshold registers. Normally, 878c2ecf20Sopenharmony_ci * these registers will be set to a default threshold that may be 888c2ecf20Sopenharmony_ci * adjusted later by the driver's runtime code. However, if the 898c2ecf20Sopenharmony_ci * ability to transmit pause frames is not enabled, then these 908c2ecf20Sopenharmony_ci * registers will be set to 0. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci if (hw->fc.current_mode & igc_fc_tx_pause) { 938c2ecf20Sopenharmony_ci /* We need to set up the Receive Threshold high and low water 948c2ecf20Sopenharmony_ci * marks as well as (optionally) enabling the transmission of 958c2ecf20Sopenharmony_ci * XON frames. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci fcrtl = hw->fc.low_water; 988c2ecf20Sopenharmony_ci if (hw->fc.send_xon) 998c2ecf20Sopenharmony_ci fcrtl |= IGC_FCRTL_XONE; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci fcrth = hw->fc.high_water; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci wr32(IGC_FCRTL, fcrtl); 1048c2ecf20Sopenharmony_ci wr32(IGC_FCRTH, fcrth); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/** 1108c2ecf20Sopenharmony_ci * igc_setup_link - Setup flow control and link settings 1118c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * Determines which flow control settings to use, then configures flow 1148c2ecf20Sopenharmony_ci * control. Calls the appropriate media-specific link configuration 1158c2ecf20Sopenharmony_ci * function. Assuming the adapter has a valid link partner, a valid link 1168c2ecf20Sopenharmony_ci * should be established. Assumes the hardware has previously been reset 1178c2ecf20Sopenharmony_ci * and the transmitter and receiver are not enabled. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cis32 igc_setup_link(struct igc_hw *hw) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci s32 ret_val = 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* In the case of the phy reset being blocked, we already have a link. 1248c2ecf20Sopenharmony_ci * We do not need to set it up again. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci if (igc_check_reset_block(hw)) 1278c2ecf20Sopenharmony_ci goto out; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* If requested flow control is set to default, set flow control 1308c2ecf20Sopenharmony_ci * to the both 'rx' and 'tx' pause frames. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci if (hw->fc.requested_mode == igc_fc_default) 1338c2ecf20Sopenharmony_ci hw->fc.requested_mode = igc_fc_full; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* We want to save off the original Flow Control configuration just 1368c2ecf20Sopenharmony_ci * in case we get disconnected and then reconnected into a different 1378c2ecf20Sopenharmony_ci * hub or switch with different Flow Control capabilities. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci hw->fc.current_mode = hw->fc.requested_mode; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Call the necessary media_type subroutine to configure the link. */ 1448c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.setup_physical_interface(hw); 1458c2ecf20Sopenharmony_ci if (ret_val) 1468c2ecf20Sopenharmony_ci goto out; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Initialize the flow control address, type, and PAUSE timer 1498c2ecf20Sopenharmony_ci * registers to their default values. This is done even if flow 1508c2ecf20Sopenharmony_ci * control is disabled, because it does not hurt anything to 1518c2ecf20Sopenharmony_ci * initialize these registers. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci hw_dbg("Initializing the Flow Control address, type and timer regs\n"); 1548c2ecf20Sopenharmony_ci wr32(IGC_FCT, FLOW_CONTROL_TYPE); 1558c2ecf20Sopenharmony_ci wr32(IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH); 1568c2ecf20Sopenharmony_ci wr32(IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci wr32(IGC_FCTTV, hw->fc.pause_time); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ret_val = igc_set_fc_watermarks(hw); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciout: 1638c2ecf20Sopenharmony_ci return ret_val; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/** 1678c2ecf20Sopenharmony_ci * igc_force_mac_fc - Force the MAC's flow control settings 1688c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the 1718c2ecf20Sopenharmony_ci * device control register to reflect the adapter settings. TFCE and RFCE 1728c2ecf20Sopenharmony_ci * need to be explicitly set by software when a copper PHY is used because 1738c2ecf20Sopenharmony_ci * autonegotiation is managed by the PHY rather than the MAC. Software must 1748c2ecf20Sopenharmony_ci * also configure these bits when link is forced on a fiber connection. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_cis32 igc_force_mac_fc(struct igc_hw *hw) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci s32 ret_val = 0; 1798c2ecf20Sopenharmony_ci u32 ctrl; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ctrl = rd32(IGC_CTRL); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* Because we didn't get link via the internal auto-negotiation 1848c2ecf20Sopenharmony_ci * mechanism (we either forced link or we got link via PHY 1858c2ecf20Sopenharmony_ci * auto-neg), we have to manually enable/disable transmit an 1868c2ecf20Sopenharmony_ci * receive flow control. 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * The "Case" statement below enables/disable flow control 1898c2ecf20Sopenharmony_ci * according to the "hw->fc.current_mode" parameter. 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * The possible values of the "fc" parameter are: 1928c2ecf20Sopenharmony_ci * 0: Flow control is completely disabled 1938c2ecf20Sopenharmony_ci * 1: Rx flow control is enabled (we can receive pause 1948c2ecf20Sopenharmony_ci * frames but not send pause frames). 1958c2ecf20Sopenharmony_ci * 2: Tx flow control is enabled (we can send pause frames 1968c2ecf20Sopenharmony_ci * frames but we do not receive pause frames). 1978c2ecf20Sopenharmony_ci * 3: Both Rx and TX flow control (symmetric) is enabled. 1988c2ecf20Sopenharmony_ci * other: No other values should be possible at this point. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci switch (hw->fc.current_mode) { 2038c2ecf20Sopenharmony_ci case igc_fc_none: 2048c2ecf20Sopenharmony_ci ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE)); 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci case igc_fc_rx_pause: 2078c2ecf20Sopenharmony_ci ctrl &= (~IGC_CTRL_TFCE); 2088c2ecf20Sopenharmony_ci ctrl |= IGC_CTRL_RFCE; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case igc_fc_tx_pause: 2118c2ecf20Sopenharmony_ci ctrl &= (~IGC_CTRL_RFCE); 2128c2ecf20Sopenharmony_ci ctrl |= IGC_CTRL_TFCE; 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci case igc_fc_full: 2158c2ecf20Sopenharmony_ci ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE); 2168c2ecf20Sopenharmony_ci break; 2178c2ecf20Sopenharmony_ci default: 2188c2ecf20Sopenharmony_ci hw_dbg("Flow control param set incorrectly\n"); 2198c2ecf20Sopenharmony_ci ret_val = -IGC_ERR_CONFIG; 2208c2ecf20Sopenharmony_ci goto out; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci wr32(IGC_CTRL, ctrl); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciout: 2268c2ecf20Sopenharmony_ci return ret_val; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/** 2308c2ecf20Sopenharmony_ci * igc_clear_hw_cntrs_base - Clear base hardware counters 2318c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * Clears the base hardware counters by reading the counter registers. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_civoid igc_clear_hw_cntrs_base(struct igc_hw *hw) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci rd32(IGC_CRCERRS); 2388c2ecf20Sopenharmony_ci rd32(IGC_MPC); 2398c2ecf20Sopenharmony_ci rd32(IGC_SCC); 2408c2ecf20Sopenharmony_ci rd32(IGC_ECOL); 2418c2ecf20Sopenharmony_ci rd32(IGC_MCC); 2428c2ecf20Sopenharmony_ci rd32(IGC_LATECOL); 2438c2ecf20Sopenharmony_ci rd32(IGC_COLC); 2448c2ecf20Sopenharmony_ci rd32(IGC_RERC); 2458c2ecf20Sopenharmony_ci rd32(IGC_DC); 2468c2ecf20Sopenharmony_ci rd32(IGC_RLEC); 2478c2ecf20Sopenharmony_ci rd32(IGC_XONRXC); 2488c2ecf20Sopenharmony_ci rd32(IGC_XONTXC); 2498c2ecf20Sopenharmony_ci rd32(IGC_XOFFRXC); 2508c2ecf20Sopenharmony_ci rd32(IGC_XOFFTXC); 2518c2ecf20Sopenharmony_ci rd32(IGC_FCRUC); 2528c2ecf20Sopenharmony_ci rd32(IGC_GPRC); 2538c2ecf20Sopenharmony_ci rd32(IGC_BPRC); 2548c2ecf20Sopenharmony_ci rd32(IGC_MPRC); 2558c2ecf20Sopenharmony_ci rd32(IGC_GPTC); 2568c2ecf20Sopenharmony_ci rd32(IGC_GORCL); 2578c2ecf20Sopenharmony_ci rd32(IGC_GORCH); 2588c2ecf20Sopenharmony_ci rd32(IGC_GOTCL); 2598c2ecf20Sopenharmony_ci rd32(IGC_GOTCH); 2608c2ecf20Sopenharmony_ci rd32(IGC_RNBC); 2618c2ecf20Sopenharmony_ci rd32(IGC_RUC); 2628c2ecf20Sopenharmony_ci rd32(IGC_RFC); 2638c2ecf20Sopenharmony_ci rd32(IGC_ROC); 2648c2ecf20Sopenharmony_ci rd32(IGC_RJC); 2658c2ecf20Sopenharmony_ci rd32(IGC_TORL); 2668c2ecf20Sopenharmony_ci rd32(IGC_TORH); 2678c2ecf20Sopenharmony_ci rd32(IGC_TOTL); 2688c2ecf20Sopenharmony_ci rd32(IGC_TOTH); 2698c2ecf20Sopenharmony_ci rd32(IGC_TPR); 2708c2ecf20Sopenharmony_ci rd32(IGC_TPT); 2718c2ecf20Sopenharmony_ci rd32(IGC_MPTC); 2728c2ecf20Sopenharmony_ci rd32(IGC_BPTC); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci rd32(IGC_PRC64); 2758c2ecf20Sopenharmony_ci rd32(IGC_PRC127); 2768c2ecf20Sopenharmony_ci rd32(IGC_PRC255); 2778c2ecf20Sopenharmony_ci rd32(IGC_PRC511); 2788c2ecf20Sopenharmony_ci rd32(IGC_PRC1023); 2798c2ecf20Sopenharmony_ci rd32(IGC_PRC1522); 2808c2ecf20Sopenharmony_ci rd32(IGC_PTC64); 2818c2ecf20Sopenharmony_ci rd32(IGC_PTC127); 2828c2ecf20Sopenharmony_ci rd32(IGC_PTC255); 2838c2ecf20Sopenharmony_ci rd32(IGC_PTC511); 2848c2ecf20Sopenharmony_ci rd32(IGC_PTC1023); 2858c2ecf20Sopenharmony_ci rd32(IGC_PTC1522); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci rd32(IGC_ALGNERRC); 2888c2ecf20Sopenharmony_ci rd32(IGC_RXERRC); 2898c2ecf20Sopenharmony_ci rd32(IGC_TNCRS); 2908c2ecf20Sopenharmony_ci rd32(IGC_HTDPMC); 2918c2ecf20Sopenharmony_ci rd32(IGC_TSCTC); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci rd32(IGC_MGTPRC); 2948c2ecf20Sopenharmony_ci rd32(IGC_MGTPDC); 2958c2ecf20Sopenharmony_ci rd32(IGC_MGTPTC); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci rd32(IGC_IAC); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci rd32(IGC_RPTHC); 3008c2ecf20Sopenharmony_ci rd32(IGC_TLPIC); 3018c2ecf20Sopenharmony_ci rd32(IGC_RLPIC); 3028c2ecf20Sopenharmony_ci rd32(IGC_HGPTC); 3038c2ecf20Sopenharmony_ci rd32(IGC_RXDMTC); 3048c2ecf20Sopenharmony_ci rd32(IGC_HGORCL); 3058c2ecf20Sopenharmony_ci rd32(IGC_HGORCH); 3068c2ecf20Sopenharmony_ci rd32(IGC_HGOTCL); 3078c2ecf20Sopenharmony_ci rd32(IGC_HGOTCH); 3088c2ecf20Sopenharmony_ci rd32(IGC_LENERRS); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/** 3128c2ecf20Sopenharmony_ci * igc_rar_set - Set receive address register 3138c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 3148c2ecf20Sopenharmony_ci * @addr: pointer to the receive address 3158c2ecf20Sopenharmony_ci * @index: receive address array register 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * Sets the receive address array register at index to the address passed 3188c2ecf20Sopenharmony_ci * in by addr. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_civoid igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci u32 rar_low, rar_high; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* HW expects these in little endian so we reverse the byte order 3258c2ecf20Sopenharmony_ci * from network order (big endian) to little endian 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_ci rar_low = ((u32)addr[0] | 3288c2ecf20Sopenharmony_ci ((u32)addr[1] << 8) | 3298c2ecf20Sopenharmony_ci ((u32)addr[2] << 16) | ((u32)addr[3] << 24)); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci rar_high = ((u32)addr[4] | ((u32)addr[5] << 8)); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* If MAC address zero, no need to set the AV bit */ 3348c2ecf20Sopenharmony_ci if (rar_low || rar_high) 3358c2ecf20Sopenharmony_ci rar_high |= IGC_RAH_AV; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Some bridges will combine consecutive 32-bit writes into 3388c2ecf20Sopenharmony_ci * a single burst write, which will malfunction on some parts. 3398c2ecf20Sopenharmony_ci * The flushes avoid this. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci wr32(IGC_RAL(index), rar_low); 3428c2ecf20Sopenharmony_ci wrfl(); 3438c2ecf20Sopenharmony_ci wr32(IGC_RAH(index), rar_high); 3448c2ecf20Sopenharmony_ci wrfl(); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci/** 3488c2ecf20Sopenharmony_ci * igc_check_for_copper_link - Check for link (Copper) 3498c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 3508c2ecf20Sopenharmony_ci * 3518c2ecf20Sopenharmony_ci * Checks to see of the link status of the hardware has changed. If a 3528c2ecf20Sopenharmony_ci * change in link status has been detected, then we read the PHY registers 3538c2ecf20Sopenharmony_ci * to get the current speed/duplex if link exists. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_cis32 igc_check_for_copper_link(struct igc_hw *hw) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct igc_mac_info *mac = &hw->mac; 3588c2ecf20Sopenharmony_ci bool link = false; 3598c2ecf20Sopenharmony_ci s32 ret_val; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* We only want to go out to the PHY registers to see if Auto-Neg 3628c2ecf20Sopenharmony_ci * has completed and/or if our link status has changed. The 3638c2ecf20Sopenharmony_ci * get_link_status flag is set upon receiving a Link Status 3648c2ecf20Sopenharmony_ci * Change or Rx Sequence Error interrupt. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci if (!mac->get_link_status) { 3678c2ecf20Sopenharmony_ci ret_val = 0; 3688c2ecf20Sopenharmony_ci goto out; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* First we want to see if the MII Status Register reports 3728c2ecf20Sopenharmony_ci * link. If so, then we want to get the current speed/duplex 3738c2ecf20Sopenharmony_ci * of the PHY. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_ci ret_val = igc_phy_has_link(hw, 1, 0, &link); 3768c2ecf20Sopenharmony_ci if (ret_val) 3778c2ecf20Sopenharmony_ci goto out; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (!link) 3808c2ecf20Sopenharmony_ci goto out; /* No link detected */ 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci mac->get_link_status = false; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Check if there was DownShift, must be checked 3858c2ecf20Sopenharmony_ci * immediately after link-up 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_ci igc_check_downshift(hw); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* If we are forcing speed/duplex, then we simply return since 3908c2ecf20Sopenharmony_ci * we have already determined whether we have link or not. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci if (!mac->autoneg) { 3938c2ecf20Sopenharmony_ci ret_val = -IGC_ERR_CONFIG; 3948c2ecf20Sopenharmony_ci goto out; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Auto-Neg is enabled. Auto Speed Detection takes care 3988c2ecf20Sopenharmony_ci * of MAC speed/duplex configuration. So we only need to 3998c2ecf20Sopenharmony_ci * configure Collision Distance in the MAC. 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci igc_config_collision_dist(hw); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* Configure Flow Control now that Auto-Neg has completed. 4048c2ecf20Sopenharmony_ci * First, we need to restore the desired flow control 4058c2ecf20Sopenharmony_ci * settings because we may have had to re-autoneg with a 4068c2ecf20Sopenharmony_ci * different link partner. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci ret_val = igc_config_fc_after_link_up(hw); 4098c2ecf20Sopenharmony_ci if (ret_val) 4108c2ecf20Sopenharmony_ci hw_dbg("Error configuring flow control\n"); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ciout: 4138c2ecf20Sopenharmony_ci /* Now that we are aware of our link settings, we can set the LTR 4148c2ecf20Sopenharmony_ci * thresholds. 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_ci ret_val = igc_set_ltr_i225(hw, link); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return ret_val; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/** 4228c2ecf20Sopenharmony_ci * igc_config_collision_dist - Configure collision distance 4238c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 4248c2ecf20Sopenharmony_ci * 4258c2ecf20Sopenharmony_ci * Configures the collision distance to the default value and is used 4268c2ecf20Sopenharmony_ci * during link setup. Currently no func pointer exists and all 4278c2ecf20Sopenharmony_ci * implementations are handled in the generic version of this function. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_civoid igc_config_collision_dist(struct igc_hw *hw) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci u32 tctl; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci tctl = rd32(IGC_TCTL); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci tctl &= ~IGC_TCTL_COLD; 4368c2ecf20Sopenharmony_ci tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci wr32(IGC_TCTL, tctl); 4398c2ecf20Sopenharmony_ci wrfl(); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci/** 4438c2ecf20Sopenharmony_ci * igc_config_fc_after_link_up - Configures flow control after link 4448c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 4458c2ecf20Sopenharmony_ci * 4468c2ecf20Sopenharmony_ci * Checks the status of auto-negotiation after link up to ensure that the 4478c2ecf20Sopenharmony_ci * speed and duplex were not forced. If the link needed to be forced, then 4488c2ecf20Sopenharmony_ci * flow control needs to be forced also. If auto-negotiation is enabled 4498c2ecf20Sopenharmony_ci * and did not fail, then we configure flow control based on our link 4508c2ecf20Sopenharmony_ci * partner. 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_cis32 igc_config_fc_after_link_up(struct igc_hw *hw) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; 4558c2ecf20Sopenharmony_ci struct igc_mac_info *mac = &hw->mac; 4568c2ecf20Sopenharmony_ci u16 speed, duplex; 4578c2ecf20Sopenharmony_ci s32 ret_val = 0; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* Check for the case where we have fiber media and auto-neg failed 4608c2ecf20Sopenharmony_ci * so we had to force link. In this case, we need to force the 4618c2ecf20Sopenharmony_ci * configuration of the MAC to match the "fc" parameter. 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci if (mac->autoneg_failed) 4648c2ecf20Sopenharmony_ci ret_val = igc_force_mac_fc(hw); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (ret_val) { 4678c2ecf20Sopenharmony_ci hw_dbg("Error forcing flow control settings\n"); 4688c2ecf20Sopenharmony_ci goto out; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Check for the case where we have copper media and auto-neg is 4728c2ecf20Sopenharmony_ci * enabled. In this case, we need to check and see if Auto-Neg 4738c2ecf20Sopenharmony_ci * has completed, and if so, how the PHY and link partner has 4748c2ecf20Sopenharmony_ci * flow control configured. 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci if (mac->autoneg) { 4778c2ecf20Sopenharmony_ci /* Read the MII Status Register and check to see if AutoNeg 4788c2ecf20Sopenharmony_ci * has completed. We read this twice because this reg has 4798c2ecf20Sopenharmony_ci * some "sticky" (latched) bits. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, 4828c2ecf20Sopenharmony_ci &mii_status_reg); 4838c2ecf20Sopenharmony_ci if (ret_val) 4848c2ecf20Sopenharmony_ci goto out; 4858c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, 4868c2ecf20Sopenharmony_ci &mii_status_reg); 4878c2ecf20Sopenharmony_ci if (ret_val) 4888c2ecf20Sopenharmony_ci goto out; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { 4918c2ecf20Sopenharmony_ci hw_dbg("Copper PHY and Auto Neg has not completed.\n"); 4928c2ecf20Sopenharmony_ci goto out; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* The AutoNeg process has completed, so we now need to 4968c2ecf20Sopenharmony_ci * read both the Auto Negotiation Advertisement 4978c2ecf20Sopenharmony_ci * Register (Address 4) and the Auto_Negotiation Base 4988c2ecf20Sopenharmony_ci * Page Ability Register (Address 5) to determine how 4998c2ecf20Sopenharmony_ci * flow control was negotiated. 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, 5028c2ecf20Sopenharmony_ci &mii_nway_adv_reg); 5038c2ecf20Sopenharmony_ci if (ret_val) 5048c2ecf20Sopenharmony_ci goto out; 5058c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, 5068c2ecf20Sopenharmony_ci &mii_nway_lp_ability_reg); 5078c2ecf20Sopenharmony_ci if (ret_val) 5088c2ecf20Sopenharmony_ci goto out; 5098c2ecf20Sopenharmony_ci /* Two bits in the Auto Negotiation Advertisement Register 5108c2ecf20Sopenharmony_ci * (Address 4) and two bits in the Auto Negotiation Base 5118c2ecf20Sopenharmony_ci * Page Ability Register (Address 5) determine flow control 5128c2ecf20Sopenharmony_ci * for both the PHY and the link partner. The following 5138c2ecf20Sopenharmony_ci * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, 5148c2ecf20Sopenharmony_ci * 1999, describes these PAUSE resolution bits and how flow 5158c2ecf20Sopenharmony_ci * control is determined based upon these settings. 5168c2ecf20Sopenharmony_ci * NOTE: DC = Don't Care 5178c2ecf20Sopenharmony_ci * 5188c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 5198c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution 5208c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 5218c2ecf20Sopenharmony_ci * 0 | 0 | DC | DC | igc_fc_none 5228c2ecf20Sopenharmony_ci * 0 | 1 | 0 | DC | igc_fc_none 5238c2ecf20Sopenharmony_ci * 0 | 1 | 1 | 0 | igc_fc_none 5248c2ecf20Sopenharmony_ci * 0 | 1 | 1 | 1 | igc_fc_tx_pause 5258c2ecf20Sopenharmony_ci * 1 | 0 | 0 | DC | igc_fc_none 5268c2ecf20Sopenharmony_ci * 1 | DC | 1 | DC | igc_fc_full 5278c2ecf20Sopenharmony_ci * 1 | 1 | 0 | 0 | igc_fc_none 5288c2ecf20Sopenharmony_ci * 1 | 1 | 0 | 1 | igc_fc_rx_pause 5298c2ecf20Sopenharmony_ci * 5308c2ecf20Sopenharmony_ci * Are both PAUSE bits set to 1? If so, this implies 5318c2ecf20Sopenharmony_ci * Symmetric Flow Control is enabled at both ends. The 5328c2ecf20Sopenharmony_ci * ASM_DIR bits are irrelevant per the spec. 5338c2ecf20Sopenharmony_ci * 5348c2ecf20Sopenharmony_ci * For Symmetric Flow Control: 5358c2ecf20Sopenharmony_ci * 5368c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 5378c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result 5388c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 5398c2ecf20Sopenharmony_ci * 1 | DC | 1 | DC | IGC_fc_full 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && 5438c2ecf20Sopenharmony_ci (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { 5448c2ecf20Sopenharmony_ci /* Now we need to check if the user selected RX ONLY 5458c2ecf20Sopenharmony_ci * of pause frames. In this case, we had to advertise 5468c2ecf20Sopenharmony_ci * FULL flow control because we could not advertise RX 5478c2ecf20Sopenharmony_ci * ONLY. Hence, we must now check to see if we need to 5488c2ecf20Sopenharmony_ci * turn OFF the TRANSMISSION of PAUSE frames. 5498c2ecf20Sopenharmony_ci */ 5508c2ecf20Sopenharmony_ci if (hw->fc.requested_mode == igc_fc_full) { 5518c2ecf20Sopenharmony_ci hw->fc.current_mode = igc_fc_full; 5528c2ecf20Sopenharmony_ci hw_dbg("Flow Control = FULL.\n"); 5538c2ecf20Sopenharmony_ci } else { 5548c2ecf20Sopenharmony_ci hw->fc.current_mode = igc_fc_rx_pause; 5558c2ecf20Sopenharmony_ci hw_dbg("Flow Control = RX PAUSE frames only.\n"); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* For receiving PAUSE frames ONLY. 5608c2ecf20Sopenharmony_ci * 5618c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 5628c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result 5638c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 5648c2ecf20Sopenharmony_ci * 0 | 1 | 1 | 1 | igc_fc_tx_pause 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_ci else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && 5678c2ecf20Sopenharmony_ci (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && 5688c2ecf20Sopenharmony_ci (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && 5698c2ecf20Sopenharmony_ci (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { 5708c2ecf20Sopenharmony_ci hw->fc.current_mode = igc_fc_tx_pause; 5718c2ecf20Sopenharmony_ci hw_dbg("Flow Control = TX PAUSE frames only.\n"); 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci /* For transmitting PAUSE frames ONLY. 5748c2ecf20Sopenharmony_ci * 5758c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 5768c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result 5778c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 5788c2ecf20Sopenharmony_ci * 1 | 1 | 0 | 1 | igc_fc_rx_pause 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_ci else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && 5818c2ecf20Sopenharmony_ci (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && 5828c2ecf20Sopenharmony_ci !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && 5838c2ecf20Sopenharmony_ci (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { 5848c2ecf20Sopenharmony_ci hw->fc.current_mode = igc_fc_rx_pause; 5858c2ecf20Sopenharmony_ci hw_dbg("Flow Control = RX PAUSE frames only.\n"); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci /* Per the IEEE spec, at this point flow control should be 5888c2ecf20Sopenharmony_ci * disabled. However, we want to consider that we could 5898c2ecf20Sopenharmony_ci * be connected to a legacy switch that doesn't advertise 5908c2ecf20Sopenharmony_ci * desired flow control, but can be forced on the link 5918c2ecf20Sopenharmony_ci * partner. So if we advertised no flow control, that is 5928c2ecf20Sopenharmony_ci * what we will resolve to. If we advertised some kind of 5938c2ecf20Sopenharmony_ci * receive capability (Rx Pause Only or Full Flow Control) 5948c2ecf20Sopenharmony_ci * and the link partner advertised none, we will configure 5958c2ecf20Sopenharmony_ci * ourselves to enable Rx Flow Control only. We can do 5968c2ecf20Sopenharmony_ci * this safely for two reasons: If the link partner really 5978c2ecf20Sopenharmony_ci * didn't want flow control enabled, and we enable Rx, no 5988c2ecf20Sopenharmony_ci * harm done since we won't be receiving any PAUSE frames 5998c2ecf20Sopenharmony_ci * anyway. If the intent on the link partner was to have 6008c2ecf20Sopenharmony_ci * flow control enabled, then by us enabling RX only, we 6018c2ecf20Sopenharmony_ci * can at least receive pause frames and process them. 6028c2ecf20Sopenharmony_ci * This is a good idea because in most cases, since we are 6038c2ecf20Sopenharmony_ci * predominantly a server NIC, more times than not we will 6048c2ecf20Sopenharmony_ci * be asked to delay transmission of packets than asking 6058c2ecf20Sopenharmony_ci * our link partner to pause transmission of frames. 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_ci else if ((hw->fc.requested_mode == igc_fc_none) || 6088c2ecf20Sopenharmony_ci (hw->fc.requested_mode == igc_fc_tx_pause) || 6098c2ecf20Sopenharmony_ci (hw->fc.strict_ieee)) { 6108c2ecf20Sopenharmony_ci hw->fc.current_mode = igc_fc_none; 6118c2ecf20Sopenharmony_ci hw_dbg("Flow Control = NONE.\n"); 6128c2ecf20Sopenharmony_ci } else { 6138c2ecf20Sopenharmony_ci hw->fc.current_mode = igc_fc_rx_pause; 6148c2ecf20Sopenharmony_ci hw_dbg("Flow Control = RX PAUSE frames only.\n"); 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* Now we need to do one last check... If we auto- 6188c2ecf20Sopenharmony_ci * negotiated to HALF DUPLEX, flow control should not be 6198c2ecf20Sopenharmony_ci * enabled per IEEE 802.3 spec. 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); 6228c2ecf20Sopenharmony_ci if (ret_val) { 6238c2ecf20Sopenharmony_ci hw_dbg("Error getting link speed and duplex\n"); 6248c2ecf20Sopenharmony_ci goto out; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (duplex == HALF_DUPLEX) 6288c2ecf20Sopenharmony_ci hw->fc.current_mode = igc_fc_none; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* Now we call a subroutine to actually force the MAC 6318c2ecf20Sopenharmony_ci * controller to use the correct flow control settings. 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_ci ret_val = igc_force_mac_fc(hw); 6348c2ecf20Sopenharmony_ci if (ret_val) { 6358c2ecf20Sopenharmony_ci hw_dbg("Error forcing flow control settings\n"); 6368c2ecf20Sopenharmony_ci goto out; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ciout: 6418c2ecf20Sopenharmony_ci return ret_val; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci/** 6458c2ecf20Sopenharmony_ci * igc_get_auto_rd_done - Check for auto read completion 6468c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 6478c2ecf20Sopenharmony_ci * 6488c2ecf20Sopenharmony_ci * Check EEPROM for Auto Read done bit. 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_cis32 igc_get_auto_rd_done(struct igc_hw *hw) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci s32 ret_val = 0; 6538c2ecf20Sopenharmony_ci s32 i = 0; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci while (i < AUTO_READ_DONE_TIMEOUT) { 6568c2ecf20Sopenharmony_ci if (rd32(IGC_EECD) & IGC_EECD_AUTO_RD) 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 6598c2ecf20Sopenharmony_ci i++; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (i == AUTO_READ_DONE_TIMEOUT) { 6638c2ecf20Sopenharmony_ci hw_dbg("Auto read by HW from NVM has not completed.\n"); 6648c2ecf20Sopenharmony_ci ret_val = -IGC_ERR_RESET; 6658c2ecf20Sopenharmony_ci goto out; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ciout: 6698c2ecf20Sopenharmony_ci return ret_val; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/** 6738c2ecf20Sopenharmony_ci * igc_get_speed_and_duplex_copper - Retrieve current speed/duplex 6748c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 6758c2ecf20Sopenharmony_ci * @speed: stores the current speed 6768c2ecf20Sopenharmony_ci * @duplex: stores the current duplex 6778c2ecf20Sopenharmony_ci * 6788c2ecf20Sopenharmony_ci * Read the status register for the current speed/duplex and store the current 6798c2ecf20Sopenharmony_ci * speed and duplex for copper connections. 6808c2ecf20Sopenharmony_ci */ 6818c2ecf20Sopenharmony_cis32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, 6828c2ecf20Sopenharmony_ci u16 *duplex) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci u32 status; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci status = rd32(IGC_STATUS); 6878c2ecf20Sopenharmony_ci if (status & IGC_STATUS_SPEED_1000) { 6888c2ecf20Sopenharmony_ci /* For I225, STATUS will indicate 1G speed in both 1 Gbps 6898c2ecf20Sopenharmony_ci * and 2.5 Gbps link modes. An additional bit is used 6908c2ecf20Sopenharmony_ci * to differentiate between 1 Gbps and 2.5 Gbps. 6918c2ecf20Sopenharmony_ci */ 6928c2ecf20Sopenharmony_ci if (hw->mac.type == igc_i225 && 6938c2ecf20Sopenharmony_ci (status & IGC_STATUS_SPEED_2500)) { 6948c2ecf20Sopenharmony_ci *speed = SPEED_2500; 6958c2ecf20Sopenharmony_ci hw_dbg("2500 Mbs, "); 6968c2ecf20Sopenharmony_ci } else { 6978c2ecf20Sopenharmony_ci *speed = SPEED_1000; 6988c2ecf20Sopenharmony_ci hw_dbg("1000 Mbs, "); 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci } else if (status & IGC_STATUS_SPEED_100) { 7018c2ecf20Sopenharmony_ci *speed = SPEED_100; 7028c2ecf20Sopenharmony_ci hw_dbg("100 Mbs, "); 7038c2ecf20Sopenharmony_ci } else { 7048c2ecf20Sopenharmony_ci *speed = SPEED_10; 7058c2ecf20Sopenharmony_ci hw_dbg("10 Mbs, "); 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (status & IGC_STATUS_FD) { 7098c2ecf20Sopenharmony_ci *duplex = FULL_DUPLEX; 7108c2ecf20Sopenharmony_ci hw_dbg("Full Duplex\n"); 7118c2ecf20Sopenharmony_ci } else { 7128c2ecf20Sopenharmony_ci *duplex = HALF_DUPLEX; 7138c2ecf20Sopenharmony_ci hw_dbg("Half Duplex\n"); 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci return 0; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci/** 7208c2ecf20Sopenharmony_ci * igc_put_hw_semaphore - Release hardware semaphore 7218c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7228c2ecf20Sopenharmony_ci * 7238c2ecf20Sopenharmony_ci * Release hardware semaphore used to access the PHY or NVM 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_civoid igc_put_hw_semaphore(struct igc_hw *hw) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci u32 swsm; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci swsm = rd32(IGC_SWSM); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci wr32(IGC_SWSM, swsm); 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci/** 7378c2ecf20Sopenharmony_ci * igc_enable_mng_pass_thru - Enable processing of ARP's 7388c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7398c2ecf20Sopenharmony_ci * 7408c2ecf20Sopenharmony_ci * Verifies the hardware needs to leave interface enabled so that frames can 7418c2ecf20Sopenharmony_ci * be directed to and from the management interface. 7428c2ecf20Sopenharmony_ci */ 7438c2ecf20Sopenharmony_cibool igc_enable_mng_pass_thru(struct igc_hw *hw) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci bool ret_val = false; 7468c2ecf20Sopenharmony_ci u32 fwsm, factps; 7478c2ecf20Sopenharmony_ci u32 manc; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (!hw->mac.asf_firmware_present) 7508c2ecf20Sopenharmony_ci goto out; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci manc = rd32(IGC_MANC); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (!(manc & IGC_MANC_RCV_TCO_EN)) 7558c2ecf20Sopenharmony_ci goto out; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (hw->mac.arc_subsystem_valid) { 7588c2ecf20Sopenharmony_ci fwsm = rd32(IGC_FWSM); 7598c2ecf20Sopenharmony_ci factps = rd32(IGC_FACTPS); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!(factps & IGC_FACTPS_MNGCG) && 7628c2ecf20Sopenharmony_ci ((fwsm & IGC_FWSM_MODE_MASK) == 7638c2ecf20Sopenharmony_ci (igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) { 7648c2ecf20Sopenharmony_ci ret_val = true; 7658c2ecf20Sopenharmony_ci goto out; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci } else { 7688c2ecf20Sopenharmony_ci if ((manc & IGC_MANC_SMBUS_EN) && 7698c2ecf20Sopenharmony_ci !(manc & IGC_MANC_ASF_EN)) { 7708c2ecf20Sopenharmony_ci ret_val = true; 7718c2ecf20Sopenharmony_ci goto out; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ciout: 7768c2ecf20Sopenharmony_ci return ret_val; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci/** 7808c2ecf20Sopenharmony_ci * igc_hash_mc_addr - Generate a multicast hash value 7818c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7828c2ecf20Sopenharmony_ci * @mc_addr: pointer to a multicast address 7838c2ecf20Sopenharmony_ci * 7848c2ecf20Sopenharmony_ci * Generates a multicast address hash value which is used to determine 7858c2ecf20Sopenharmony_ci * the multicast filter table array address and new table value. See 7868c2ecf20Sopenharmony_ci * igc_mta_set() 7878c2ecf20Sopenharmony_ci **/ 7888c2ecf20Sopenharmony_cistatic u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci u32 hash_value, hash_mask; 7918c2ecf20Sopenharmony_ci u8 bit_shift = 0; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* Register count multiplied by bits per register */ 7948c2ecf20Sopenharmony_ci hash_mask = (hw->mac.mta_reg_count * 32) - 1; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* For a mc_filter_type of 0, bit_shift is the number of left-shifts 7978c2ecf20Sopenharmony_ci * where 0xFF would still fall within the hash mask. 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_ci while (hash_mask >> bit_shift != 0xFF) 8008c2ecf20Sopenharmony_ci bit_shift++; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci /* The portion of the address that is used for the hash table 8038c2ecf20Sopenharmony_ci * is determined by the mc_filter_type setting. 8048c2ecf20Sopenharmony_ci * The algorithm is such that there is a total of 8 bits of shifting. 8058c2ecf20Sopenharmony_ci * The bit_shift for a mc_filter_type of 0 represents the number of 8068c2ecf20Sopenharmony_ci * left-shifts where the MSB of mc_addr[5] would still fall within 8078c2ecf20Sopenharmony_ci * the hash_mask. Case 0 does this exactly. Since there are a total 8088c2ecf20Sopenharmony_ci * of 8 bits of shifting, then mc_addr[4] will shift right the 8098c2ecf20Sopenharmony_ci * remaining number of bits. Thus 8 - bit_shift. The rest of the 8108c2ecf20Sopenharmony_ci * cases are a variation of this algorithm...essentially raising the 8118c2ecf20Sopenharmony_ci * number of bits to shift mc_addr[5] left, while still keeping the 8128c2ecf20Sopenharmony_ci * 8-bit shifting total. 8138c2ecf20Sopenharmony_ci * 8148c2ecf20Sopenharmony_ci * For example, given the following Destination MAC Address and an 8158c2ecf20Sopenharmony_ci * MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask), 8168c2ecf20Sopenharmony_ci * we can see that the bit_shift for case 0 is 4. These are the hash 8178c2ecf20Sopenharmony_ci * values resulting from each mc_filter_type... 8188c2ecf20Sopenharmony_ci * [0] [1] [2] [3] [4] [5] 8198c2ecf20Sopenharmony_ci * 01 AA 00 12 34 56 8208c2ecf20Sopenharmony_ci * LSB MSB 8218c2ecf20Sopenharmony_ci * 8228c2ecf20Sopenharmony_ci * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 8238c2ecf20Sopenharmony_ci * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 8248c2ecf20Sopenharmony_ci * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 8258c2ecf20Sopenharmony_ci * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci switch (hw->mac.mc_filter_type) { 8288c2ecf20Sopenharmony_ci default: 8298c2ecf20Sopenharmony_ci case 0: 8308c2ecf20Sopenharmony_ci break; 8318c2ecf20Sopenharmony_ci case 1: 8328c2ecf20Sopenharmony_ci bit_shift += 1; 8338c2ecf20Sopenharmony_ci break; 8348c2ecf20Sopenharmony_ci case 2: 8358c2ecf20Sopenharmony_ci bit_shift += 2; 8368c2ecf20Sopenharmony_ci break; 8378c2ecf20Sopenharmony_ci case 3: 8388c2ecf20Sopenharmony_ci bit_shift += 4; 8398c2ecf20Sopenharmony_ci break; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | 8438c2ecf20Sopenharmony_ci (((u16)mc_addr[5]) << bit_shift))); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci return hash_value; 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci/** 8498c2ecf20Sopenharmony_ci * igc_update_mc_addr_list - Update Multicast addresses 8508c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 8518c2ecf20Sopenharmony_ci * @mc_addr_list: array of multicast addresses to program 8528c2ecf20Sopenharmony_ci * @mc_addr_count: number of multicast addresses to program 8538c2ecf20Sopenharmony_ci * 8548c2ecf20Sopenharmony_ci * Updates entire Multicast Table Array. 8558c2ecf20Sopenharmony_ci * The caller must have a packed mc_addr_list of multicast addresses. 8568c2ecf20Sopenharmony_ci **/ 8578c2ecf20Sopenharmony_civoid igc_update_mc_addr_list(struct igc_hw *hw, 8588c2ecf20Sopenharmony_ci u8 *mc_addr_list, u32 mc_addr_count) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci u32 hash_value, hash_bit, hash_reg; 8618c2ecf20Sopenharmony_ci int i; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* clear mta_shadow */ 8648c2ecf20Sopenharmony_ci memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* update mta_shadow from mc_addr_list */ 8678c2ecf20Sopenharmony_ci for (i = 0; (u32)i < mc_addr_count; i++) { 8688c2ecf20Sopenharmony_ci hash_value = igc_hash_mc_addr(hw, mc_addr_list); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); 8718c2ecf20Sopenharmony_ci hash_bit = hash_value & 0x1F; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit); 8748c2ecf20Sopenharmony_ci mc_addr_list += ETH_ALEN; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* replace the entire MTA table */ 8788c2ecf20Sopenharmony_ci for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) 8798c2ecf20Sopenharmony_ci array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]); 8808c2ecf20Sopenharmony_ci wrfl(); 8818c2ecf20Sopenharmony_ci} 882