18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 2007 - 2018 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 58c2ecf20Sopenharmony_ci#include <linux/delay.h> 68c2ecf20Sopenharmony_ci#include <linux/pci.h> 78c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 88c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "e1000_mac.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "igb.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic s32 igb_set_default_fc(struct e1000_hw *hw); 158c2ecf20Sopenharmony_cistatic void igb_set_fc_watermarks(struct e1000_hw *hw); 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/** 188c2ecf20Sopenharmony_ci * igb_get_bus_info_pcie - Get PCIe bus information 198c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Determines and stores the system bus information for a particular 228c2ecf20Sopenharmony_ci * network interface. The following bus information is determined and stored: 238c2ecf20Sopenharmony_ci * bus speed, bus width, type (PCIe), and PCIe function. 248c2ecf20Sopenharmony_ci **/ 258c2ecf20Sopenharmony_cis32 igb_get_bus_info_pcie(struct e1000_hw *hw) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct e1000_bus_info *bus = &hw->bus; 288c2ecf20Sopenharmony_ci s32 ret_val; 298c2ecf20Sopenharmony_ci u32 reg; 308c2ecf20Sopenharmony_ci u16 pcie_link_status; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci bus->type = e1000_bus_type_pci_express; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci ret_val = igb_read_pcie_cap_reg(hw, 358c2ecf20Sopenharmony_ci PCI_EXP_LNKSTA, 368c2ecf20Sopenharmony_ci &pcie_link_status); 378c2ecf20Sopenharmony_ci if (ret_val) { 388c2ecf20Sopenharmony_ci bus->width = e1000_bus_width_unknown; 398c2ecf20Sopenharmony_ci bus->speed = e1000_bus_speed_unknown; 408c2ecf20Sopenharmony_ci } else { 418c2ecf20Sopenharmony_ci switch (pcie_link_status & PCI_EXP_LNKSTA_CLS) { 428c2ecf20Sopenharmony_ci case PCI_EXP_LNKSTA_CLS_2_5GB: 438c2ecf20Sopenharmony_ci bus->speed = e1000_bus_speed_2500; 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci case PCI_EXP_LNKSTA_CLS_5_0GB: 468c2ecf20Sopenharmony_ci bus->speed = e1000_bus_speed_5000; 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci default: 498c2ecf20Sopenharmony_ci bus->speed = e1000_bus_speed_unknown; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci bus->width = (enum e1000_bus_width)((pcie_link_status & 548c2ecf20Sopenharmony_ci PCI_EXP_LNKSTA_NLW) >> 558c2ecf20Sopenharmony_ci PCI_EXP_LNKSTA_NLW_SHIFT); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci reg = rd32(E1000_STATUS); 598c2ecf20Sopenharmony_ci bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * igb_clear_vfta - Clear VLAN filter table 668c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * Clears the register array which contains the VLAN filter table by 698c2ecf20Sopenharmony_ci * setting all the values to 0. 708c2ecf20Sopenharmony_ci **/ 718c2ecf20Sopenharmony_civoid igb_clear_vfta(struct e1000_hw *hw) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci u32 offset; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci for (offset = E1000_VLAN_FILTER_TBL_SIZE; offset--;) 768c2ecf20Sopenharmony_ci hw->mac.ops.write_vfta(hw, offset, 0); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * igb_write_vfta - Write value to VLAN filter table 818c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 828c2ecf20Sopenharmony_ci * @offset: register offset in VLAN filter table 838c2ecf20Sopenharmony_ci * @value: register value written to VLAN filter table 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * Writes value at the given offset in the register array which stores 868c2ecf20Sopenharmony_ci * the VLAN filter table. 878c2ecf20Sopenharmony_ci **/ 888c2ecf20Sopenharmony_civoid igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct igb_adapter *adapter = hw->back; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci array_wr32(E1000_VFTA, offset, value); 938c2ecf20Sopenharmony_ci wrfl(); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci adapter->shadow_vfta[offset] = value; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * igb_init_rx_addrs - Initialize receive address's 1008c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 1018c2ecf20Sopenharmony_ci * @rar_count: receive address registers 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Setups the receive address registers by setting the base receive address 1048c2ecf20Sopenharmony_ci * register to the devices MAC address and clearing all the other receive 1058c2ecf20Sopenharmony_ci * address registers to 0. 1068c2ecf20Sopenharmony_ci **/ 1078c2ecf20Sopenharmony_civoid igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci u32 i; 1108c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN] = {0}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Setup the receive address */ 1138c2ecf20Sopenharmony_ci hw_dbg("Programming MAC Address into RAR[0]\n"); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci hw->mac.ops.rar_set(hw, hw->mac.addr, 0); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Zero out the other (rar_entry_count - 1) receive addresses */ 1188c2ecf20Sopenharmony_ci hw_dbg("Clearing RAR[1-%u]\n", rar_count-1); 1198c2ecf20Sopenharmony_ci for (i = 1; i < rar_count; i++) 1208c2ecf20Sopenharmony_ci hw->mac.ops.rar_set(hw, mac_addr, i); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/** 1248c2ecf20Sopenharmony_ci * igb_find_vlvf_slot - find the VLAN id or the first empty slot 1258c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 1268c2ecf20Sopenharmony_ci * @vlan: VLAN id to write to VLAN filter 1278c2ecf20Sopenharmony_ci * @vlvf_bypass: skip VLVF if no match is found 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * return the VLVF index where this VLAN id should be placed 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci **/ 1328c2ecf20Sopenharmony_cistatic s32 igb_find_vlvf_slot(struct e1000_hw *hw, u32 vlan, bool vlvf_bypass) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci s32 regindex, first_empty_slot; 1358c2ecf20Sopenharmony_ci u32 bits; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* short cut the special case */ 1388c2ecf20Sopenharmony_ci if (vlan == 0) 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* if vlvf_bypass is set we don't want to use an empty slot, we 1428c2ecf20Sopenharmony_ci * will simply bypass the VLVF if there are no entries present in the 1438c2ecf20Sopenharmony_ci * VLVF that contain our VLAN 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci first_empty_slot = vlvf_bypass ? -E1000_ERR_NO_SPACE : 0; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* Search for the VLAN id in the VLVF entries. Save off the first empty 1488c2ecf20Sopenharmony_ci * slot found along the way. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * pre-decrement loop covering (IXGBE_VLVF_ENTRIES - 1) .. 1 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci for (regindex = E1000_VLVF_ARRAY_SIZE; --regindex > 0;) { 1538c2ecf20Sopenharmony_ci bits = rd32(E1000_VLVF(regindex)) & E1000_VLVF_VLANID_MASK; 1548c2ecf20Sopenharmony_ci if (bits == vlan) 1558c2ecf20Sopenharmony_ci return regindex; 1568c2ecf20Sopenharmony_ci if (!first_empty_slot && !bits) 1578c2ecf20Sopenharmony_ci first_empty_slot = regindex; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return first_empty_slot ? : -E1000_ERR_NO_SPACE; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/** 1648c2ecf20Sopenharmony_ci * igb_vfta_set - enable or disable vlan in VLAN filter table 1658c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 1668c2ecf20Sopenharmony_ci * @vlan: VLAN id to add or remove 1678c2ecf20Sopenharmony_ci * @vind: VMDq output index that maps queue to VLAN id 1688c2ecf20Sopenharmony_ci * @vlan_on: if true add filter, if false remove 1698c2ecf20Sopenharmony_ci * @vlvf_bypass: skip VLVF if no match is found 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Sets or clears a bit in the VLAN filter table array based on VLAN id 1728c2ecf20Sopenharmony_ci * and if we are adding or removing the filter 1738c2ecf20Sopenharmony_ci **/ 1748c2ecf20Sopenharmony_cis32 igb_vfta_set(struct e1000_hw *hw, u32 vlan, u32 vind, 1758c2ecf20Sopenharmony_ci bool vlan_on, bool vlvf_bypass) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct igb_adapter *adapter = hw->back; 1788c2ecf20Sopenharmony_ci u32 regidx, vfta_delta, vfta, bits; 1798c2ecf20Sopenharmony_ci s32 vlvf_index; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if ((vlan > 4095) || (vind > 7)) 1828c2ecf20Sopenharmony_ci return -E1000_ERR_PARAM; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* this is a 2 part operation - first the VFTA, then the 1858c2ecf20Sopenharmony_ci * VLVF and VLVFB if VT Mode is set 1868c2ecf20Sopenharmony_ci * We don't write the VFTA until we know the VLVF part succeeded. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Part 1 1908c2ecf20Sopenharmony_ci * The VFTA is a bitstring made up of 128 32-bit registers 1918c2ecf20Sopenharmony_ci * that enable the particular VLAN id, much like the MTA: 1928c2ecf20Sopenharmony_ci * bits[11-5]: which register 1938c2ecf20Sopenharmony_ci * bits[4-0]: which bit in the register 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_ci regidx = vlan / 32; 1968c2ecf20Sopenharmony_ci vfta_delta = BIT(vlan % 32); 1978c2ecf20Sopenharmony_ci vfta = adapter->shadow_vfta[regidx]; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* vfta_delta represents the difference between the current value 2008c2ecf20Sopenharmony_ci * of vfta and the value we want in the register. Since the diff 2018c2ecf20Sopenharmony_ci * is an XOR mask we can just update vfta using an XOR. 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ci vfta_delta &= vlan_on ? ~vfta : vfta; 2048c2ecf20Sopenharmony_ci vfta ^= vfta_delta; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Part 2 2078c2ecf20Sopenharmony_ci * If VT Mode is set 2088c2ecf20Sopenharmony_ci * Either vlan_on 2098c2ecf20Sopenharmony_ci * make sure the VLAN is in VLVF 2108c2ecf20Sopenharmony_ci * set the vind bit in the matching VLVFB 2118c2ecf20Sopenharmony_ci * Or !vlan_on 2128c2ecf20Sopenharmony_ci * clear the pool bit and possibly the vind 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci if (!adapter->vfs_allocated_count) 2158c2ecf20Sopenharmony_ci goto vfta_update; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci vlvf_index = igb_find_vlvf_slot(hw, vlan, vlvf_bypass); 2188c2ecf20Sopenharmony_ci if (vlvf_index < 0) { 2198c2ecf20Sopenharmony_ci if (vlvf_bypass) 2208c2ecf20Sopenharmony_ci goto vfta_update; 2218c2ecf20Sopenharmony_ci return vlvf_index; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci bits = rd32(E1000_VLVF(vlvf_index)); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* set the pool bit */ 2278c2ecf20Sopenharmony_ci bits |= BIT(E1000_VLVF_POOLSEL_SHIFT + vind); 2288c2ecf20Sopenharmony_ci if (vlan_on) 2298c2ecf20Sopenharmony_ci goto vlvf_update; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* clear the pool bit */ 2328c2ecf20Sopenharmony_ci bits ^= BIT(E1000_VLVF_POOLSEL_SHIFT + vind); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (!(bits & E1000_VLVF_POOLSEL_MASK)) { 2358c2ecf20Sopenharmony_ci /* Clear VFTA first, then disable VLVF. Otherwise 2368c2ecf20Sopenharmony_ci * we run the risk of stray packets leaking into 2378c2ecf20Sopenharmony_ci * the PF via the default pool 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci if (vfta_delta) 2408c2ecf20Sopenharmony_ci hw->mac.ops.write_vfta(hw, regidx, vfta); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* disable VLVF and clear remaining bit from pool */ 2438c2ecf20Sopenharmony_ci wr32(E1000_VLVF(vlvf_index), 0); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* If there are still bits set in the VLVFB registers 2498c2ecf20Sopenharmony_ci * for the VLAN ID indicated we need to see if the 2508c2ecf20Sopenharmony_ci * caller is requesting that we clear the VFTA entry bit. 2518c2ecf20Sopenharmony_ci * If the caller has requested that we clear the VFTA 2528c2ecf20Sopenharmony_ci * entry bit but there are still pools/VFs using this VLAN 2538c2ecf20Sopenharmony_ci * ID entry then ignore the request. We're not worried 2548c2ecf20Sopenharmony_ci * about the case where we're turning the VFTA VLAN ID 2558c2ecf20Sopenharmony_ci * entry bit on, only when requested to turn it off as 2568c2ecf20Sopenharmony_ci * there may be multiple pools and/or VFs using the 2578c2ecf20Sopenharmony_ci * VLAN ID entry. In that case we cannot clear the 2588c2ecf20Sopenharmony_ci * VFTA bit until all pools/VFs using that VLAN ID have also 2598c2ecf20Sopenharmony_ci * been cleared. This will be indicated by "bits" being 2608c2ecf20Sopenharmony_ci * zero. 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_ci vfta_delta = 0; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_civlvf_update: 2658c2ecf20Sopenharmony_ci /* record pool change and enable VLAN ID if not already enabled */ 2668c2ecf20Sopenharmony_ci wr32(E1000_VLVF(vlvf_index), bits | vlan | E1000_VLVF_VLANID_ENABLE); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_civfta_update: 2698c2ecf20Sopenharmony_ci /* bit was set/cleared before we started */ 2708c2ecf20Sopenharmony_ci if (vfta_delta) 2718c2ecf20Sopenharmony_ci hw->mac.ops.write_vfta(hw, regidx, vfta); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/** 2778c2ecf20Sopenharmony_ci * igb_check_alt_mac_addr - Check for alternate MAC addr 2788c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * Checks the nvm for an alternate MAC address. An alternate MAC address 2818c2ecf20Sopenharmony_ci * can be setup by pre-boot software and must be treated like a permanent 2828c2ecf20Sopenharmony_ci * address and must override the actual permanent MAC address. If an 2838c2ecf20Sopenharmony_ci * alternate MAC address is found it is saved in the hw struct and 2848c2ecf20Sopenharmony_ci * programmed into RAR0 and the function returns success, otherwise the 2858c2ecf20Sopenharmony_ci * function returns an error. 2868c2ecf20Sopenharmony_ci **/ 2878c2ecf20Sopenharmony_cis32 igb_check_alt_mac_addr(struct e1000_hw *hw) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci u32 i; 2908c2ecf20Sopenharmony_ci s32 ret_val = 0; 2918c2ecf20Sopenharmony_ci u16 offset, nvm_alt_mac_addr_offset, nvm_data; 2928c2ecf20Sopenharmony_ci u8 alt_mac_addr[ETH_ALEN]; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Alternate MAC address is handled by the option ROM for 82580 2958c2ecf20Sopenharmony_ci * and newer. SW support not required. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_82580) 2988c2ecf20Sopenharmony_ci goto out; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1, 3018c2ecf20Sopenharmony_ci &nvm_alt_mac_addr_offset); 3028c2ecf20Sopenharmony_ci if (ret_val) { 3038c2ecf20Sopenharmony_ci hw_dbg("NVM Read Error\n"); 3048c2ecf20Sopenharmony_ci goto out; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if ((nvm_alt_mac_addr_offset == 0xFFFF) || 3088c2ecf20Sopenharmony_ci (nvm_alt_mac_addr_offset == 0x0000)) 3098c2ecf20Sopenharmony_ci /* There is no Alternate MAC Address */ 3108c2ecf20Sopenharmony_ci goto out; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (hw->bus.func == E1000_FUNC_1) 3138c2ecf20Sopenharmony_ci nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1; 3148c2ecf20Sopenharmony_ci if (hw->bus.func == E1000_FUNC_2) 3158c2ecf20Sopenharmony_ci nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN2; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (hw->bus.func == E1000_FUNC_3) 3188c2ecf20Sopenharmony_ci nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN3; 3198c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i += 2) { 3208c2ecf20Sopenharmony_ci offset = nvm_alt_mac_addr_offset + (i >> 1); 3218c2ecf20Sopenharmony_ci ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); 3228c2ecf20Sopenharmony_ci if (ret_val) { 3238c2ecf20Sopenharmony_ci hw_dbg("NVM Read Error\n"); 3248c2ecf20Sopenharmony_ci goto out; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci alt_mac_addr[i] = (u8)(nvm_data & 0xFF); 3288c2ecf20Sopenharmony_ci alt_mac_addr[i + 1] = (u8)(nvm_data >> 8); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* if multicast bit is set, the alternate address will not be used */ 3328c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(alt_mac_addr)) { 3338c2ecf20Sopenharmony_ci hw_dbg("Ignoring Alternate Mac Address with MC bit set\n"); 3348c2ecf20Sopenharmony_ci goto out; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* We have a valid alternate MAC address, and we want to treat it the 3388c2ecf20Sopenharmony_ci * same as the normal permanent MAC address stored by the HW into the 3398c2ecf20Sopenharmony_ci * RAR. Do this by mapping this address into RAR0. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci hw->mac.ops.rar_set(hw, alt_mac_addr, 0); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ciout: 3448c2ecf20Sopenharmony_ci return ret_val; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci/** 3488c2ecf20Sopenharmony_ci * igb_rar_set - Set receive address register 3498c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 3508c2ecf20Sopenharmony_ci * @addr: pointer to the receive address 3518c2ecf20Sopenharmony_ci * @index: receive address array register 3528c2ecf20Sopenharmony_ci * 3538c2ecf20Sopenharmony_ci * Sets the receive address array register at index to the address passed 3548c2ecf20Sopenharmony_ci * in by addr. 3558c2ecf20Sopenharmony_ci **/ 3568c2ecf20Sopenharmony_civoid igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci u32 rar_low, rar_high; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* HW expects these in little endian so we reverse the byte order 3618c2ecf20Sopenharmony_ci * from network order (big endian) to little endian 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ci rar_low = ((u32) addr[0] | 3648c2ecf20Sopenharmony_ci ((u32) addr[1] << 8) | 3658c2ecf20Sopenharmony_ci ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* If MAC address zero, no need to set the AV bit */ 3708c2ecf20Sopenharmony_ci if (rar_low || rar_high) 3718c2ecf20Sopenharmony_ci rar_high |= E1000_RAH_AV; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* Some bridges will combine consecutive 32-bit writes into 3748c2ecf20Sopenharmony_ci * a single burst write, which will malfunction on some parts. 3758c2ecf20Sopenharmony_ci * The flushes avoid this. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_ci wr32(E1000_RAL(index), rar_low); 3788c2ecf20Sopenharmony_ci wrfl(); 3798c2ecf20Sopenharmony_ci wr32(E1000_RAH(index), rar_high); 3808c2ecf20Sopenharmony_ci wrfl(); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/** 3848c2ecf20Sopenharmony_ci * igb_mta_set - Set multicast filter table address 3858c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 3868c2ecf20Sopenharmony_ci * @hash_value: determines the MTA register and bit to set 3878c2ecf20Sopenharmony_ci * 3888c2ecf20Sopenharmony_ci * The multicast table address is a register array of 32-bit registers. 3898c2ecf20Sopenharmony_ci * The hash_value is used to determine what register the bit is in, the 3908c2ecf20Sopenharmony_ci * current value is read, the new bit is OR'd in and the new value is 3918c2ecf20Sopenharmony_ci * written back into the register. 3928c2ecf20Sopenharmony_ci **/ 3938c2ecf20Sopenharmony_civoid igb_mta_set(struct e1000_hw *hw, u32 hash_value) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci u32 hash_bit, hash_reg, mta; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* The MTA is a register array of 32-bit registers. It is 3988c2ecf20Sopenharmony_ci * treated like an array of (32*mta_reg_count) bits. We want to 3998c2ecf20Sopenharmony_ci * set bit BitArray[hash_value]. So we figure out what register 4008c2ecf20Sopenharmony_ci * the bit is in, read it, OR in the new bit, then write 4018c2ecf20Sopenharmony_ci * back the new value. The (hw->mac.mta_reg_count - 1) serves as a 4028c2ecf20Sopenharmony_ci * mask to bits 31:5 of the hash value which gives us the 4038c2ecf20Sopenharmony_ci * register we're modifying. The hash bit within that register 4048c2ecf20Sopenharmony_ci * is determined by the lower 5 bits of the hash value. 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ci hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); 4078c2ecf20Sopenharmony_ci hash_bit = hash_value & 0x1F; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci mta = array_rd32(E1000_MTA, hash_reg); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci mta |= BIT(hash_bit); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci array_wr32(E1000_MTA, hash_reg, mta); 4148c2ecf20Sopenharmony_ci wrfl(); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci/** 4188c2ecf20Sopenharmony_ci * igb_hash_mc_addr - Generate a multicast hash value 4198c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 4208c2ecf20Sopenharmony_ci * @mc_addr: pointer to a multicast address 4218c2ecf20Sopenharmony_ci * 4228c2ecf20Sopenharmony_ci * Generates a multicast address hash value which is used to determine 4238c2ecf20Sopenharmony_ci * the multicast filter table array address and new table value. See 4248c2ecf20Sopenharmony_ci * igb_mta_set() 4258c2ecf20Sopenharmony_ci **/ 4268c2ecf20Sopenharmony_cistatic u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci u32 hash_value, hash_mask; 4298c2ecf20Sopenharmony_ci u8 bit_shift = 1; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* Register count multiplied by bits per register */ 4328c2ecf20Sopenharmony_ci hash_mask = (hw->mac.mta_reg_count * 32) - 1; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* For a mc_filter_type of 0, bit_shift is the number of left-shifts 4358c2ecf20Sopenharmony_ci * where 0xFF would still fall within the hash mask. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ci while (hash_mask >> bit_shift != 0xFF && bit_shift < 4) 4388c2ecf20Sopenharmony_ci bit_shift++; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* The portion of the address that is used for the hash table 4418c2ecf20Sopenharmony_ci * is determined by the mc_filter_type setting. 4428c2ecf20Sopenharmony_ci * The algorithm is such that there is a total of 8 bits of shifting. 4438c2ecf20Sopenharmony_ci * The bit_shift for a mc_filter_type of 0 represents the number of 4448c2ecf20Sopenharmony_ci * left-shifts where the MSB of mc_addr[5] would still fall within 4458c2ecf20Sopenharmony_ci * the hash_mask. Case 0 does this exactly. Since there are a total 4468c2ecf20Sopenharmony_ci * of 8 bits of shifting, then mc_addr[4] will shift right the 4478c2ecf20Sopenharmony_ci * remaining number of bits. Thus 8 - bit_shift. The rest of the 4488c2ecf20Sopenharmony_ci * cases are a variation of this algorithm...essentially raising the 4498c2ecf20Sopenharmony_ci * number of bits to shift mc_addr[5] left, while still keeping the 4508c2ecf20Sopenharmony_ci * 8-bit shifting total. 4518c2ecf20Sopenharmony_ci * 4528c2ecf20Sopenharmony_ci * For example, given the following Destination MAC Address and an 4538c2ecf20Sopenharmony_ci * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask), 4548c2ecf20Sopenharmony_ci * we can see that the bit_shift for case 0 is 4. These are the hash 4558c2ecf20Sopenharmony_ci * values resulting from each mc_filter_type... 4568c2ecf20Sopenharmony_ci * [0] [1] [2] [3] [4] [5] 4578c2ecf20Sopenharmony_ci * 01 AA 00 12 34 56 4588c2ecf20Sopenharmony_ci * LSB MSB 4598c2ecf20Sopenharmony_ci * 4608c2ecf20Sopenharmony_ci * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 4618c2ecf20Sopenharmony_ci * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 4628c2ecf20Sopenharmony_ci * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 4638c2ecf20Sopenharmony_ci * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci switch (hw->mac.mc_filter_type) { 4668c2ecf20Sopenharmony_ci default: 4678c2ecf20Sopenharmony_ci case 0: 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci case 1: 4708c2ecf20Sopenharmony_ci bit_shift += 1; 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci case 2: 4738c2ecf20Sopenharmony_ci bit_shift += 2; 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci case 3: 4768c2ecf20Sopenharmony_ci bit_shift += 4; 4778c2ecf20Sopenharmony_ci break; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | 4818c2ecf20Sopenharmony_ci (((u16) mc_addr[5]) << bit_shift))); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return hash_value; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/** 4878c2ecf20Sopenharmony_ci * igb_update_mc_addr_list - Update Multicast addresses 4888c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 4898c2ecf20Sopenharmony_ci * @mc_addr_list: array of multicast addresses to program 4908c2ecf20Sopenharmony_ci * @mc_addr_count: number of multicast addresses to program 4918c2ecf20Sopenharmony_ci * 4928c2ecf20Sopenharmony_ci * Updates entire Multicast Table Array. 4938c2ecf20Sopenharmony_ci * The caller must have a packed mc_addr_list of multicast addresses. 4948c2ecf20Sopenharmony_ci **/ 4958c2ecf20Sopenharmony_civoid igb_update_mc_addr_list(struct e1000_hw *hw, 4968c2ecf20Sopenharmony_ci u8 *mc_addr_list, u32 mc_addr_count) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci u32 hash_value, hash_bit, hash_reg; 4998c2ecf20Sopenharmony_ci int i; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* clear mta_shadow */ 5028c2ecf20Sopenharmony_ci memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* update mta_shadow from mc_addr_list */ 5058c2ecf20Sopenharmony_ci for (i = 0; (u32) i < mc_addr_count; i++) { 5068c2ecf20Sopenharmony_ci hash_value = igb_hash_mc_addr(hw, mc_addr_list); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); 5098c2ecf20Sopenharmony_ci hash_bit = hash_value & 0x1F; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit); 5128c2ecf20Sopenharmony_ci mc_addr_list += (ETH_ALEN); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* replace the entire MTA table */ 5168c2ecf20Sopenharmony_ci for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) 5178c2ecf20Sopenharmony_ci array_wr32(E1000_MTA, i, hw->mac.mta_shadow[i]); 5188c2ecf20Sopenharmony_ci wrfl(); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci/** 5228c2ecf20Sopenharmony_ci * igb_clear_hw_cntrs_base - Clear base hardware counters 5238c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 5248c2ecf20Sopenharmony_ci * 5258c2ecf20Sopenharmony_ci * Clears the base hardware counters by reading the counter registers. 5268c2ecf20Sopenharmony_ci **/ 5278c2ecf20Sopenharmony_civoid igb_clear_hw_cntrs_base(struct e1000_hw *hw) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci rd32(E1000_CRCERRS); 5308c2ecf20Sopenharmony_ci rd32(E1000_SYMERRS); 5318c2ecf20Sopenharmony_ci rd32(E1000_MPC); 5328c2ecf20Sopenharmony_ci rd32(E1000_SCC); 5338c2ecf20Sopenharmony_ci rd32(E1000_ECOL); 5348c2ecf20Sopenharmony_ci rd32(E1000_MCC); 5358c2ecf20Sopenharmony_ci rd32(E1000_LATECOL); 5368c2ecf20Sopenharmony_ci rd32(E1000_COLC); 5378c2ecf20Sopenharmony_ci rd32(E1000_DC); 5388c2ecf20Sopenharmony_ci rd32(E1000_SEC); 5398c2ecf20Sopenharmony_ci rd32(E1000_RLEC); 5408c2ecf20Sopenharmony_ci rd32(E1000_XONRXC); 5418c2ecf20Sopenharmony_ci rd32(E1000_XONTXC); 5428c2ecf20Sopenharmony_ci rd32(E1000_XOFFRXC); 5438c2ecf20Sopenharmony_ci rd32(E1000_XOFFTXC); 5448c2ecf20Sopenharmony_ci rd32(E1000_FCRUC); 5458c2ecf20Sopenharmony_ci rd32(E1000_GPRC); 5468c2ecf20Sopenharmony_ci rd32(E1000_BPRC); 5478c2ecf20Sopenharmony_ci rd32(E1000_MPRC); 5488c2ecf20Sopenharmony_ci rd32(E1000_GPTC); 5498c2ecf20Sopenharmony_ci rd32(E1000_GORCL); 5508c2ecf20Sopenharmony_ci rd32(E1000_GORCH); 5518c2ecf20Sopenharmony_ci rd32(E1000_GOTCL); 5528c2ecf20Sopenharmony_ci rd32(E1000_GOTCH); 5538c2ecf20Sopenharmony_ci rd32(E1000_RNBC); 5548c2ecf20Sopenharmony_ci rd32(E1000_RUC); 5558c2ecf20Sopenharmony_ci rd32(E1000_RFC); 5568c2ecf20Sopenharmony_ci rd32(E1000_ROC); 5578c2ecf20Sopenharmony_ci rd32(E1000_RJC); 5588c2ecf20Sopenharmony_ci rd32(E1000_TORL); 5598c2ecf20Sopenharmony_ci rd32(E1000_TORH); 5608c2ecf20Sopenharmony_ci rd32(E1000_TOTL); 5618c2ecf20Sopenharmony_ci rd32(E1000_TOTH); 5628c2ecf20Sopenharmony_ci rd32(E1000_TPR); 5638c2ecf20Sopenharmony_ci rd32(E1000_TPT); 5648c2ecf20Sopenharmony_ci rd32(E1000_MPTC); 5658c2ecf20Sopenharmony_ci rd32(E1000_BPTC); 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci/** 5698c2ecf20Sopenharmony_ci * igb_check_for_copper_link - Check for link (Copper) 5708c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 5718c2ecf20Sopenharmony_ci * 5728c2ecf20Sopenharmony_ci * Checks to see of the link status of the hardware has changed. If a 5738c2ecf20Sopenharmony_ci * change in link status has been detected, then we read the PHY registers 5748c2ecf20Sopenharmony_ci * to get the current speed/duplex if link exists. 5758c2ecf20Sopenharmony_ci **/ 5768c2ecf20Sopenharmony_cis32 igb_check_for_copper_link(struct e1000_hw *hw) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct e1000_mac_info *mac = &hw->mac; 5798c2ecf20Sopenharmony_ci s32 ret_val; 5808c2ecf20Sopenharmony_ci bool link; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* We only want to go out to the PHY registers to see if Auto-Neg 5838c2ecf20Sopenharmony_ci * has completed and/or if our link status has changed. The 5848c2ecf20Sopenharmony_ci * get_link_status flag is set upon receiving a Link Status 5858c2ecf20Sopenharmony_ci * Change or Rx Sequence Error interrupt. 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_ci if (!mac->get_link_status) { 5888c2ecf20Sopenharmony_ci ret_val = 0; 5898c2ecf20Sopenharmony_ci goto out; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* First we want to see if the MII Status Register reports 5938c2ecf20Sopenharmony_ci * link. If so, then we want to get the current speed/duplex 5948c2ecf20Sopenharmony_ci * of the PHY. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci ret_val = igb_phy_has_link(hw, 1, 0, &link); 5978c2ecf20Sopenharmony_ci if (ret_val) 5988c2ecf20Sopenharmony_ci goto out; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (!link) 6018c2ecf20Sopenharmony_ci goto out; /* No link detected */ 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci mac->get_link_status = false; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* Check if there was DownShift, must be checked 6068c2ecf20Sopenharmony_ci * immediately after link-up 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ci igb_check_downshift(hw); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* If we are forcing speed/duplex, then we simply return since 6118c2ecf20Sopenharmony_ci * we have already determined whether we have link or not. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_ci if (!mac->autoneg) { 6148c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_CONFIG; 6158c2ecf20Sopenharmony_ci goto out; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* Auto-Neg is enabled. Auto Speed Detection takes care 6198c2ecf20Sopenharmony_ci * of MAC speed/duplex configuration. So we only need to 6208c2ecf20Sopenharmony_ci * configure Collision Distance in the MAC. 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_ci igb_config_collision_dist(hw); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Configure Flow Control now that Auto-Neg has completed. 6258c2ecf20Sopenharmony_ci * First, we need to restore the desired flow control 6268c2ecf20Sopenharmony_ci * settings because we may have had to re-autoneg with a 6278c2ecf20Sopenharmony_ci * different link partner. 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci ret_val = igb_config_fc_after_link_up(hw); 6308c2ecf20Sopenharmony_ci if (ret_val) 6318c2ecf20Sopenharmony_ci hw_dbg("Error configuring flow control\n"); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ciout: 6348c2ecf20Sopenharmony_ci return ret_val; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci/** 6388c2ecf20Sopenharmony_ci * igb_setup_link - Setup flow control and link settings 6398c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 6408c2ecf20Sopenharmony_ci * 6418c2ecf20Sopenharmony_ci * Determines which flow control settings to use, then configures flow 6428c2ecf20Sopenharmony_ci * control. Calls the appropriate media-specific link configuration 6438c2ecf20Sopenharmony_ci * function. Assuming the adapter has a valid link partner, a valid link 6448c2ecf20Sopenharmony_ci * should be established. Assumes the hardware has previously been reset 6458c2ecf20Sopenharmony_ci * and the transmitter and receiver are not enabled. 6468c2ecf20Sopenharmony_ci **/ 6478c2ecf20Sopenharmony_cis32 igb_setup_link(struct e1000_hw *hw) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci s32 ret_val = 0; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* In the case of the phy reset being blocked, we already have a link. 6528c2ecf20Sopenharmony_ci * We do not need to set it up again. 6538c2ecf20Sopenharmony_ci */ 6548c2ecf20Sopenharmony_ci if (igb_check_reset_block(hw)) 6558c2ecf20Sopenharmony_ci goto out; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* If requested flow control is set to default, set flow control 6588c2ecf20Sopenharmony_ci * based on the EEPROM flow control settings. 6598c2ecf20Sopenharmony_ci */ 6608c2ecf20Sopenharmony_ci if (hw->fc.requested_mode == e1000_fc_default) { 6618c2ecf20Sopenharmony_ci ret_val = igb_set_default_fc(hw); 6628c2ecf20Sopenharmony_ci if (ret_val) 6638c2ecf20Sopenharmony_ci goto out; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* We want to save off the original Flow Control configuration just 6678c2ecf20Sopenharmony_ci * in case we get disconnected and then reconnected into a different 6688c2ecf20Sopenharmony_ci * hub or switch with different Flow Control capabilities. 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci hw->fc.current_mode = hw->fc.requested_mode; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* Call the necessary media_type subroutine to configure the link. */ 6758c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.setup_physical_interface(hw); 6768c2ecf20Sopenharmony_ci if (ret_val) 6778c2ecf20Sopenharmony_ci goto out; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* Initialize the flow control address, type, and PAUSE timer 6808c2ecf20Sopenharmony_ci * registers to their default values. This is done even if flow 6818c2ecf20Sopenharmony_ci * control is disabled, because it does not hurt anything to 6828c2ecf20Sopenharmony_ci * initialize these registers. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci hw_dbg("Initializing the Flow Control address, type and timer regs\n"); 6858c2ecf20Sopenharmony_ci wr32(E1000_FCT, FLOW_CONTROL_TYPE); 6868c2ecf20Sopenharmony_ci wr32(E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH); 6878c2ecf20Sopenharmony_ci wr32(E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci wr32(E1000_FCTTV, hw->fc.pause_time); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci igb_set_fc_watermarks(hw); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ciout: 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return ret_val; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/** 6998c2ecf20Sopenharmony_ci * igb_config_collision_dist - Configure collision distance 7008c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7018c2ecf20Sopenharmony_ci * 7028c2ecf20Sopenharmony_ci * Configures the collision distance to the default value and is used 7038c2ecf20Sopenharmony_ci * during link setup. Currently no func pointer exists and all 7048c2ecf20Sopenharmony_ci * implementations are handled in the generic version of this function. 7058c2ecf20Sopenharmony_ci **/ 7068c2ecf20Sopenharmony_civoid igb_config_collision_dist(struct e1000_hw *hw) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci u32 tctl; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci tctl = rd32(E1000_TCTL); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci tctl &= ~E1000_TCTL_COLD; 7138c2ecf20Sopenharmony_ci tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci wr32(E1000_TCTL, tctl); 7168c2ecf20Sopenharmony_ci wrfl(); 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci/** 7208c2ecf20Sopenharmony_ci * igb_set_fc_watermarks - Set flow control high/low watermarks 7218c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7228c2ecf20Sopenharmony_ci * 7238c2ecf20Sopenharmony_ci * Sets the flow control high/low threshold (watermark) registers. If 7248c2ecf20Sopenharmony_ci * flow control XON frame transmission is enabled, then set XON frame 7258c2ecf20Sopenharmony_ci * tansmission as well. 7268c2ecf20Sopenharmony_ci **/ 7278c2ecf20Sopenharmony_cistatic void igb_set_fc_watermarks(struct e1000_hw *hw) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci u32 fcrtl = 0, fcrth = 0; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Set the flow control receive threshold registers. Normally, 7328c2ecf20Sopenharmony_ci * these registers will be set to a default threshold that may be 7338c2ecf20Sopenharmony_ci * adjusted later by the driver's runtime code. However, if the 7348c2ecf20Sopenharmony_ci * ability to transmit pause frames is not enabled, then these 7358c2ecf20Sopenharmony_ci * registers will be set to 0. 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_ci if (hw->fc.current_mode & e1000_fc_tx_pause) { 7388c2ecf20Sopenharmony_ci /* We need to set up the Receive Threshold high and low water 7398c2ecf20Sopenharmony_ci * marks as well as (optionally) enabling the transmission of 7408c2ecf20Sopenharmony_ci * XON frames. 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_ci fcrtl = hw->fc.low_water; 7438c2ecf20Sopenharmony_ci if (hw->fc.send_xon) 7448c2ecf20Sopenharmony_ci fcrtl |= E1000_FCRTL_XONE; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci fcrth = hw->fc.high_water; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci wr32(E1000_FCRTL, fcrtl); 7498c2ecf20Sopenharmony_ci wr32(E1000_FCRTH, fcrth); 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci/** 7538c2ecf20Sopenharmony_ci * igb_set_default_fc - Set flow control default values 7548c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7558c2ecf20Sopenharmony_ci * 7568c2ecf20Sopenharmony_ci * Read the EEPROM for the default values for flow control and store the 7578c2ecf20Sopenharmony_ci * values. 7588c2ecf20Sopenharmony_ci **/ 7598c2ecf20Sopenharmony_cistatic s32 igb_set_default_fc(struct e1000_hw *hw) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci s32 ret_val = 0; 7628c2ecf20Sopenharmony_ci u16 lan_offset; 7638c2ecf20Sopenharmony_ci u16 nvm_data; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* Read and store word 0x0F of the EEPROM. This word contains bits 7668c2ecf20Sopenharmony_ci * that determine the hardware's default PAUSE (flow control) mode, 7678c2ecf20Sopenharmony_ci * a bit that determines whether the HW defaults to enabling or 7688c2ecf20Sopenharmony_ci * disabling auto-negotiation, and the direction of the 7698c2ecf20Sopenharmony_ci * SW defined pins. If there is no SW over-ride of the flow 7708c2ecf20Sopenharmony_ci * control setting, then the variable hw->fc will 7718c2ecf20Sopenharmony_ci * be initialized based on a value in the EEPROM. 7728c2ecf20Sopenharmony_ci */ 7738c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_i350) 7748c2ecf20Sopenharmony_ci lan_offset = NVM_82580_LAN_FUNC_OFFSET(hw->bus.func); 7758c2ecf20Sopenharmony_ci else 7768c2ecf20Sopenharmony_ci lan_offset = 0; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG + lan_offset, 7798c2ecf20Sopenharmony_ci 1, &nvm_data); 7808c2ecf20Sopenharmony_ci if (ret_val) { 7818c2ecf20Sopenharmony_ci hw_dbg("NVM Read Error\n"); 7828c2ecf20Sopenharmony_ci goto out; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) 7868c2ecf20Sopenharmony_ci hw->fc.requested_mode = e1000_fc_none; 7878c2ecf20Sopenharmony_ci else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == NVM_WORD0F_ASM_DIR) 7888c2ecf20Sopenharmony_ci hw->fc.requested_mode = e1000_fc_tx_pause; 7898c2ecf20Sopenharmony_ci else 7908c2ecf20Sopenharmony_ci hw->fc.requested_mode = e1000_fc_full; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ciout: 7938c2ecf20Sopenharmony_ci return ret_val; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci/** 7978c2ecf20Sopenharmony_ci * igb_force_mac_fc - Force the MAC's flow control settings 7988c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7998c2ecf20Sopenharmony_ci * 8008c2ecf20Sopenharmony_ci * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the 8018c2ecf20Sopenharmony_ci * device control register to reflect the adapter settings. TFCE and RFCE 8028c2ecf20Sopenharmony_ci * need to be explicitly set by software when a copper PHY is used because 8038c2ecf20Sopenharmony_ci * autonegotiation is managed by the PHY rather than the MAC. Software must 8048c2ecf20Sopenharmony_ci * also configure these bits when link is forced on a fiber connection. 8058c2ecf20Sopenharmony_ci **/ 8068c2ecf20Sopenharmony_cis32 igb_force_mac_fc(struct e1000_hw *hw) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci u32 ctrl; 8098c2ecf20Sopenharmony_ci s32 ret_val = 0; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci ctrl = rd32(E1000_CTRL); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci /* Because we didn't get link via the internal auto-negotiation 8148c2ecf20Sopenharmony_ci * mechanism (we either forced link or we got link via PHY 8158c2ecf20Sopenharmony_ci * auto-neg), we have to manually enable/disable transmit an 8168c2ecf20Sopenharmony_ci * receive flow control. 8178c2ecf20Sopenharmony_ci * 8188c2ecf20Sopenharmony_ci * The "Case" statement below enables/disable flow control 8198c2ecf20Sopenharmony_ci * according to the "hw->fc.current_mode" parameter. 8208c2ecf20Sopenharmony_ci * 8218c2ecf20Sopenharmony_ci * The possible values of the "fc" parameter are: 8228c2ecf20Sopenharmony_ci * 0: Flow control is completely disabled 8238c2ecf20Sopenharmony_ci * 1: Rx flow control is enabled (we can receive pause 8248c2ecf20Sopenharmony_ci * frames but not send pause frames). 8258c2ecf20Sopenharmony_ci * 2: Tx flow control is enabled (we can send pause frames 8268c2ecf20Sopenharmony_ci * frames but we do not receive pause frames). 8278c2ecf20Sopenharmony_ci * 3: Both Rx and TX flow control (symmetric) is enabled. 8288c2ecf20Sopenharmony_ci * other: No other values should be possible at this point. 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_ci hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci switch (hw->fc.current_mode) { 8338c2ecf20Sopenharmony_ci case e1000_fc_none: 8348c2ecf20Sopenharmony_ci ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci case e1000_fc_rx_pause: 8378c2ecf20Sopenharmony_ci ctrl &= (~E1000_CTRL_TFCE); 8388c2ecf20Sopenharmony_ci ctrl |= E1000_CTRL_RFCE; 8398c2ecf20Sopenharmony_ci break; 8408c2ecf20Sopenharmony_ci case e1000_fc_tx_pause: 8418c2ecf20Sopenharmony_ci ctrl &= (~E1000_CTRL_RFCE); 8428c2ecf20Sopenharmony_ci ctrl |= E1000_CTRL_TFCE; 8438c2ecf20Sopenharmony_ci break; 8448c2ecf20Sopenharmony_ci case e1000_fc_full: 8458c2ecf20Sopenharmony_ci ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); 8468c2ecf20Sopenharmony_ci break; 8478c2ecf20Sopenharmony_ci default: 8488c2ecf20Sopenharmony_ci hw_dbg("Flow control param set incorrectly\n"); 8498c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_CONFIG; 8508c2ecf20Sopenharmony_ci goto out; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci wr32(E1000_CTRL, ctrl); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ciout: 8568c2ecf20Sopenharmony_ci return ret_val; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci/** 8608c2ecf20Sopenharmony_ci * igb_config_fc_after_link_up - Configures flow control after link 8618c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 8628c2ecf20Sopenharmony_ci * 8638c2ecf20Sopenharmony_ci * Checks the status of auto-negotiation after link up to ensure that the 8648c2ecf20Sopenharmony_ci * speed and duplex were not forced. If the link needed to be forced, then 8658c2ecf20Sopenharmony_ci * flow control needs to be forced also. If auto-negotiation is enabled 8668c2ecf20Sopenharmony_ci * and did not fail, then we configure flow control based on our link 8678c2ecf20Sopenharmony_ci * partner. 8688c2ecf20Sopenharmony_ci **/ 8698c2ecf20Sopenharmony_cis32 igb_config_fc_after_link_up(struct e1000_hw *hw) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci struct e1000_mac_info *mac = &hw->mac; 8728c2ecf20Sopenharmony_ci s32 ret_val = 0; 8738c2ecf20Sopenharmony_ci u32 pcs_status_reg, pcs_adv_reg, pcs_lp_ability_reg, pcs_ctrl_reg; 8748c2ecf20Sopenharmony_ci u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; 8758c2ecf20Sopenharmony_ci u16 speed, duplex; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* Check for the case where we have fiber media and auto-neg failed 8788c2ecf20Sopenharmony_ci * so we had to force link. In this case, we need to force the 8798c2ecf20Sopenharmony_ci * configuration of the MAC to match the "fc" parameter. 8808c2ecf20Sopenharmony_ci */ 8818c2ecf20Sopenharmony_ci if (mac->autoneg_failed) { 8828c2ecf20Sopenharmony_ci if (hw->phy.media_type == e1000_media_type_internal_serdes) 8838c2ecf20Sopenharmony_ci ret_val = igb_force_mac_fc(hw); 8848c2ecf20Sopenharmony_ci } else { 8858c2ecf20Sopenharmony_ci if (hw->phy.media_type == e1000_media_type_copper) 8868c2ecf20Sopenharmony_ci ret_val = igb_force_mac_fc(hw); 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (ret_val) { 8908c2ecf20Sopenharmony_ci hw_dbg("Error forcing flow control settings\n"); 8918c2ecf20Sopenharmony_ci goto out; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* Check for the case where we have copper media and auto-neg is 8958c2ecf20Sopenharmony_ci * enabled. In this case, we need to check and see if Auto-Neg 8968c2ecf20Sopenharmony_ci * has completed, and if so, how the PHY and link partner has 8978c2ecf20Sopenharmony_ci * flow control configured. 8988c2ecf20Sopenharmony_ci */ 8998c2ecf20Sopenharmony_ci if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) { 9008c2ecf20Sopenharmony_ci /* Read the MII Status Register and check to see if AutoNeg 9018c2ecf20Sopenharmony_ci * has completed. We read this twice because this reg has 9028c2ecf20Sopenharmony_ci * some "sticky" (latched) bits. 9038c2ecf20Sopenharmony_ci */ 9048c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, 9058c2ecf20Sopenharmony_ci &mii_status_reg); 9068c2ecf20Sopenharmony_ci if (ret_val) 9078c2ecf20Sopenharmony_ci goto out; 9088c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, 9098c2ecf20Sopenharmony_ci &mii_status_reg); 9108c2ecf20Sopenharmony_ci if (ret_val) 9118c2ecf20Sopenharmony_ci goto out; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { 9148c2ecf20Sopenharmony_ci hw_dbg("Copper PHY and Auto Neg has not completed.\n"); 9158c2ecf20Sopenharmony_ci goto out; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* The AutoNeg process has completed, so we now need to 9198c2ecf20Sopenharmony_ci * read both the Auto Negotiation Advertisement 9208c2ecf20Sopenharmony_ci * Register (Address 4) and the Auto_Negotiation Base 9218c2ecf20Sopenharmony_ci * Page Ability Register (Address 5) to determine how 9228c2ecf20Sopenharmony_ci * flow control was negotiated. 9238c2ecf20Sopenharmony_ci */ 9248c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, 9258c2ecf20Sopenharmony_ci &mii_nway_adv_reg); 9268c2ecf20Sopenharmony_ci if (ret_val) 9278c2ecf20Sopenharmony_ci goto out; 9288c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, 9298c2ecf20Sopenharmony_ci &mii_nway_lp_ability_reg); 9308c2ecf20Sopenharmony_ci if (ret_val) 9318c2ecf20Sopenharmony_ci goto out; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* Two bits in the Auto Negotiation Advertisement Register 9348c2ecf20Sopenharmony_ci * (Address 4) and two bits in the Auto Negotiation Base 9358c2ecf20Sopenharmony_ci * Page Ability Register (Address 5) determine flow control 9368c2ecf20Sopenharmony_ci * for both the PHY and the link partner. The following 9378c2ecf20Sopenharmony_ci * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, 9388c2ecf20Sopenharmony_ci * 1999, describes these PAUSE resolution bits and how flow 9398c2ecf20Sopenharmony_ci * control is determined based upon these settings. 9408c2ecf20Sopenharmony_ci * NOTE: DC = Don't Care 9418c2ecf20Sopenharmony_ci * 9428c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 9438c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution 9448c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 9458c2ecf20Sopenharmony_ci * 0 | 0 | DC | DC | e1000_fc_none 9468c2ecf20Sopenharmony_ci * 0 | 1 | 0 | DC | e1000_fc_none 9478c2ecf20Sopenharmony_ci * 0 | 1 | 1 | 0 | e1000_fc_none 9488c2ecf20Sopenharmony_ci * 0 | 1 | 1 | 1 | e1000_fc_tx_pause 9498c2ecf20Sopenharmony_ci * 1 | 0 | 0 | DC | e1000_fc_none 9508c2ecf20Sopenharmony_ci * 1 | DC | 1 | DC | e1000_fc_full 9518c2ecf20Sopenharmony_ci * 1 | 1 | 0 | 0 | e1000_fc_none 9528c2ecf20Sopenharmony_ci * 1 | 1 | 0 | 1 | e1000_fc_rx_pause 9538c2ecf20Sopenharmony_ci * 9548c2ecf20Sopenharmony_ci * Are both PAUSE bits set to 1? If so, this implies 9558c2ecf20Sopenharmony_ci * Symmetric Flow Control is enabled at both ends. The 9568c2ecf20Sopenharmony_ci * ASM_DIR bits are irrelevant per the spec. 9578c2ecf20Sopenharmony_ci * 9588c2ecf20Sopenharmony_ci * For Symmetric Flow Control: 9598c2ecf20Sopenharmony_ci * 9608c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 9618c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result 9628c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 9638c2ecf20Sopenharmony_ci * 1 | DC | 1 | DC | E1000_fc_full 9648c2ecf20Sopenharmony_ci * 9658c2ecf20Sopenharmony_ci */ 9668c2ecf20Sopenharmony_ci if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && 9678c2ecf20Sopenharmony_ci (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { 9688c2ecf20Sopenharmony_ci /* Now we need to check if the user selected RX ONLY 9698c2ecf20Sopenharmony_ci * of pause frames. In this case, we had to advertise 9708c2ecf20Sopenharmony_ci * FULL flow control because we could not advertise RX 9718c2ecf20Sopenharmony_ci * ONLY. Hence, we must now check to see if we need to 9728c2ecf20Sopenharmony_ci * turn OFF the TRANSMISSION of PAUSE frames. 9738c2ecf20Sopenharmony_ci */ 9748c2ecf20Sopenharmony_ci if (hw->fc.requested_mode == e1000_fc_full) { 9758c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_full; 9768c2ecf20Sopenharmony_ci hw_dbg("Flow Control = FULL.\n"); 9778c2ecf20Sopenharmony_ci } else { 9788c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_rx_pause; 9798c2ecf20Sopenharmony_ci hw_dbg("Flow Control = RX PAUSE frames only.\n"); 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci /* For receiving PAUSE frames ONLY. 9838c2ecf20Sopenharmony_ci * 9848c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 9858c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result 9868c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 9878c2ecf20Sopenharmony_ci * 0 | 1 | 1 | 1 | e1000_fc_tx_pause 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_ci else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && 9908c2ecf20Sopenharmony_ci (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && 9918c2ecf20Sopenharmony_ci (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && 9928c2ecf20Sopenharmony_ci (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { 9938c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_tx_pause; 9948c2ecf20Sopenharmony_ci hw_dbg("Flow Control = TX PAUSE frames only.\n"); 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci /* For transmitting PAUSE frames ONLY. 9978c2ecf20Sopenharmony_ci * 9988c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 9998c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result 10008c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 10018c2ecf20Sopenharmony_ci * 1 | 1 | 0 | 1 | e1000_fc_rx_pause 10028c2ecf20Sopenharmony_ci */ 10038c2ecf20Sopenharmony_ci else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && 10048c2ecf20Sopenharmony_ci (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && 10058c2ecf20Sopenharmony_ci !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && 10068c2ecf20Sopenharmony_ci (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { 10078c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_rx_pause; 10088c2ecf20Sopenharmony_ci hw_dbg("Flow Control = RX PAUSE frames only.\n"); 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci /* Per the IEEE spec, at this point flow control should be 10118c2ecf20Sopenharmony_ci * disabled. However, we want to consider that we could 10128c2ecf20Sopenharmony_ci * be connected to a legacy switch that doesn't advertise 10138c2ecf20Sopenharmony_ci * desired flow control, but can be forced on the link 10148c2ecf20Sopenharmony_ci * partner. So if we advertised no flow control, that is 10158c2ecf20Sopenharmony_ci * what we will resolve to. If we advertised some kind of 10168c2ecf20Sopenharmony_ci * receive capability (Rx Pause Only or Full Flow Control) 10178c2ecf20Sopenharmony_ci * and the link partner advertised none, we will configure 10188c2ecf20Sopenharmony_ci * ourselves to enable Rx Flow Control only. We can do 10198c2ecf20Sopenharmony_ci * this safely for two reasons: If the link partner really 10208c2ecf20Sopenharmony_ci * didn't want flow control enabled, and we enable Rx, no 10218c2ecf20Sopenharmony_ci * harm done since we won't be receiving any PAUSE frames 10228c2ecf20Sopenharmony_ci * anyway. If the intent on the link partner was to have 10238c2ecf20Sopenharmony_ci * flow control enabled, then by us enabling RX only, we 10248c2ecf20Sopenharmony_ci * can at least receive pause frames and process them. 10258c2ecf20Sopenharmony_ci * This is a good idea because in most cases, since we are 10268c2ecf20Sopenharmony_ci * predominantly a server NIC, more times than not we will 10278c2ecf20Sopenharmony_ci * be asked to delay transmission of packets than asking 10288c2ecf20Sopenharmony_ci * our link partner to pause transmission of frames. 10298c2ecf20Sopenharmony_ci */ 10308c2ecf20Sopenharmony_ci else if ((hw->fc.requested_mode == e1000_fc_none) || 10318c2ecf20Sopenharmony_ci (hw->fc.requested_mode == e1000_fc_tx_pause) || 10328c2ecf20Sopenharmony_ci (hw->fc.strict_ieee)) { 10338c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_none; 10348c2ecf20Sopenharmony_ci hw_dbg("Flow Control = NONE.\n"); 10358c2ecf20Sopenharmony_ci } else { 10368c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_rx_pause; 10378c2ecf20Sopenharmony_ci hw_dbg("Flow Control = RX PAUSE frames only.\n"); 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci /* Now we need to do one last check... If we auto- 10418c2ecf20Sopenharmony_ci * negotiated to HALF DUPLEX, flow control should not be 10428c2ecf20Sopenharmony_ci * enabled per IEEE 802.3 spec. 10438c2ecf20Sopenharmony_ci */ 10448c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); 10458c2ecf20Sopenharmony_ci if (ret_val) { 10468c2ecf20Sopenharmony_ci hw_dbg("Error getting link speed and duplex\n"); 10478c2ecf20Sopenharmony_ci goto out; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (duplex == HALF_DUPLEX) 10518c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_none; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* Now we call a subroutine to actually force the MAC 10548c2ecf20Sopenharmony_ci * controller to use the correct flow control settings. 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci ret_val = igb_force_mac_fc(hw); 10578c2ecf20Sopenharmony_ci if (ret_val) { 10588c2ecf20Sopenharmony_ci hw_dbg("Error forcing flow control settings\n"); 10598c2ecf20Sopenharmony_ci goto out; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci /* Check for the case where we have SerDes media and auto-neg is 10638c2ecf20Sopenharmony_ci * enabled. In this case, we need to check and see if Auto-Neg 10648c2ecf20Sopenharmony_ci * has completed, and if so, how the PHY and link partner has 10658c2ecf20Sopenharmony_ci * flow control configured. 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_ci if ((hw->phy.media_type == e1000_media_type_internal_serdes) 10688c2ecf20Sopenharmony_ci && mac->autoneg) { 10698c2ecf20Sopenharmony_ci /* Read the PCS_LSTS and check to see if AutoNeg 10708c2ecf20Sopenharmony_ci * has completed. 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci pcs_status_reg = rd32(E1000_PCS_LSTAT); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (!(pcs_status_reg & E1000_PCS_LSTS_AN_COMPLETE)) { 10758c2ecf20Sopenharmony_ci hw_dbg("PCS Auto Neg has not completed.\n"); 10768c2ecf20Sopenharmony_ci return ret_val; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* The AutoNeg process has completed, so we now need to 10808c2ecf20Sopenharmony_ci * read both the Auto Negotiation Advertisement 10818c2ecf20Sopenharmony_ci * Register (PCS_ANADV) and the Auto_Negotiation Base 10828c2ecf20Sopenharmony_ci * Page Ability Register (PCS_LPAB) to determine how 10838c2ecf20Sopenharmony_ci * flow control was negotiated. 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_ci pcs_adv_reg = rd32(E1000_PCS_ANADV); 10868c2ecf20Sopenharmony_ci pcs_lp_ability_reg = rd32(E1000_PCS_LPAB); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* Two bits in the Auto Negotiation Advertisement Register 10898c2ecf20Sopenharmony_ci * (PCS_ANADV) and two bits in the Auto Negotiation Base 10908c2ecf20Sopenharmony_ci * Page Ability Register (PCS_LPAB) determine flow control 10918c2ecf20Sopenharmony_ci * for both the PHY and the link partner. The following 10928c2ecf20Sopenharmony_ci * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, 10938c2ecf20Sopenharmony_ci * 1999, describes these PAUSE resolution bits and how flow 10948c2ecf20Sopenharmony_ci * control is determined based upon these settings. 10958c2ecf20Sopenharmony_ci * NOTE: DC = Don't Care 10968c2ecf20Sopenharmony_ci * 10978c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 10988c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution 10998c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 11008c2ecf20Sopenharmony_ci * 0 | 0 | DC | DC | e1000_fc_none 11018c2ecf20Sopenharmony_ci * 0 | 1 | 0 | DC | e1000_fc_none 11028c2ecf20Sopenharmony_ci * 0 | 1 | 1 | 0 | e1000_fc_none 11038c2ecf20Sopenharmony_ci * 0 | 1 | 1 | 1 | e1000_fc_tx_pause 11048c2ecf20Sopenharmony_ci * 1 | 0 | 0 | DC | e1000_fc_none 11058c2ecf20Sopenharmony_ci * 1 | DC | 1 | DC | e1000_fc_full 11068c2ecf20Sopenharmony_ci * 1 | 1 | 0 | 0 | e1000_fc_none 11078c2ecf20Sopenharmony_ci * 1 | 1 | 0 | 1 | e1000_fc_rx_pause 11088c2ecf20Sopenharmony_ci * 11098c2ecf20Sopenharmony_ci * Are both PAUSE bits set to 1? If so, this implies 11108c2ecf20Sopenharmony_ci * Symmetric Flow Control is enabled at both ends. The 11118c2ecf20Sopenharmony_ci * ASM_DIR bits are irrelevant per the spec. 11128c2ecf20Sopenharmony_ci * 11138c2ecf20Sopenharmony_ci * For Symmetric Flow Control: 11148c2ecf20Sopenharmony_ci * 11158c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 11168c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result 11178c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 11188c2ecf20Sopenharmony_ci * 1 | DC | 1 | DC | e1000_fc_full 11198c2ecf20Sopenharmony_ci * 11208c2ecf20Sopenharmony_ci */ 11218c2ecf20Sopenharmony_ci if ((pcs_adv_reg & E1000_TXCW_PAUSE) && 11228c2ecf20Sopenharmony_ci (pcs_lp_ability_reg & E1000_TXCW_PAUSE)) { 11238c2ecf20Sopenharmony_ci /* Now we need to check if the user selected Rx ONLY 11248c2ecf20Sopenharmony_ci * of pause frames. In this case, we had to advertise 11258c2ecf20Sopenharmony_ci * FULL flow control because we could not advertise Rx 11268c2ecf20Sopenharmony_ci * ONLY. Hence, we must now check to see if we need to 11278c2ecf20Sopenharmony_ci * turn OFF the TRANSMISSION of PAUSE frames. 11288c2ecf20Sopenharmony_ci */ 11298c2ecf20Sopenharmony_ci if (hw->fc.requested_mode == e1000_fc_full) { 11308c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_full; 11318c2ecf20Sopenharmony_ci hw_dbg("Flow Control = FULL.\n"); 11328c2ecf20Sopenharmony_ci } else { 11338c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_rx_pause; 11348c2ecf20Sopenharmony_ci hw_dbg("Flow Control = Rx PAUSE frames only.\n"); 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci /* For receiving PAUSE frames ONLY. 11388c2ecf20Sopenharmony_ci * 11398c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 11408c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result 11418c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 11428c2ecf20Sopenharmony_ci * 0 | 1 | 1 | 1 | e1000_fc_tx_pause 11438c2ecf20Sopenharmony_ci */ 11448c2ecf20Sopenharmony_ci else if (!(pcs_adv_reg & E1000_TXCW_PAUSE) && 11458c2ecf20Sopenharmony_ci (pcs_adv_reg & E1000_TXCW_ASM_DIR) && 11468c2ecf20Sopenharmony_ci (pcs_lp_ability_reg & E1000_TXCW_PAUSE) && 11478c2ecf20Sopenharmony_ci (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) { 11488c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_tx_pause; 11498c2ecf20Sopenharmony_ci hw_dbg("Flow Control = Tx PAUSE frames only.\n"); 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci /* For transmitting PAUSE frames ONLY. 11528c2ecf20Sopenharmony_ci * 11538c2ecf20Sopenharmony_ci * LOCAL DEVICE | LINK PARTNER 11548c2ecf20Sopenharmony_ci * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result 11558c2ecf20Sopenharmony_ci *-------|---------|-------|---------|-------------------- 11568c2ecf20Sopenharmony_ci * 1 | 1 | 0 | 1 | e1000_fc_rx_pause 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_ci else if ((pcs_adv_reg & E1000_TXCW_PAUSE) && 11598c2ecf20Sopenharmony_ci (pcs_adv_reg & E1000_TXCW_ASM_DIR) && 11608c2ecf20Sopenharmony_ci !(pcs_lp_ability_reg & E1000_TXCW_PAUSE) && 11618c2ecf20Sopenharmony_ci (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) { 11628c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_rx_pause; 11638c2ecf20Sopenharmony_ci hw_dbg("Flow Control = Rx PAUSE frames only.\n"); 11648c2ecf20Sopenharmony_ci } else { 11658c2ecf20Sopenharmony_ci /* Per the IEEE spec, at this point flow control 11668c2ecf20Sopenharmony_ci * should be disabled. 11678c2ecf20Sopenharmony_ci */ 11688c2ecf20Sopenharmony_ci hw->fc.current_mode = e1000_fc_none; 11698c2ecf20Sopenharmony_ci hw_dbg("Flow Control = NONE.\n"); 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Now we call a subroutine to actually force the MAC 11738c2ecf20Sopenharmony_ci * controller to use the correct flow control settings. 11748c2ecf20Sopenharmony_ci */ 11758c2ecf20Sopenharmony_ci pcs_ctrl_reg = rd32(E1000_PCS_LCTL); 11768c2ecf20Sopenharmony_ci pcs_ctrl_reg |= E1000_PCS_LCTL_FORCE_FCTRL; 11778c2ecf20Sopenharmony_ci wr32(E1000_PCS_LCTL, pcs_ctrl_reg); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci ret_val = igb_force_mac_fc(hw); 11808c2ecf20Sopenharmony_ci if (ret_val) { 11818c2ecf20Sopenharmony_ci hw_dbg("Error forcing flow control settings\n"); 11828c2ecf20Sopenharmony_ci return ret_val; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ciout: 11878c2ecf20Sopenharmony_ci return ret_val; 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci/** 11918c2ecf20Sopenharmony_ci * igb_get_speed_and_duplex_copper - Retrieve current speed/duplex 11928c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 11938c2ecf20Sopenharmony_ci * @speed: stores the current speed 11948c2ecf20Sopenharmony_ci * @duplex: stores the current duplex 11958c2ecf20Sopenharmony_ci * 11968c2ecf20Sopenharmony_ci * Read the status register for the current speed/duplex and store the current 11978c2ecf20Sopenharmony_ci * speed and duplex for copper connections. 11988c2ecf20Sopenharmony_ci **/ 11998c2ecf20Sopenharmony_cis32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, 12008c2ecf20Sopenharmony_ci u16 *duplex) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci u32 status; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci status = rd32(E1000_STATUS); 12058c2ecf20Sopenharmony_ci if (status & E1000_STATUS_SPEED_1000) { 12068c2ecf20Sopenharmony_ci *speed = SPEED_1000; 12078c2ecf20Sopenharmony_ci hw_dbg("1000 Mbs, "); 12088c2ecf20Sopenharmony_ci } else if (status & E1000_STATUS_SPEED_100) { 12098c2ecf20Sopenharmony_ci *speed = SPEED_100; 12108c2ecf20Sopenharmony_ci hw_dbg("100 Mbs, "); 12118c2ecf20Sopenharmony_ci } else { 12128c2ecf20Sopenharmony_ci *speed = SPEED_10; 12138c2ecf20Sopenharmony_ci hw_dbg("10 Mbs, "); 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (status & E1000_STATUS_FD) { 12178c2ecf20Sopenharmony_ci *duplex = FULL_DUPLEX; 12188c2ecf20Sopenharmony_ci hw_dbg("Full Duplex\n"); 12198c2ecf20Sopenharmony_ci } else { 12208c2ecf20Sopenharmony_ci *duplex = HALF_DUPLEX; 12218c2ecf20Sopenharmony_ci hw_dbg("Half Duplex\n"); 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci return 0; 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci/** 12288c2ecf20Sopenharmony_ci * igb_get_hw_semaphore - Acquire hardware semaphore 12298c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 12308c2ecf20Sopenharmony_ci * 12318c2ecf20Sopenharmony_ci * Acquire the HW semaphore to access the PHY or NVM 12328c2ecf20Sopenharmony_ci **/ 12338c2ecf20Sopenharmony_cis32 igb_get_hw_semaphore(struct e1000_hw *hw) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci u32 swsm; 12368c2ecf20Sopenharmony_ci s32 ret_val = 0; 12378c2ecf20Sopenharmony_ci s32 timeout = hw->nvm.word_size + 1; 12388c2ecf20Sopenharmony_ci s32 i = 0; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* Get the SW semaphore */ 12418c2ecf20Sopenharmony_ci while (i < timeout) { 12428c2ecf20Sopenharmony_ci swsm = rd32(E1000_SWSM); 12438c2ecf20Sopenharmony_ci if (!(swsm & E1000_SWSM_SMBI)) 12448c2ecf20Sopenharmony_ci break; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci udelay(50); 12478c2ecf20Sopenharmony_ci i++; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (i == timeout) { 12518c2ecf20Sopenharmony_ci hw_dbg("Driver can't access device - SMBI bit is set.\n"); 12528c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_NVM; 12538c2ecf20Sopenharmony_ci goto out; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* Get the FW semaphore. */ 12578c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 12588c2ecf20Sopenharmony_ci swsm = rd32(E1000_SWSM); 12598c2ecf20Sopenharmony_ci wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci /* Semaphore acquired if bit latched */ 12628c2ecf20Sopenharmony_ci if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI) 12638c2ecf20Sopenharmony_ci break; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci udelay(50); 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (i == timeout) { 12698c2ecf20Sopenharmony_ci /* Release semaphores */ 12708c2ecf20Sopenharmony_ci igb_put_hw_semaphore(hw); 12718c2ecf20Sopenharmony_ci hw_dbg("Driver can't access the NVM\n"); 12728c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_NVM; 12738c2ecf20Sopenharmony_ci goto out; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ciout: 12778c2ecf20Sopenharmony_ci return ret_val; 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci/** 12818c2ecf20Sopenharmony_ci * igb_put_hw_semaphore - Release hardware semaphore 12828c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 12838c2ecf20Sopenharmony_ci * 12848c2ecf20Sopenharmony_ci * Release hardware semaphore used to access the PHY or NVM 12858c2ecf20Sopenharmony_ci **/ 12868c2ecf20Sopenharmony_civoid igb_put_hw_semaphore(struct e1000_hw *hw) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci u32 swsm; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci swsm = rd32(E1000_SWSM); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci wr32(E1000_SWSM, swsm); 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci/** 12988c2ecf20Sopenharmony_ci * igb_get_auto_rd_done - Check for auto read completion 12998c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 13008c2ecf20Sopenharmony_ci * 13018c2ecf20Sopenharmony_ci * Check EEPROM for Auto Read done bit. 13028c2ecf20Sopenharmony_ci **/ 13038c2ecf20Sopenharmony_cis32 igb_get_auto_rd_done(struct e1000_hw *hw) 13048c2ecf20Sopenharmony_ci{ 13058c2ecf20Sopenharmony_ci s32 i = 0; 13068c2ecf20Sopenharmony_ci s32 ret_val = 0; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci while (i < AUTO_READ_DONE_TIMEOUT) { 13108c2ecf20Sopenharmony_ci if (rd32(E1000_EECD) & E1000_EECD_AUTO_RD) 13118c2ecf20Sopenharmony_ci break; 13128c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 13138c2ecf20Sopenharmony_ci i++; 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (i == AUTO_READ_DONE_TIMEOUT) { 13178c2ecf20Sopenharmony_ci hw_dbg("Auto read by HW from NVM has not completed.\n"); 13188c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_RESET; 13198c2ecf20Sopenharmony_ci goto out; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ciout: 13238c2ecf20Sopenharmony_ci return ret_val; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci/** 13278c2ecf20Sopenharmony_ci * igb_valid_led_default - Verify a valid default LED config 13288c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 13298c2ecf20Sopenharmony_ci * @data: pointer to the NVM (EEPROM) 13308c2ecf20Sopenharmony_ci * 13318c2ecf20Sopenharmony_ci * Read the EEPROM for the current default LED configuration. If the 13328c2ecf20Sopenharmony_ci * LED configuration is not valid, set to a valid LED configuration. 13338c2ecf20Sopenharmony_ci **/ 13348c2ecf20Sopenharmony_cistatic s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci s32 ret_val; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); 13398c2ecf20Sopenharmony_ci if (ret_val) { 13408c2ecf20Sopenharmony_ci hw_dbg("NVM Read Error\n"); 13418c2ecf20Sopenharmony_ci goto out; 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { 13458c2ecf20Sopenharmony_ci switch (hw->phy.media_type) { 13468c2ecf20Sopenharmony_ci case e1000_media_type_internal_serdes: 13478c2ecf20Sopenharmony_ci *data = ID_LED_DEFAULT_82575_SERDES; 13488c2ecf20Sopenharmony_ci break; 13498c2ecf20Sopenharmony_ci case e1000_media_type_copper: 13508c2ecf20Sopenharmony_ci default: 13518c2ecf20Sopenharmony_ci *data = ID_LED_DEFAULT; 13528c2ecf20Sopenharmony_ci break; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ciout: 13568c2ecf20Sopenharmony_ci return ret_val; 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci/** 13608c2ecf20Sopenharmony_ci * igb_id_led_init - 13618c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 13628c2ecf20Sopenharmony_ci * 13638c2ecf20Sopenharmony_ci **/ 13648c2ecf20Sopenharmony_cis32 igb_id_led_init(struct e1000_hw *hw) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci struct e1000_mac_info *mac = &hw->mac; 13678c2ecf20Sopenharmony_ci s32 ret_val; 13688c2ecf20Sopenharmony_ci const u32 ledctl_mask = 0x000000FF; 13698c2ecf20Sopenharmony_ci const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON; 13708c2ecf20Sopenharmony_ci const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF; 13718c2ecf20Sopenharmony_ci u16 data, i, temp; 13728c2ecf20Sopenharmony_ci const u16 led_mask = 0x0F; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* i210 and i211 devices have different LED mechanism */ 13758c2ecf20Sopenharmony_ci if ((hw->mac.type == e1000_i210) || 13768c2ecf20Sopenharmony_ci (hw->mac.type == e1000_i211)) 13778c2ecf20Sopenharmony_ci ret_val = igb_valid_led_default_i210(hw, &data); 13788c2ecf20Sopenharmony_ci else 13798c2ecf20Sopenharmony_ci ret_val = igb_valid_led_default(hw, &data); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (ret_val) 13828c2ecf20Sopenharmony_ci goto out; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci mac->ledctl_default = rd32(E1000_LEDCTL); 13858c2ecf20Sopenharmony_ci mac->ledctl_mode1 = mac->ledctl_default; 13868c2ecf20Sopenharmony_ci mac->ledctl_mode2 = mac->ledctl_default; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 13898c2ecf20Sopenharmony_ci temp = (data >> (i << 2)) & led_mask; 13908c2ecf20Sopenharmony_ci switch (temp) { 13918c2ecf20Sopenharmony_ci case ID_LED_ON1_DEF2: 13928c2ecf20Sopenharmony_ci case ID_LED_ON1_ON2: 13938c2ecf20Sopenharmony_ci case ID_LED_ON1_OFF2: 13948c2ecf20Sopenharmony_ci mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); 13958c2ecf20Sopenharmony_ci mac->ledctl_mode1 |= ledctl_on << (i << 3); 13968c2ecf20Sopenharmony_ci break; 13978c2ecf20Sopenharmony_ci case ID_LED_OFF1_DEF2: 13988c2ecf20Sopenharmony_ci case ID_LED_OFF1_ON2: 13998c2ecf20Sopenharmony_ci case ID_LED_OFF1_OFF2: 14008c2ecf20Sopenharmony_ci mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); 14018c2ecf20Sopenharmony_ci mac->ledctl_mode1 |= ledctl_off << (i << 3); 14028c2ecf20Sopenharmony_ci break; 14038c2ecf20Sopenharmony_ci default: 14048c2ecf20Sopenharmony_ci /* Do nothing */ 14058c2ecf20Sopenharmony_ci break; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci switch (temp) { 14088c2ecf20Sopenharmony_ci case ID_LED_DEF1_ON2: 14098c2ecf20Sopenharmony_ci case ID_LED_ON1_ON2: 14108c2ecf20Sopenharmony_ci case ID_LED_OFF1_ON2: 14118c2ecf20Sopenharmony_ci mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); 14128c2ecf20Sopenharmony_ci mac->ledctl_mode2 |= ledctl_on << (i << 3); 14138c2ecf20Sopenharmony_ci break; 14148c2ecf20Sopenharmony_ci case ID_LED_DEF1_OFF2: 14158c2ecf20Sopenharmony_ci case ID_LED_ON1_OFF2: 14168c2ecf20Sopenharmony_ci case ID_LED_OFF1_OFF2: 14178c2ecf20Sopenharmony_ci mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); 14188c2ecf20Sopenharmony_ci mac->ledctl_mode2 |= ledctl_off << (i << 3); 14198c2ecf20Sopenharmony_ci break; 14208c2ecf20Sopenharmony_ci default: 14218c2ecf20Sopenharmony_ci /* Do nothing */ 14228c2ecf20Sopenharmony_ci break; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ciout: 14278c2ecf20Sopenharmony_ci return ret_val; 14288c2ecf20Sopenharmony_ci} 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci/** 14318c2ecf20Sopenharmony_ci * igb_cleanup_led - Set LED config to default operation 14328c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 14338c2ecf20Sopenharmony_ci * 14348c2ecf20Sopenharmony_ci * Remove the current LED configuration and set the LED configuration 14358c2ecf20Sopenharmony_ci * to the default value, saved from the EEPROM. 14368c2ecf20Sopenharmony_ci **/ 14378c2ecf20Sopenharmony_cis32 igb_cleanup_led(struct e1000_hw *hw) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci wr32(E1000_LEDCTL, hw->mac.ledctl_default); 14408c2ecf20Sopenharmony_ci return 0; 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci/** 14448c2ecf20Sopenharmony_ci * igb_blink_led - Blink LED 14458c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 14468c2ecf20Sopenharmony_ci * 14478c2ecf20Sopenharmony_ci * Blink the led's which are set to be on. 14488c2ecf20Sopenharmony_ci **/ 14498c2ecf20Sopenharmony_cis32 igb_blink_led(struct e1000_hw *hw) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci u32 ledctl_blink = 0; 14528c2ecf20Sopenharmony_ci u32 i; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (hw->phy.media_type == e1000_media_type_fiber) { 14558c2ecf20Sopenharmony_ci /* always blink LED0 for PCI-E fiber */ 14568c2ecf20Sopenharmony_ci ledctl_blink = E1000_LEDCTL_LED0_BLINK | 14578c2ecf20Sopenharmony_ci (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); 14588c2ecf20Sopenharmony_ci } else { 14598c2ecf20Sopenharmony_ci /* Set the blink bit for each LED that's "on" (0x0E) 14608c2ecf20Sopenharmony_ci * (or "off" if inverted) in ledctl_mode2. The blink 14618c2ecf20Sopenharmony_ci * logic in hardware only works when mode is set to "on" 14628c2ecf20Sopenharmony_ci * so it must be changed accordingly when the mode is 14638c2ecf20Sopenharmony_ci * "off" and inverted. 14648c2ecf20Sopenharmony_ci */ 14658c2ecf20Sopenharmony_ci ledctl_blink = hw->mac.ledctl_mode2; 14668c2ecf20Sopenharmony_ci for (i = 0; i < 32; i += 8) { 14678c2ecf20Sopenharmony_ci u32 mode = (hw->mac.ledctl_mode2 >> i) & 14688c2ecf20Sopenharmony_ci E1000_LEDCTL_LED0_MODE_MASK; 14698c2ecf20Sopenharmony_ci u32 led_default = hw->mac.ledctl_default >> i; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if ((!(led_default & E1000_LEDCTL_LED0_IVRT) && 14728c2ecf20Sopenharmony_ci (mode == E1000_LEDCTL_MODE_LED_ON)) || 14738c2ecf20Sopenharmony_ci ((led_default & E1000_LEDCTL_LED0_IVRT) && 14748c2ecf20Sopenharmony_ci (mode == E1000_LEDCTL_MODE_LED_OFF))) { 14758c2ecf20Sopenharmony_ci ledctl_blink &= 14768c2ecf20Sopenharmony_ci ~(E1000_LEDCTL_LED0_MODE_MASK << i); 14778c2ecf20Sopenharmony_ci ledctl_blink |= (E1000_LEDCTL_LED0_BLINK | 14788c2ecf20Sopenharmony_ci E1000_LEDCTL_MODE_LED_ON) << i; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci wr32(E1000_LEDCTL, ledctl_blink); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci return 0; 14868c2ecf20Sopenharmony_ci} 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci/** 14898c2ecf20Sopenharmony_ci * igb_led_off - Turn LED off 14908c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 14918c2ecf20Sopenharmony_ci * 14928c2ecf20Sopenharmony_ci * Turn LED off. 14938c2ecf20Sopenharmony_ci **/ 14948c2ecf20Sopenharmony_cis32 igb_led_off(struct e1000_hw *hw) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci switch (hw->phy.media_type) { 14978c2ecf20Sopenharmony_ci case e1000_media_type_copper: 14988c2ecf20Sopenharmony_ci wr32(E1000_LEDCTL, hw->mac.ledctl_mode1); 14998c2ecf20Sopenharmony_ci break; 15008c2ecf20Sopenharmony_ci default: 15018c2ecf20Sopenharmony_ci break; 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return 0; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci/** 15088c2ecf20Sopenharmony_ci * igb_disable_pcie_master - Disables PCI-express master access 15098c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 15108c2ecf20Sopenharmony_ci * 15118c2ecf20Sopenharmony_ci * Returns 0 (0) if successful, else returns -10 15128c2ecf20Sopenharmony_ci * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused 15138c2ecf20Sopenharmony_ci * the master requests to be disabled. 15148c2ecf20Sopenharmony_ci * 15158c2ecf20Sopenharmony_ci * Disables PCI-Express master access and verifies there are no pending 15168c2ecf20Sopenharmony_ci * requests. 15178c2ecf20Sopenharmony_ci **/ 15188c2ecf20Sopenharmony_cis32 igb_disable_pcie_master(struct e1000_hw *hw) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci u32 ctrl; 15218c2ecf20Sopenharmony_ci s32 timeout = MASTER_DISABLE_TIMEOUT; 15228c2ecf20Sopenharmony_ci s32 ret_val = 0; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (hw->bus.type != e1000_bus_type_pci_express) 15258c2ecf20Sopenharmony_ci goto out; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci ctrl = rd32(E1000_CTRL); 15288c2ecf20Sopenharmony_ci ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; 15298c2ecf20Sopenharmony_ci wr32(E1000_CTRL, ctrl); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci while (timeout) { 15328c2ecf20Sopenharmony_ci if (!(rd32(E1000_STATUS) & 15338c2ecf20Sopenharmony_ci E1000_STATUS_GIO_MASTER_ENABLE)) 15348c2ecf20Sopenharmony_ci break; 15358c2ecf20Sopenharmony_ci udelay(100); 15368c2ecf20Sopenharmony_ci timeout--; 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci if (!timeout) { 15408c2ecf20Sopenharmony_ci hw_dbg("Master requests are pending.\n"); 15418c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING; 15428c2ecf20Sopenharmony_ci goto out; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ciout: 15468c2ecf20Sopenharmony_ci return ret_val; 15478c2ecf20Sopenharmony_ci} 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci/** 15508c2ecf20Sopenharmony_ci * igb_validate_mdi_setting - Verify MDI/MDIx settings 15518c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 15528c2ecf20Sopenharmony_ci * 15538c2ecf20Sopenharmony_ci * Verify that when not using auto-negotitation that MDI/MDIx is correctly 15548c2ecf20Sopenharmony_ci * set, which is forced to MDI mode only. 15558c2ecf20Sopenharmony_ci **/ 15568c2ecf20Sopenharmony_cis32 igb_validate_mdi_setting(struct e1000_hw *hw) 15578c2ecf20Sopenharmony_ci{ 15588c2ecf20Sopenharmony_ci s32 ret_val = 0; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci /* All MDI settings are supported on 82580 and newer. */ 15618c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_82580) 15628c2ecf20Sopenharmony_ci goto out; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) { 15658c2ecf20Sopenharmony_ci hw_dbg("Invalid MDI setting detected\n"); 15668c2ecf20Sopenharmony_ci hw->phy.mdix = 1; 15678c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_CONFIG; 15688c2ecf20Sopenharmony_ci goto out; 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ciout: 15728c2ecf20Sopenharmony_ci return ret_val; 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci/** 15768c2ecf20Sopenharmony_ci * igb_write_8bit_ctrl_reg - Write a 8bit CTRL register 15778c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 15788c2ecf20Sopenharmony_ci * @reg: 32bit register offset such as E1000_SCTL 15798c2ecf20Sopenharmony_ci * @offset: register offset to write to 15808c2ecf20Sopenharmony_ci * @data: data to write at register offset 15818c2ecf20Sopenharmony_ci * 15828c2ecf20Sopenharmony_ci * Writes an address/data control type register. There are several of these 15838c2ecf20Sopenharmony_ci * and they all have the format address << 8 | data and bit 31 is polled for 15848c2ecf20Sopenharmony_ci * completion. 15858c2ecf20Sopenharmony_ci **/ 15868c2ecf20Sopenharmony_cis32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, 15878c2ecf20Sopenharmony_ci u32 offset, u8 data) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci u32 i, regvalue = 0; 15908c2ecf20Sopenharmony_ci s32 ret_val = 0; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci /* Set up the address and data */ 15938c2ecf20Sopenharmony_ci regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT); 15948c2ecf20Sopenharmony_ci wr32(reg, regvalue); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* Poll the ready bit to see if the MDI read completed */ 15978c2ecf20Sopenharmony_ci for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) { 15988c2ecf20Sopenharmony_ci udelay(5); 15998c2ecf20Sopenharmony_ci regvalue = rd32(reg); 16008c2ecf20Sopenharmony_ci if (regvalue & E1000_GEN_CTL_READY) 16018c2ecf20Sopenharmony_ci break; 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci if (!(regvalue & E1000_GEN_CTL_READY)) { 16048c2ecf20Sopenharmony_ci hw_dbg("Reg %08x did not indicate ready\n", reg); 16058c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_PHY; 16068c2ecf20Sopenharmony_ci goto out; 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ciout: 16108c2ecf20Sopenharmony_ci return ret_val; 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci/** 16148c2ecf20Sopenharmony_ci * igb_enable_mng_pass_thru - Enable processing of ARP's 16158c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 16168c2ecf20Sopenharmony_ci * 16178c2ecf20Sopenharmony_ci * Verifies the hardware needs to leave interface enabled so that frames can 16188c2ecf20Sopenharmony_ci * be directed to and from the management interface. 16198c2ecf20Sopenharmony_ci **/ 16208c2ecf20Sopenharmony_cibool igb_enable_mng_pass_thru(struct e1000_hw *hw) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci u32 manc; 16238c2ecf20Sopenharmony_ci u32 fwsm, factps; 16248c2ecf20Sopenharmony_ci bool ret_val = false; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (!hw->mac.asf_firmware_present) 16278c2ecf20Sopenharmony_ci goto out; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci manc = rd32(E1000_MANC); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (!(manc & E1000_MANC_RCV_TCO_EN)) 16328c2ecf20Sopenharmony_ci goto out; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci if (hw->mac.arc_subsystem_valid) { 16358c2ecf20Sopenharmony_ci fwsm = rd32(E1000_FWSM); 16368c2ecf20Sopenharmony_ci factps = rd32(E1000_FACTPS); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (!(factps & E1000_FACTPS_MNGCG) && 16398c2ecf20Sopenharmony_ci ((fwsm & E1000_FWSM_MODE_MASK) == 16408c2ecf20Sopenharmony_ci (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { 16418c2ecf20Sopenharmony_ci ret_val = true; 16428c2ecf20Sopenharmony_ci goto out; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci } else { 16458c2ecf20Sopenharmony_ci if ((manc & E1000_MANC_SMBUS_EN) && 16468c2ecf20Sopenharmony_ci !(manc & E1000_MANC_ASF_EN)) { 16478c2ecf20Sopenharmony_ci ret_val = true; 16488c2ecf20Sopenharmony_ci goto out; 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ciout: 16538c2ecf20Sopenharmony_ci return ret_val; 16548c2ecf20Sopenharmony_ci} 1655