18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/pci.h> 58c2ecf20Sopenharmony_ci#include <linux/delay.h> 68c2ecf20Sopenharmony_ci#include <linux/sched.h> 78c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "ixgbe.h" 108c2ecf20Sopenharmony_ci#include "ixgbe_common.h" 118c2ecf20Sopenharmony_ci#include "ixgbe_phy.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw); 148c2ecf20Sopenharmony_cistatic s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw); 158c2ecf20Sopenharmony_cistatic void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw); 168c2ecf20Sopenharmony_cistatic s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw); 178c2ecf20Sopenharmony_cistatic void ixgbe_standby_eeprom(struct ixgbe_hw *hw); 188c2ecf20Sopenharmony_cistatic void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, 198c2ecf20Sopenharmony_ci u16 count); 208c2ecf20Sopenharmony_cistatic u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count); 218c2ecf20Sopenharmony_cistatic void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); 228c2ecf20Sopenharmony_cistatic void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); 238c2ecf20Sopenharmony_cistatic void ixgbe_release_eeprom(struct ixgbe_hw *hw); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); 268c2ecf20Sopenharmony_cistatic s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); 278c2ecf20Sopenharmony_cistatic s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, 288c2ecf20Sopenharmony_ci u16 words, u16 *data); 298c2ecf20Sopenharmony_cistatic s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, 308c2ecf20Sopenharmony_ci u16 words, u16 *data); 318c2ecf20Sopenharmony_cistatic s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, 328c2ecf20Sopenharmony_ci u16 offset); 338c2ecf20Sopenharmony_cistatic s32 ixgbe_disable_pcie_primary(struct ixgbe_hw *hw); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Base table for registers values that change by MAC */ 368c2ecf20Sopenharmony_ciconst u32 ixgbe_mvals_8259X[IXGBE_MVALS_IDX_LIMIT] = { 378c2ecf20Sopenharmony_ci IXGBE_MVALS_INIT(8259X) 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/** 418c2ecf20Sopenharmony_ci * ixgbe_device_supports_autoneg_fc - Check if phy supports autoneg flow 428c2ecf20Sopenharmony_ci * control 438c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * There are several phys that do not support autoneg flow control. This 468c2ecf20Sopenharmony_ci * function check the device id to see if the associated phy supports 478c2ecf20Sopenharmony_ci * autoneg flow control. 488c2ecf20Sopenharmony_ci **/ 498c2ecf20Sopenharmony_cibool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci bool supported = false; 528c2ecf20Sopenharmony_ci ixgbe_link_speed speed; 538c2ecf20Sopenharmony_ci bool link_up; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci switch (hw->phy.media_type) { 568c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber: 578c2ecf20Sopenharmony_ci /* flow control autoneg black list */ 588c2ecf20Sopenharmony_ci switch (hw->device_id) { 598c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SFP: 608c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SFP_N: 618c2ecf20Sopenharmony_ci supported = false; 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci default: 648c2ecf20Sopenharmony_ci hw->mac.ops.check_link(hw, &speed, &link_up, false); 658c2ecf20Sopenharmony_ci /* if link is down, assume supported */ 668c2ecf20Sopenharmony_ci if (link_up) 678c2ecf20Sopenharmony_ci supported = speed == IXGBE_LINK_SPEED_1GB_FULL; 688c2ecf20Sopenharmony_ci else 698c2ecf20Sopenharmony_ci supported = true; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci case ixgbe_media_type_backplane: 748c2ecf20Sopenharmony_ci if (hw->device_id == IXGBE_DEV_ID_X550EM_X_XFI) 758c2ecf20Sopenharmony_ci supported = false; 768c2ecf20Sopenharmony_ci else 778c2ecf20Sopenharmony_ci supported = true; 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci case ixgbe_media_type_copper: 808c2ecf20Sopenharmony_ci /* only some copper devices support flow control autoneg */ 818c2ecf20Sopenharmony_ci switch (hw->device_id) { 828c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_82599_T3_LOM: 838c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X540T: 848c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X540T1: 858c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550T: 868c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550T1: 878c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_X_10G_T: 888c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_10G_T: 898c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_1G_T: 908c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_1G_T_L: 918c2ecf20Sopenharmony_ci supported = true; 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci default: 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci default: 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (!supported) 1018c2ecf20Sopenharmony_ci hw_dbg(hw, "Device %x does not support flow control autoneg\n", 1028c2ecf20Sopenharmony_ci hw->device_id); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return supported; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/** 1088c2ecf20Sopenharmony_ci * ixgbe_setup_fc_generic - Set up flow control 1098c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 1108c2ecf20Sopenharmony_ci * 1118c2ecf20Sopenharmony_ci * Called at init time to set up flow control. 1128c2ecf20Sopenharmony_ci **/ 1138c2ecf20Sopenharmony_cis32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci s32 ret_val = 0; 1168c2ecf20Sopenharmony_ci u32 reg = 0, reg_bp = 0; 1178c2ecf20Sopenharmony_ci u16 reg_cu = 0; 1188c2ecf20Sopenharmony_ci bool locked = false; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * Validate the requested mode. Strict IEEE mode does not allow 1228c2ecf20Sopenharmony_ci * ixgbe_fc_rx_pause because it will cause us to fail at UNH. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { 1258c2ecf20Sopenharmony_ci hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); 1268c2ecf20Sopenharmony_ci return -EINVAL; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * 10gig parts do not have a word in the EEPROM to determine the 1318c2ecf20Sopenharmony_ci * default flow control setting, so we explicitly set it to full. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci if (hw->fc.requested_mode == ixgbe_fc_default) 1348c2ecf20Sopenharmony_ci hw->fc.requested_mode = ixgbe_fc_full; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * Set up the 1G and 10G flow control advertisement registers so the 1388c2ecf20Sopenharmony_ci * HW will be able to do fc autoneg once the cable is plugged in. If 1398c2ecf20Sopenharmony_ci * we link at 10G, the 1G advertisement is harmless and vice versa. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci switch (hw->phy.media_type) { 1428c2ecf20Sopenharmony_ci case ixgbe_media_type_backplane: 1438c2ecf20Sopenharmony_ci /* some MAC's need RMW protection on AUTOC */ 1448c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, ®_bp); 1458c2ecf20Sopenharmony_ci if (ret_val) 1468c2ecf20Sopenharmony_ci return ret_val; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci fallthrough; /* only backplane uses autoc */ 1498c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber: 1508c2ecf20Sopenharmony_ci reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case ixgbe_media_type_copper: 1548c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, 1558c2ecf20Sopenharmony_ci MDIO_MMD_AN, ®_cu); 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci default: 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * The possible values of fc.requested_mode are: 1638c2ecf20Sopenharmony_ci * 0: Flow control is completely disabled 1648c2ecf20Sopenharmony_ci * 1: Rx flow control is enabled (we can receive pause frames, 1658c2ecf20Sopenharmony_ci * but not send pause frames). 1668c2ecf20Sopenharmony_ci * 2: Tx flow control is enabled (we can send pause frames but 1678c2ecf20Sopenharmony_ci * we do not support receiving pause frames). 1688c2ecf20Sopenharmony_ci * 3: Both Rx and Tx flow control (symmetric) are enabled. 1698c2ecf20Sopenharmony_ci * other: Invalid. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ci switch (hw->fc.requested_mode) { 1728c2ecf20Sopenharmony_ci case ixgbe_fc_none: 1738c2ecf20Sopenharmony_ci /* Flow control completely disabled by software override. */ 1748c2ecf20Sopenharmony_ci reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); 1758c2ecf20Sopenharmony_ci if (hw->phy.media_type == ixgbe_media_type_backplane) 1768c2ecf20Sopenharmony_ci reg_bp &= ~(IXGBE_AUTOC_SYM_PAUSE | 1778c2ecf20Sopenharmony_ci IXGBE_AUTOC_ASM_PAUSE); 1788c2ecf20Sopenharmony_ci else if (hw->phy.media_type == ixgbe_media_type_copper) 1798c2ecf20Sopenharmony_ci reg_cu &= ~(IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE); 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci case ixgbe_fc_tx_pause: 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * Tx Flow control is enabled, and Rx Flow control is 1848c2ecf20Sopenharmony_ci * disabled by software override. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci reg |= IXGBE_PCS1GANA_ASM_PAUSE; 1878c2ecf20Sopenharmony_ci reg &= ~IXGBE_PCS1GANA_SYM_PAUSE; 1888c2ecf20Sopenharmony_ci if (hw->phy.media_type == ixgbe_media_type_backplane) { 1898c2ecf20Sopenharmony_ci reg_bp |= IXGBE_AUTOC_ASM_PAUSE; 1908c2ecf20Sopenharmony_ci reg_bp &= ~IXGBE_AUTOC_SYM_PAUSE; 1918c2ecf20Sopenharmony_ci } else if (hw->phy.media_type == ixgbe_media_type_copper) { 1928c2ecf20Sopenharmony_ci reg_cu |= IXGBE_TAF_ASM_PAUSE; 1938c2ecf20Sopenharmony_ci reg_cu &= ~IXGBE_TAF_SYM_PAUSE; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci case ixgbe_fc_rx_pause: 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * Rx Flow control is enabled and Tx Flow control is 1998c2ecf20Sopenharmony_ci * disabled by software override. Since there really 2008c2ecf20Sopenharmony_ci * isn't a way to advertise that we are capable of RX 2018c2ecf20Sopenharmony_ci * Pause ONLY, we will advertise that we support both 2028c2ecf20Sopenharmony_ci * symmetric and asymmetric Rx PAUSE, as such we fall 2038c2ecf20Sopenharmony_ci * through to the fc_full statement. Later, we will 2048c2ecf20Sopenharmony_ci * disable the adapter's ability to send PAUSE frames. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci case ixgbe_fc_full: 2078c2ecf20Sopenharmony_ci /* Flow control (both Rx and Tx) is enabled by SW override. */ 2088c2ecf20Sopenharmony_ci reg |= IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE; 2098c2ecf20Sopenharmony_ci if (hw->phy.media_type == ixgbe_media_type_backplane) 2108c2ecf20Sopenharmony_ci reg_bp |= IXGBE_AUTOC_SYM_PAUSE | 2118c2ecf20Sopenharmony_ci IXGBE_AUTOC_ASM_PAUSE; 2128c2ecf20Sopenharmony_ci else if (hw->phy.media_type == ixgbe_media_type_copper) 2138c2ecf20Sopenharmony_ci reg_cu |= IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE; 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci default: 2168c2ecf20Sopenharmony_ci hw_dbg(hw, "Flow control param set incorrectly\n"); 2178c2ecf20Sopenharmony_ci return -EIO; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (hw->mac.type != ixgbe_mac_X540) { 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * Enable auto-negotiation between the MAC & PHY; 2238c2ecf20Sopenharmony_ci * the MAC will advertise clause 37 flow control. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); 2268c2ecf20Sopenharmony_ci reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Disable AN timeout */ 2298c2ecf20Sopenharmony_ci if (hw->fc.strict_ieee) 2308c2ecf20Sopenharmony_ci reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); 2338c2ecf20Sopenharmony_ci hw_dbg(hw, "Set up FC; PCS1GLCTL = 0x%08X\n", reg); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* 2378c2ecf20Sopenharmony_ci * AUTOC restart handles negotiation of 1G and 10G on backplane 2388c2ecf20Sopenharmony_ci * and copper. There is no need to set the PCS1GCTL register. 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci if (hw->phy.media_type == ixgbe_media_type_backplane) { 2428c2ecf20Sopenharmony_ci /* Need the SW/FW semaphore around AUTOC writes if 82599 and 2438c2ecf20Sopenharmony_ci * LESM is on, likewise reset_pipeline requries the lock as 2448c2ecf20Sopenharmony_ci * it also writes AUTOC. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.prot_autoc_write(hw, reg_bp, locked); 2478c2ecf20Sopenharmony_ci if (ret_val) 2488c2ecf20Sopenharmony_ci return ret_val; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci } else if ((hw->phy.media_type == ixgbe_media_type_copper) && 2518c2ecf20Sopenharmony_ci ixgbe_device_supports_autoneg_fc(hw)) { 2528c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, 2538c2ecf20Sopenharmony_ci MDIO_MMD_AN, reg_cu); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci hw_dbg(hw, "Set up FC; IXGBE_AUTOC = 0x%08X\n", reg); 2578c2ecf20Sopenharmony_ci return ret_val; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/** 2618c2ecf20Sopenharmony_ci * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx 2628c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 2638c2ecf20Sopenharmony_ci * 2648c2ecf20Sopenharmony_ci * Starts the hardware by filling the bus info structure and media type, clears 2658c2ecf20Sopenharmony_ci * all on chip counters, initializes receive address registers, multicast 2668c2ecf20Sopenharmony_ci * table, VLAN filter table, calls routine to set up link and flow control 2678c2ecf20Sopenharmony_ci * settings, and leaves transmit and receive units disabled and uninitialized 2688c2ecf20Sopenharmony_ci **/ 2698c2ecf20Sopenharmony_cis32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci s32 ret_val; 2728c2ecf20Sopenharmony_ci u32 ctrl_ext; 2738c2ecf20Sopenharmony_ci u16 device_caps; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Set the media type */ 2768c2ecf20Sopenharmony_ci hw->phy.media_type = hw->mac.ops.get_media_type(hw); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Identify the PHY */ 2798c2ecf20Sopenharmony_ci hw->phy.ops.identify(hw); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Clear the VLAN filter table */ 2828c2ecf20Sopenharmony_ci hw->mac.ops.clear_vfta(hw); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Clear statistics registers */ 2858c2ecf20Sopenharmony_ci hw->mac.ops.clear_hw_cntrs(hw); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Set No Snoop Disable */ 2888c2ecf20Sopenharmony_ci ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 2898c2ecf20Sopenharmony_ci ctrl_ext |= IXGBE_CTRL_EXT_NS_DIS; 2908c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 2918c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Setup flow control if method for doing so */ 2948c2ecf20Sopenharmony_ci if (hw->mac.ops.setup_fc) { 2958c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.setup_fc(hw); 2968c2ecf20Sopenharmony_ci if (ret_val) 2978c2ecf20Sopenharmony_ci return ret_val; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Cashe bit indicating need for crosstalk fix */ 3018c2ecf20Sopenharmony_ci switch (hw->mac.type) { 3028c2ecf20Sopenharmony_ci case ixgbe_mac_82599EB: 3038c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 3048c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 3058c2ecf20Sopenharmony_ci hw->mac.ops.get_device_caps(hw, &device_caps); 3068c2ecf20Sopenharmony_ci if (device_caps & IXGBE_DEVICE_CAPS_NO_CROSSTALK_WR) 3078c2ecf20Sopenharmony_ci hw->need_crosstalk_fix = false; 3088c2ecf20Sopenharmony_ci else 3098c2ecf20Sopenharmony_ci hw->need_crosstalk_fix = true; 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci default: 3128c2ecf20Sopenharmony_ci hw->need_crosstalk_fix = false; 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* Clear adapter stopped flag */ 3178c2ecf20Sopenharmony_ci hw->adapter_stopped = false; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/** 3238c2ecf20Sopenharmony_ci * ixgbe_start_hw_gen2 - Init sequence for common device family 3248c2ecf20Sopenharmony_ci * @hw: pointer to hw structure 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * Performs the init sequence common to the second generation 3278c2ecf20Sopenharmony_ci * of 10 GbE devices. 3288c2ecf20Sopenharmony_ci * Devices in the second generation: 3298c2ecf20Sopenharmony_ci * 82599 3308c2ecf20Sopenharmony_ci * X540 3318c2ecf20Sopenharmony_ci **/ 3328c2ecf20Sopenharmony_cis32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci u32 i; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Clear the rate limiters */ 3378c2ecf20Sopenharmony_ci for (i = 0; i < hw->mac.max_tx_queues; i++) { 3388c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, i); 3398c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/** 3478c2ecf20Sopenharmony_ci * ixgbe_init_hw_generic - Generic hardware initialization 3488c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 3498c2ecf20Sopenharmony_ci * 3508c2ecf20Sopenharmony_ci * Initialize the hardware by resetting the hardware, filling the bus info 3518c2ecf20Sopenharmony_ci * structure and media type, clears all on chip counters, initializes receive 3528c2ecf20Sopenharmony_ci * address registers, multicast table, VLAN filter table, calls routine to set 3538c2ecf20Sopenharmony_ci * up link and flow control settings, and leaves transmit and receive units 3548c2ecf20Sopenharmony_ci * disabled and uninitialized 3558c2ecf20Sopenharmony_ci **/ 3568c2ecf20Sopenharmony_cis32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci s32 status; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Reset the hardware */ 3618c2ecf20Sopenharmony_ci status = hw->mac.ops.reset_hw(hw); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (status == 0) { 3648c2ecf20Sopenharmony_ci /* Start the HW */ 3658c2ecf20Sopenharmony_ci status = hw->mac.ops.start_hw(hw); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* Initialize the LED link active for LED blink support */ 3698c2ecf20Sopenharmony_ci if (hw->mac.ops.init_led_link_act) 3708c2ecf20Sopenharmony_ci hw->mac.ops.init_led_link_act(hw); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return status; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/** 3768c2ecf20Sopenharmony_ci * ixgbe_clear_hw_cntrs_generic - Generic clear hardware counters 3778c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 3788c2ecf20Sopenharmony_ci * 3798c2ecf20Sopenharmony_ci * Clears all hardware statistics counters by reading them from the hardware 3808c2ecf20Sopenharmony_ci * Statistics counters are clear on read. 3818c2ecf20Sopenharmony_ci **/ 3828c2ecf20Sopenharmony_cis32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci u16 i = 0; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_CRCERRS); 3878c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_ILLERRC); 3888c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_ERRBC); 3898c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_MSPDC); 3908c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 3918c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_MPC(i)); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_MLFC); 3948c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_MRFC); 3958c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RLEC); 3968c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_LXONTXC); 3978c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); 3988c2ecf20Sopenharmony_ci if (hw->mac.type >= ixgbe_mac_82599EB) { 3998c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); 4008c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); 4018c2ecf20Sopenharmony_ci } else { 4028c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_LXONRXC); 4038c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 4078c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PXONTXC(i)); 4088c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i)); 4098c2ecf20Sopenharmony_ci if (hw->mac.type >= ixgbe_mac_82599EB) { 4108c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i)); 4118c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PXOFFRXCNT(i)); 4128c2ecf20Sopenharmony_ci } else { 4138c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PXONRXC(i)); 4148c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i)); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci if (hw->mac.type >= ixgbe_mac_82599EB) 4188c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 4198c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PXON2OFFCNT(i)); 4208c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PRC64); 4218c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PRC127); 4228c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PRC255); 4238c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PRC511); 4248c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PRC1023); 4258c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PRC1522); 4268c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_GPRC); 4278c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_BPRC); 4288c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_MPRC); 4298c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_GPTC); 4308c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_GORCL); 4318c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_GORCH); 4328c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_GOTCL); 4338c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_GOTCH); 4348c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) 4358c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 4368c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RNBC(i)); 4378c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RUC); 4388c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RFC); 4398c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_ROC); 4408c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RJC); 4418c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_MNGPRC); 4428c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_MNGPDC); 4438c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_MNGPTC); 4448c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_TORL); 4458c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_TORH); 4468c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_TPR); 4478c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_TPT); 4488c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PTC64); 4498c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PTC127); 4508c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PTC255); 4518c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PTC511); 4528c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PTC1023); 4538c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_PTC1522); 4548c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_MPTC); 4558c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_BPTC); 4568c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 4578c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_QPRC(i)); 4588c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_QPTC(i)); 4598c2ecf20Sopenharmony_ci if (hw->mac.type >= ixgbe_mac_82599EB) { 4608c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_QBRC_L(i)); 4618c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_QBRC_H(i)); 4628c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_QBTC_L(i)); 4638c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_QBTC_H(i)); 4648c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); 4658c2ecf20Sopenharmony_ci } else { 4668c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_QBRC(i)); 4678c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_QBTC(i)); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X540) { 4728c2ecf20Sopenharmony_ci if (hw->phy.id == 0) 4738c2ecf20Sopenharmony_ci hw->phy.ops.identify(hw); 4748c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, IXGBE_PCRC8ECL, MDIO_MMD_PCS, &i); 4758c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, IXGBE_PCRC8ECH, MDIO_MMD_PCS, &i); 4768c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, IXGBE_LDPCECL, MDIO_MMD_PCS, &i); 4778c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, IXGBE_LDPCECH, MDIO_MMD_PCS, &i); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci return 0; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci/** 4848c2ecf20Sopenharmony_ci * ixgbe_read_pba_string_generic - Reads part number string from EEPROM 4858c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 4868c2ecf20Sopenharmony_ci * @pba_num: stores the part number string from the EEPROM 4878c2ecf20Sopenharmony_ci * @pba_num_size: part number string buffer length 4888c2ecf20Sopenharmony_ci * 4898c2ecf20Sopenharmony_ci * Reads the part number string from the EEPROM. 4908c2ecf20Sopenharmony_ci **/ 4918c2ecf20Sopenharmony_cis32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, 4928c2ecf20Sopenharmony_ci u32 pba_num_size) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci s32 ret_val; 4958c2ecf20Sopenharmony_ci u16 data; 4968c2ecf20Sopenharmony_ci u16 pba_ptr; 4978c2ecf20Sopenharmony_ci u16 offset; 4988c2ecf20Sopenharmony_ci u16 length; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (pba_num == NULL) { 5018c2ecf20Sopenharmony_ci hw_dbg(hw, "PBA string buffer was null\n"); 5028c2ecf20Sopenharmony_ci return -EINVAL; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM0_PTR, &data); 5068c2ecf20Sopenharmony_ci if (ret_val) { 5078c2ecf20Sopenharmony_ci hw_dbg(hw, "NVM Read Error\n"); 5088c2ecf20Sopenharmony_ci return ret_val; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM1_PTR, &pba_ptr); 5128c2ecf20Sopenharmony_ci if (ret_val) { 5138c2ecf20Sopenharmony_ci hw_dbg(hw, "NVM Read Error\n"); 5148c2ecf20Sopenharmony_ci return ret_val; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* 5188c2ecf20Sopenharmony_ci * if data is not ptr guard the PBA must be in legacy format which 5198c2ecf20Sopenharmony_ci * means pba_ptr is actually our second data word for the PBA number 5208c2ecf20Sopenharmony_ci * and we can decode it into an ascii string 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_ci if (data != IXGBE_PBANUM_PTR_GUARD) { 5238c2ecf20Sopenharmony_ci hw_dbg(hw, "NVM PBA number is not stored as string\n"); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* we will need 11 characters to store the PBA */ 5268c2ecf20Sopenharmony_ci if (pba_num_size < 11) { 5278c2ecf20Sopenharmony_ci hw_dbg(hw, "PBA string buffer too small\n"); 5288c2ecf20Sopenharmony_ci return -ENOSPC; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* extract hex string from data and pba_ptr */ 5328c2ecf20Sopenharmony_ci pba_num[0] = (data >> 12) & 0xF; 5338c2ecf20Sopenharmony_ci pba_num[1] = (data >> 8) & 0xF; 5348c2ecf20Sopenharmony_ci pba_num[2] = (data >> 4) & 0xF; 5358c2ecf20Sopenharmony_ci pba_num[3] = data & 0xF; 5368c2ecf20Sopenharmony_ci pba_num[4] = (pba_ptr >> 12) & 0xF; 5378c2ecf20Sopenharmony_ci pba_num[5] = (pba_ptr >> 8) & 0xF; 5388c2ecf20Sopenharmony_ci pba_num[6] = '-'; 5398c2ecf20Sopenharmony_ci pba_num[7] = 0; 5408c2ecf20Sopenharmony_ci pba_num[8] = (pba_ptr >> 4) & 0xF; 5418c2ecf20Sopenharmony_ci pba_num[9] = pba_ptr & 0xF; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* put a null character on the end of our string */ 5448c2ecf20Sopenharmony_ci pba_num[10] = '\0'; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* switch all the data but the '-' to hex char */ 5478c2ecf20Sopenharmony_ci for (offset = 0; offset < 10; offset++) { 5488c2ecf20Sopenharmony_ci if (pba_num[offset] < 0xA) 5498c2ecf20Sopenharmony_ci pba_num[offset] += '0'; 5508c2ecf20Sopenharmony_ci else if (pba_num[offset] < 0x10) 5518c2ecf20Sopenharmony_ci pba_num[offset] += 'A' - 0xA; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, pba_ptr, &length); 5588c2ecf20Sopenharmony_ci if (ret_val) { 5598c2ecf20Sopenharmony_ci hw_dbg(hw, "NVM Read Error\n"); 5608c2ecf20Sopenharmony_ci return ret_val; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (length == 0xFFFF || length == 0) { 5648c2ecf20Sopenharmony_ci hw_dbg(hw, "NVM PBA number section invalid length\n"); 5658c2ecf20Sopenharmony_ci return -EIO; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* check if pba_num buffer is big enough */ 5698c2ecf20Sopenharmony_ci if (pba_num_size < (((u32)length * 2) - 1)) { 5708c2ecf20Sopenharmony_ci hw_dbg(hw, "PBA string buffer too small\n"); 5718c2ecf20Sopenharmony_ci return -ENOSPC; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* trim pba length from start of string */ 5758c2ecf20Sopenharmony_ci pba_ptr++; 5768c2ecf20Sopenharmony_ci length--; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci for (offset = 0; offset < length; offset++) { 5798c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, pba_ptr + offset, &data); 5808c2ecf20Sopenharmony_ci if (ret_val) { 5818c2ecf20Sopenharmony_ci hw_dbg(hw, "NVM Read Error\n"); 5828c2ecf20Sopenharmony_ci return ret_val; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci pba_num[offset * 2] = (u8)(data >> 8); 5858c2ecf20Sopenharmony_ci pba_num[(offset * 2) + 1] = (u8)(data & 0xFF); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci pba_num[offset * 2] = '\0'; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/** 5938c2ecf20Sopenharmony_ci * ixgbe_get_mac_addr_generic - Generic get MAC address 5948c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 5958c2ecf20Sopenharmony_ci * @mac_addr: Adapter MAC address 5968c2ecf20Sopenharmony_ci * 5978c2ecf20Sopenharmony_ci * Reads the adapter's MAC address from first Receive Address Register (RAR0) 5988c2ecf20Sopenharmony_ci * A reset of the adapter must be performed prior to calling this function 5998c2ecf20Sopenharmony_ci * in order for the MAC address to have been loaded from the EEPROM into RAR0 6008c2ecf20Sopenharmony_ci **/ 6018c2ecf20Sopenharmony_cis32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci u32 rar_high; 6048c2ecf20Sopenharmony_ci u32 rar_low; 6058c2ecf20Sopenharmony_ci u16 i; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(0)); 6088c2ecf20Sopenharmony_ci rar_low = IXGBE_READ_REG(hw, IXGBE_RAL(0)); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 6118c2ecf20Sopenharmony_ci mac_addr[i] = (u8)(rar_low >> (i*8)); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 6148c2ecf20Sopenharmony_ci mac_addr[i+4] = (u8)(rar_high >> (i*8)); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cienum ixgbe_bus_width ixgbe_convert_bus_width(u16 link_status) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci switch (link_status & IXGBE_PCI_LINK_WIDTH) { 6228c2ecf20Sopenharmony_ci case IXGBE_PCI_LINK_WIDTH_1: 6238c2ecf20Sopenharmony_ci return ixgbe_bus_width_pcie_x1; 6248c2ecf20Sopenharmony_ci case IXGBE_PCI_LINK_WIDTH_2: 6258c2ecf20Sopenharmony_ci return ixgbe_bus_width_pcie_x2; 6268c2ecf20Sopenharmony_ci case IXGBE_PCI_LINK_WIDTH_4: 6278c2ecf20Sopenharmony_ci return ixgbe_bus_width_pcie_x4; 6288c2ecf20Sopenharmony_ci case IXGBE_PCI_LINK_WIDTH_8: 6298c2ecf20Sopenharmony_ci return ixgbe_bus_width_pcie_x8; 6308c2ecf20Sopenharmony_ci default: 6318c2ecf20Sopenharmony_ci return ixgbe_bus_width_unknown; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cienum ixgbe_bus_speed ixgbe_convert_bus_speed(u16 link_status) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci switch (link_status & IXGBE_PCI_LINK_SPEED) { 6388c2ecf20Sopenharmony_ci case IXGBE_PCI_LINK_SPEED_2500: 6398c2ecf20Sopenharmony_ci return ixgbe_bus_speed_2500; 6408c2ecf20Sopenharmony_ci case IXGBE_PCI_LINK_SPEED_5000: 6418c2ecf20Sopenharmony_ci return ixgbe_bus_speed_5000; 6428c2ecf20Sopenharmony_ci case IXGBE_PCI_LINK_SPEED_8000: 6438c2ecf20Sopenharmony_ci return ixgbe_bus_speed_8000; 6448c2ecf20Sopenharmony_ci default: 6458c2ecf20Sopenharmony_ci return ixgbe_bus_speed_unknown; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/** 6508c2ecf20Sopenharmony_ci * ixgbe_get_bus_info_generic - Generic set PCI bus info 6518c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 6528c2ecf20Sopenharmony_ci * 6538c2ecf20Sopenharmony_ci * Sets the PCI bus info (speed, width, type) within the ixgbe_hw structure 6548c2ecf20Sopenharmony_ci **/ 6558c2ecf20Sopenharmony_cis32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci u16 link_status; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci hw->bus.type = ixgbe_bus_type_pci_express; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* Get the negotiated link width and speed from PCI config space */ 6628c2ecf20Sopenharmony_ci link_status = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_LINK_STATUS); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci hw->bus.width = ixgbe_convert_bus_width(link_status); 6658c2ecf20Sopenharmony_ci hw->bus.speed = ixgbe_convert_bus_speed(link_status); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci hw->mac.ops.set_lan_id(hw); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return 0; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/** 6738c2ecf20Sopenharmony_ci * ixgbe_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices 6748c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 6758c2ecf20Sopenharmony_ci * 6768c2ecf20Sopenharmony_ci * Determines the LAN function id by reading memory-mapped registers 6778c2ecf20Sopenharmony_ci * and swaps the port value if requested. 6788c2ecf20Sopenharmony_ci **/ 6798c2ecf20Sopenharmony_civoid ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct ixgbe_bus_info *bus = &hw->bus; 6828c2ecf20Sopenharmony_ci u16 ee_ctrl_4; 6838c2ecf20Sopenharmony_ci u32 reg; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci reg = IXGBE_READ_REG(hw, IXGBE_STATUS); 6868c2ecf20Sopenharmony_ci bus->func = (reg & IXGBE_STATUS_LAN_ID) >> IXGBE_STATUS_LAN_ID_SHIFT; 6878c2ecf20Sopenharmony_ci bus->lan_id = bus->func; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* check for a port swap */ 6908c2ecf20Sopenharmony_ci reg = IXGBE_READ_REG(hw, IXGBE_FACTPS(hw)); 6918c2ecf20Sopenharmony_ci if (reg & IXGBE_FACTPS_LFS) 6928c2ecf20Sopenharmony_ci bus->func ^= 0x1; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* Get MAC instance from EEPROM for configuring CS4227 */ 6958c2ecf20Sopenharmony_ci if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP) { 6968c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, IXGBE_EEPROM_CTRL_4, &ee_ctrl_4); 6978c2ecf20Sopenharmony_ci bus->instance_id = (ee_ctrl_4 & IXGBE_EE_CTRL_4_INST_ID) >> 6988c2ecf20Sopenharmony_ci IXGBE_EE_CTRL_4_INST_ID_SHIFT; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci/** 7038c2ecf20Sopenharmony_ci * ixgbe_stop_adapter_generic - Generic stop Tx/Rx units 7048c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 7058c2ecf20Sopenharmony_ci * 7068c2ecf20Sopenharmony_ci * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts, 7078c2ecf20Sopenharmony_ci * disables transmit and receive units. The adapter_stopped flag is used by 7088c2ecf20Sopenharmony_ci * the shared code and drivers to determine if the adapter is in a stopped 7098c2ecf20Sopenharmony_ci * state and should not touch the hardware. 7108c2ecf20Sopenharmony_ci **/ 7118c2ecf20Sopenharmony_cis32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci u32 reg_val; 7148c2ecf20Sopenharmony_ci u16 i; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* 7178c2ecf20Sopenharmony_ci * Set the adapter_stopped flag so other driver functions stop touching 7188c2ecf20Sopenharmony_ci * the hardware 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci hw->adapter_stopped = true; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* Disable the receive unit */ 7238c2ecf20Sopenharmony_ci hw->mac.ops.disable_rx(hw); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* Clear interrupt mask to stop interrupts from being generated */ 7268c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* Clear any pending interrupts, flush previous writes */ 7298c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_EICR); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Disable the transmit unit. Each queue must be disabled. */ 7328c2ecf20Sopenharmony_ci for (i = 0; i < hw->mac.max_tx_queues; i++) 7338c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), IXGBE_TXDCTL_SWFLSH); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* Disable the receive unit by stopping each queue */ 7368c2ecf20Sopenharmony_ci for (i = 0; i < hw->mac.max_rx_queues; i++) { 7378c2ecf20Sopenharmony_ci reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); 7388c2ecf20Sopenharmony_ci reg_val &= ~IXGBE_RXDCTL_ENABLE; 7398c2ecf20Sopenharmony_ci reg_val |= IXGBE_RXDCTL_SWFLSH; 7408c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), reg_val); 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* flush all queues disables */ 7448c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 7458c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* 7488c2ecf20Sopenharmony_ci * Prevent the PCI-E bus from hanging by disabling PCI-E primary 7498c2ecf20Sopenharmony_ci * access and verify no pending requests 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_ci return ixgbe_disable_pcie_primary(hw); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci/** 7558c2ecf20Sopenharmony_ci * ixgbe_init_led_link_act_generic - Store the LED index link/activity. 7568c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 7578c2ecf20Sopenharmony_ci * 7588c2ecf20Sopenharmony_ci * Store the index for the link active LED. This will be used to support 7598c2ecf20Sopenharmony_ci * blinking the LED. 7608c2ecf20Sopenharmony_ci **/ 7618c2ecf20Sopenharmony_cis32 ixgbe_init_led_link_act_generic(struct ixgbe_hw *hw) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct ixgbe_mac_info *mac = &hw->mac; 7648c2ecf20Sopenharmony_ci u32 led_reg, led_mode; 7658c2ecf20Sopenharmony_ci u16 i; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* Get LED link active from the LEDCTL register */ 7708c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 7718c2ecf20Sopenharmony_ci led_mode = led_reg >> IXGBE_LED_MODE_SHIFT(i); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if ((led_mode & IXGBE_LED_MODE_MASK_BASE) == 7748c2ecf20Sopenharmony_ci IXGBE_LED_LINK_ACTIVE) { 7758c2ecf20Sopenharmony_ci mac->led_link_act = i; 7768c2ecf20Sopenharmony_ci return 0; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* If LEDCTL register does not have the LED link active set, then use 7818c2ecf20Sopenharmony_ci * known MAC defaults. 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_ci switch (hw->mac.type) { 7848c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 7858c2ecf20Sopenharmony_ci mac->led_link_act = 0; 7868c2ecf20Sopenharmony_ci break; 7878c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 7888c2ecf20Sopenharmony_ci mac->led_link_act = 1; 7898c2ecf20Sopenharmony_ci break; 7908c2ecf20Sopenharmony_ci default: 7918c2ecf20Sopenharmony_ci mac->led_link_act = 2; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return 0; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci/** 7988c2ecf20Sopenharmony_ci * ixgbe_led_on_generic - Turns on the software controllable LEDs. 7998c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 8008c2ecf20Sopenharmony_ci * @index: led number to turn on 8018c2ecf20Sopenharmony_ci **/ 8028c2ecf20Sopenharmony_cis32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (index > 3) 8078c2ecf20Sopenharmony_ci return -EINVAL; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* To turn on the LED, set mode to ON. */ 8108c2ecf20Sopenharmony_ci led_reg &= ~IXGBE_LED_MODE_MASK(index); 8118c2ecf20Sopenharmony_ci led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index); 8128c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); 8138c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci return 0; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci/** 8198c2ecf20Sopenharmony_ci * ixgbe_led_off_generic - Turns off the software controllable LEDs. 8208c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 8218c2ecf20Sopenharmony_ci * @index: led number to turn off 8228c2ecf20Sopenharmony_ci **/ 8238c2ecf20Sopenharmony_cis32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (index > 3) 8288c2ecf20Sopenharmony_ci return -EINVAL; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* To turn off the LED, set mode to OFF. */ 8318c2ecf20Sopenharmony_ci led_reg &= ~IXGBE_LED_MODE_MASK(index); 8328c2ecf20Sopenharmony_ci led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index); 8338c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); 8348c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci return 0; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci/** 8408c2ecf20Sopenharmony_ci * ixgbe_init_eeprom_params_generic - Initialize EEPROM params 8418c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 8428c2ecf20Sopenharmony_ci * 8438c2ecf20Sopenharmony_ci * Initializes the EEPROM parameters ixgbe_eeprom_info within the 8448c2ecf20Sopenharmony_ci * ixgbe_hw struct in order to set up EEPROM access. 8458c2ecf20Sopenharmony_ci **/ 8468c2ecf20Sopenharmony_cis32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct ixgbe_eeprom_info *eeprom = &hw->eeprom; 8498c2ecf20Sopenharmony_ci u32 eec; 8508c2ecf20Sopenharmony_ci u16 eeprom_size; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (eeprom->type == ixgbe_eeprom_uninitialized) { 8538c2ecf20Sopenharmony_ci eeprom->type = ixgbe_eeprom_none; 8548c2ecf20Sopenharmony_ci /* Set default semaphore delay to 10ms which is a well 8558c2ecf20Sopenharmony_ci * tested value */ 8568c2ecf20Sopenharmony_ci eeprom->semaphore_delay = 10; 8578c2ecf20Sopenharmony_ci /* Clear EEPROM page size, it will be initialized as needed */ 8588c2ecf20Sopenharmony_ci eeprom->word_page_size = 0; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* 8618c2ecf20Sopenharmony_ci * Check for EEPROM present first. 8628c2ecf20Sopenharmony_ci * If not present leave as none 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_ci eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); 8658c2ecf20Sopenharmony_ci if (eec & IXGBE_EEC_PRES) { 8668c2ecf20Sopenharmony_ci eeprom->type = ixgbe_eeprom_spi; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* 8698c2ecf20Sopenharmony_ci * SPI EEPROM is assumed here. This code would need to 8708c2ecf20Sopenharmony_ci * change if a future EEPROM is not SPI. 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >> 8738c2ecf20Sopenharmony_ci IXGBE_EEC_SIZE_SHIFT); 8748c2ecf20Sopenharmony_ci eeprom->word_size = BIT(eeprom_size + 8758c2ecf20Sopenharmony_ci IXGBE_EEPROM_WORD_SIZE_SHIFT); 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (eec & IXGBE_EEC_ADDR_SIZE) 8798c2ecf20Sopenharmony_ci eeprom->address_bits = 16; 8808c2ecf20Sopenharmony_ci else 8818c2ecf20Sopenharmony_ci eeprom->address_bits = 8; 8828c2ecf20Sopenharmony_ci hw_dbg(hw, "Eeprom params: type = %d, size = %d, address bits: %d\n", 8838c2ecf20Sopenharmony_ci eeprom->type, eeprom->word_size, eeprom->address_bits); 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci return 0; 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci/** 8908c2ecf20Sopenharmony_ci * ixgbe_write_eeprom_buffer_bit_bang_generic - Write EEPROM using bit-bang 8918c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 8928c2ecf20Sopenharmony_ci * @offset: offset within the EEPROM to write 8938c2ecf20Sopenharmony_ci * @words: number of words 8948c2ecf20Sopenharmony_ci * @data: 16 bit word(s) to write to EEPROM 8958c2ecf20Sopenharmony_ci * 8968c2ecf20Sopenharmony_ci * Reads 16 bit word(s) from EEPROM through bit-bang method 8978c2ecf20Sopenharmony_ci **/ 8988c2ecf20Sopenharmony_cis32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, 8998c2ecf20Sopenharmony_ci u16 words, u16 *data) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci s32 status; 9028c2ecf20Sopenharmony_ci u16 i, count; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci hw->eeprom.ops.init_params(hw); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (words == 0 || (offset + words > hw->eeprom.word_size)) 9078c2ecf20Sopenharmony_ci return -EINVAL; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* 9108c2ecf20Sopenharmony_ci * The EEPROM page size cannot be queried from the chip. We do lazy 9118c2ecf20Sopenharmony_ci * initialization. It is worth to do that when we write large buffer. 9128c2ecf20Sopenharmony_ci */ 9138c2ecf20Sopenharmony_ci if ((hw->eeprom.word_page_size == 0) && 9148c2ecf20Sopenharmony_ci (words > IXGBE_EEPROM_PAGE_SIZE_MAX)) 9158c2ecf20Sopenharmony_ci ixgbe_detect_eeprom_page_size_generic(hw, offset); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* 9188c2ecf20Sopenharmony_ci * We cannot hold synchronization semaphores for too long 9198c2ecf20Sopenharmony_ci * to avoid other entity starvation. However it is more efficient 9208c2ecf20Sopenharmony_ci * to read in bursts than synchronizing access for each word. 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_ci for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) { 9238c2ecf20Sopenharmony_ci count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ? 9248c2ecf20Sopenharmony_ci IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i); 9258c2ecf20Sopenharmony_ci status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset + i, 9268c2ecf20Sopenharmony_ci count, &data[i]); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (status != 0) 9298c2ecf20Sopenharmony_ci break; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci return status; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci/** 9368c2ecf20Sopenharmony_ci * ixgbe_write_eeprom_buffer_bit_bang - Writes 16 bit word(s) to EEPROM 9378c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 9388c2ecf20Sopenharmony_ci * @offset: offset within the EEPROM to be written to 9398c2ecf20Sopenharmony_ci * @words: number of word(s) 9408c2ecf20Sopenharmony_ci * @data: 16 bit word(s) to be written to the EEPROM 9418c2ecf20Sopenharmony_ci * 9428c2ecf20Sopenharmony_ci * If ixgbe_eeprom_update_checksum is not called after this function, the 9438c2ecf20Sopenharmony_ci * EEPROM will most likely contain an invalid checksum. 9448c2ecf20Sopenharmony_ci **/ 9458c2ecf20Sopenharmony_cistatic s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, 9468c2ecf20Sopenharmony_ci u16 words, u16 *data) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci s32 status; 9498c2ecf20Sopenharmony_ci u16 word; 9508c2ecf20Sopenharmony_ci u16 page_size; 9518c2ecf20Sopenharmony_ci u16 i; 9528c2ecf20Sopenharmony_ci u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci /* Prepare the EEPROM for writing */ 9558c2ecf20Sopenharmony_ci status = ixgbe_acquire_eeprom(hw); 9568c2ecf20Sopenharmony_ci if (status) 9578c2ecf20Sopenharmony_ci return status; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (ixgbe_ready_eeprom(hw) != 0) { 9608c2ecf20Sopenharmony_ci ixgbe_release_eeprom(hw); 9618c2ecf20Sopenharmony_ci return -EIO; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci for (i = 0; i < words; i++) { 9658c2ecf20Sopenharmony_ci ixgbe_standby_eeprom(hw); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* Send the WRITE ENABLE command (8 bit opcode) */ 9688c2ecf20Sopenharmony_ci ixgbe_shift_out_eeprom_bits(hw, 9698c2ecf20Sopenharmony_ci IXGBE_EEPROM_WREN_OPCODE_SPI, 9708c2ecf20Sopenharmony_ci IXGBE_EEPROM_OPCODE_BITS); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci ixgbe_standby_eeprom(hw); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* Some SPI eeproms use the 8th address bit embedded 9758c2ecf20Sopenharmony_ci * in the opcode 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_ci if ((hw->eeprom.address_bits == 8) && 9788c2ecf20Sopenharmony_ci ((offset + i) >= 128)) 9798c2ecf20Sopenharmony_ci write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* Send the Write command (8-bit opcode + addr) */ 9828c2ecf20Sopenharmony_ci ixgbe_shift_out_eeprom_bits(hw, write_opcode, 9838c2ecf20Sopenharmony_ci IXGBE_EEPROM_OPCODE_BITS); 9848c2ecf20Sopenharmony_ci ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), 9858c2ecf20Sopenharmony_ci hw->eeprom.address_bits); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci page_size = hw->eeprom.word_page_size; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci /* Send the data in burst via SPI */ 9908c2ecf20Sopenharmony_ci do { 9918c2ecf20Sopenharmony_ci word = data[i]; 9928c2ecf20Sopenharmony_ci word = (word >> 8) | (word << 8); 9938c2ecf20Sopenharmony_ci ixgbe_shift_out_eeprom_bits(hw, word, 16); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (page_size == 0) 9968c2ecf20Sopenharmony_ci break; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* do not wrap around page */ 9998c2ecf20Sopenharmony_ci if (((offset + i) & (page_size - 1)) == 10008c2ecf20Sopenharmony_ci (page_size - 1)) 10018c2ecf20Sopenharmony_ci break; 10028c2ecf20Sopenharmony_ci } while (++i < words); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci ixgbe_standby_eeprom(hw); 10058c2ecf20Sopenharmony_ci usleep_range(10000, 20000); 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci /* Done with writing - release the EEPROM */ 10088c2ecf20Sopenharmony_ci ixgbe_release_eeprom(hw); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci/** 10148c2ecf20Sopenharmony_ci * ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM 10158c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 10168c2ecf20Sopenharmony_ci * @offset: offset within the EEPROM to be written to 10178c2ecf20Sopenharmony_ci * @data: 16 bit word to be written to the EEPROM 10188c2ecf20Sopenharmony_ci * 10198c2ecf20Sopenharmony_ci * If ixgbe_eeprom_update_checksum is not called after this function, the 10208c2ecf20Sopenharmony_ci * EEPROM will most likely contain an invalid checksum. 10218c2ecf20Sopenharmony_ci **/ 10228c2ecf20Sopenharmony_cis32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci hw->eeprom.ops.init_params(hw); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (offset >= hw->eeprom.word_size) 10278c2ecf20Sopenharmony_ci return -EINVAL; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci return ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 1, &data); 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci/** 10338c2ecf20Sopenharmony_ci * ixgbe_read_eeprom_buffer_bit_bang_generic - Read EEPROM using bit-bang 10348c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 10358c2ecf20Sopenharmony_ci * @offset: offset within the EEPROM to be read 10368c2ecf20Sopenharmony_ci * @words: number of word(s) 10378c2ecf20Sopenharmony_ci * @data: read 16 bit words(s) from EEPROM 10388c2ecf20Sopenharmony_ci * 10398c2ecf20Sopenharmony_ci * Reads 16 bit word(s) from EEPROM through bit-bang method 10408c2ecf20Sopenharmony_ci **/ 10418c2ecf20Sopenharmony_cis32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, 10428c2ecf20Sopenharmony_ci u16 words, u16 *data) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci s32 status; 10458c2ecf20Sopenharmony_ci u16 i, count; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci hw->eeprom.ops.init_params(hw); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (words == 0 || (offset + words > hw->eeprom.word_size)) 10508c2ecf20Sopenharmony_ci return -EINVAL; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* 10538c2ecf20Sopenharmony_ci * We cannot hold synchronization semaphores for too long 10548c2ecf20Sopenharmony_ci * to avoid other entity starvation. However it is more efficient 10558c2ecf20Sopenharmony_ci * to read in bursts than synchronizing access for each word. 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_ci for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) { 10588c2ecf20Sopenharmony_ci count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ? 10598c2ecf20Sopenharmony_ci IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset + i, 10628c2ecf20Sopenharmony_ci count, &data[i]); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (status) 10658c2ecf20Sopenharmony_ci return status; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci return 0; 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci/** 10728c2ecf20Sopenharmony_ci * ixgbe_read_eeprom_buffer_bit_bang - Read EEPROM using bit-bang 10738c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 10748c2ecf20Sopenharmony_ci * @offset: offset within the EEPROM to be read 10758c2ecf20Sopenharmony_ci * @words: number of word(s) 10768c2ecf20Sopenharmony_ci * @data: read 16 bit word(s) from EEPROM 10778c2ecf20Sopenharmony_ci * 10788c2ecf20Sopenharmony_ci * Reads 16 bit word(s) from EEPROM through bit-bang method 10798c2ecf20Sopenharmony_ci **/ 10808c2ecf20Sopenharmony_cistatic s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, 10818c2ecf20Sopenharmony_ci u16 words, u16 *data) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci s32 status; 10848c2ecf20Sopenharmony_ci u16 word_in; 10858c2ecf20Sopenharmony_ci u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; 10868c2ecf20Sopenharmony_ci u16 i; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* Prepare the EEPROM for reading */ 10898c2ecf20Sopenharmony_ci status = ixgbe_acquire_eeprom(hw); 10908c2ecf20Sopenharmony_ci if (status) 10918c2ecf20Sopenharmony_ci return status; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (ixgbe_ready_eeprom(hw) != 0) { 10948c2ecf20Sopenharmony_ci ixgbe_release_eeprom(hw); 10958c2ecf20Sopenharmony_ci return -EIO; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci for (i = 0; i < words; i++) { 10998c2ecf20Sopenharmony_ci ixgbe_standby_eeprom(hw); 11008c2ecf20Sopenharmony_ci /* Some SPI eeproms use the 8th address bit embedded 11018c2ecf20Sopenharmony_ci * in the opcode 11028c2ecf20Sopenharmony_ci */ 11038c2ecf20Sopenharmony_ci if ((hw->eeprom.address_bits == 8) && 11048c2ecf20Sopenharmony_ci ((offset + i) >= 128)) 11058c2ecf20Sopenharmony_ci read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* Send the READ command (opcode + addr) */ 11088c2ecf20Sopenharmony_ci ixgbe_shift_out_eeprom_bits(hw, read_opcode, 11098c2ecf20Sopenharmony_ci IXGBE_EEPROM_OPCODE_BITS); 11108c2ecf20Sopenharmony_ci ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), 11118c2ecf20Sopenharmony_ci hw->eeprom.address_bits); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* Read the data. */ 11148c2ecf20Sopenharmony_ci word_in = ixgbe_shift_in_eeprom_bits(hw, 16); 11158c2ecf20Sopenharmony_ci data[i] = (word_in >> 8) | (word_in << 8); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* End this read operation */ 11198c2ecf20Sopenharmony_ci ixgbe_release_eeprom(hw); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci return 0; 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci/** 11258c2ecf20Sopenharmony_ci * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang 11268c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 11278c2ecf20Sopenharmony_ci * @offset: offset within the EEPROM to be read 11288c2ecf20Sopenharmony_ci * @data: read 16 bit value from EEPROM 11298c2ecf20Sopenharmony_ci * 11308c2ecf20Sopenharmony_ci * Reads 16 bit value from EEPROM through bit-bang method 11318c2ecf20Sopenharmony_ci **/ 11328c2ecf20Sopenharmony_cis32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, 11338c2ecf20Sopenharmony_ci u16 *data) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci hw->eeprom.ops.init_params(hw); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (offset >= hw->eeprom.word_size) 11388c2ecf20Sopenharmony_ci return -EINVAL; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci return ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data); 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci/** 11448c2ecf20Sopenharmony_ci * ixgbe_read_eerd_buffer_generic - Read EEPROM word(s) using EERD 11458c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 11468c2ecf20Sopenharmony_ci * @offset: offset of word in the EEPROM to read 11478c2ecf20Sopenharmony_ci * @words: number of word(s) 11488c2ecf20Sopenharmony_ci * @data: 16 bit word(s) from the EEPROM 11498c2ecf20Sopenharmony_ci * 11508c2ecf20Sopenharmony_ci * Reads a 16 bit word(s) from the EEPROM using the EERD register. 11518c2ecf20Sopenharmony_ci **/ 11528c2ecf20Sopenharmony_cis32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, 11538c2ecf20Sopenharmony_ci u16 words, u16 *data) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci u32 eerd; 11568c2ecf20Sopenharmony_ci s32 status; 11578c2ecf20Sopenharmony_ci u32 i; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci hw->eeprom.ops.init_params(hw); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (words == 0 || offset >= hw->eeprom.word_size) 11628c2ecf20Sopenharmony_ci return -EINVAL; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci for (i = 0; i < words; i++) { 11658c2ecf20Sopenharmony_ci eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) | 11668c2ecf20Sopenharmony_ci IXGBE_EEPROM_RW_REG_START; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd); 11698c2ecf20Sopenharmony_ci status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (status == 0) { 11728c2ecf20Sopenharmony_ci data[i] = (IXGBE_READ_REG(hw, IXGBE_EERD) >> 11738c2ecf20Sopenharmony_ci IXGBE_EEPROM_RW_REG_DATA); 11748c2ecf20Sopenharmony_ci } else { 11758c2ecf20Sopenharmony_ci hw_dbg(hw, "Eeprom read timed out\n"); 11768c2ecf20Sopenharmony_ci return status; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return 0; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci/** 11848c2ecf20Sopenharmony_ci * ixgbe_detect_eeprom_page_size_generic - Detect EEPROM page size 11858c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 11868c2ecf20Sopenharmony_ci * @offset: offset within the EEPROM to be used as a scratch pad 11878c2ecf20Sopenharmony_ci * 11888c2ecf20Sopenharmony_ci * Discover EEPROM page size by writing marching data at given offset. 11898c2ecf20Sopenharmony_ci * This function is called only when we are writing a new large buffer 11908c2ecf20Sopenharmony_ci * at given offset so the data would be overwritten anyway. 11918c2ecf20Sopenharmony_ci **/ 11928c2ecf20Sopenharmony_cistatic s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, 11938c2ecf20Sopenharmony_ci u16 offset) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci u16 data[IXGBE_EEPROM_PAGE_SIZE_MAX]; 11968c2ecf20Sopenharmony_ci s32 status; 11978c2ecf20Sopenharmony_ci u16 i; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_EEPROM_PAGE_SIZE_MAX; i++) 12008c2ecf20Sopenharmony_ci data[i] = i; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX; 12038c2ecf20Sopenharmony_ci status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 12048c2ecf20Sopenharmony_ci IXGBE_EEPROM_PAGE_SIZE_MAX, data); 12058c2ecf20Sopenharmony_ci hw->eeprom.word_page_size = 0; 12068c2ecf20Sopenharmony_ci if (status) 12078c2ecf20Sopenharmony_ci return status; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data); 12108c2ecf20Sopenharmony_ci if (status) 12118c2ecf20Sopenharmony_ci return status; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* 12148c2ecf20Sopenharmony_ci * When writing in burst more than the actual page size 12158c2ecf20Sopenharmony_ci * EEPROM address wraps around current page. 12168c2ecf20Sopenharmony_ci */ 12178c2ecf20Sopenharmony_ci hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX - data[0]; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci hw_dbg(hw, "Detected EEPROM page size = %d words.\n", 12208c2ecf20Sopenharmony_ci hw->eeprom.word_page_size); 12218c2ecf20Sopenharmony_ci return 0; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci/** 12258c2ecf20Sopenharmony_ci * ixgbe_read_eerd_generic - Read EEPROM word using EERD 12268c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 12278c2ecf20Sopenharmony_ci * @offset: offset of word in the EEPROM to read 12288c2ecf20Sopenharmony_ci * @data: word read from the EEPROM 12298c2ecf20Sopenharmony_ci * 12308c2ecf20Sopenharmony_ci * Reads a 16 bit word from the EEPROM using the EERD register. 12318c2ecf20Sopenharmony_ci **/ 12328c2ecf20Sopenharmony_cis32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci return ixgbe_read_eerd_buffer_generic(hw, offset, 1, data); 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci/** 12388c2ecf20Sopenharmony_ci * ixgbe_write_eewr_buffer_generic - Write EEPROM word(s) using EEWR 12398c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 12408c2ecf20Sopenharmony_ci * @offset: offset of word in the EEPROM to write 12418c2ecf20Sopenharmony_ci * @words: number of words 12428c2ecf20Sopenharmony_ci * @data: word(s) write to the EEPROM 12438c2ecf20Sopenharmony_ci * 12448c2ecf20Sopenharmony_ci * Write a 16 bit word(s) to the EEPROM using the EEWR register. 12458c2ecf20Sopenharmony_ci **/ 12468c2ecf20Sopenharmony_cis32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, 12478c2ecf20Sopenharmony_ci u16 words, u16 *data) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci u32 eewr; 12508c2ecf20Sopenharmony_ci s32 status; 12518c2ecf20Sopenharmony_ci u16 i; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci hw->eeprom.ops.init_params(hw); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (words == 0 || offset >= hw->eeprom.word_size) 12568c2ecf20Sopenharmony_ci return -EINVAL; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci for (i = 0; i < words; i++) { 12598c2ecf20Sopenharmony_ci eewr = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) | 12608c2ecf20Sopenharmony_ci (data[i] << IXGBE_EEPROM_RW_REG_DATA) | 12618c2ecf20Sopenharmony_ci IXGBE_EEPROM_RW_REG_START; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); 12648c2ecf20Sopenharmony_ci if (status) { 12658c2ecf20Sopenharmony_ci hw_dbg(hw, "Eeprom write EEWR timed out\n"); 12668c2ecf20Sopenharmony_ci return status; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); 12728c2ecf20Sopenharmony_ci if (status) { 12738c2ecf20Sopenharmony_ci hw_dbg(hw, "Eeprom write EEWR timed out\n"); 12748c2ecf20Sopenharmony_ci return status; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci return 0; 12798c2ecf20Sopenharmony_ci} 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci/** 12828c2ecf20Sopenharmony_ci * ixgbe_write_eewr_generic - Write EEPROM word using EEWR 12838c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 12848c2ecf20Sopenharmony_ci * @offset: offset of word in the EEPROM to write 12858c2ecf20Sopenharmony_ci * @data: word write to the EEPROM 12868c2ecf20Sopenharmony_ci * 12878c2ecf20Sopenharmony_ci * Write a 16 bit word to the EEPROM using the EEWR register. 12888c2ecf20Sopenharmony_ci **/ 12898c2ecf20Sopenharmony_cis32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci return ixgbe_write_eewr_buffer_generic(hw, offset, 1, &data); 12928c2ecf20Sopenharmony_ci} 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci/** 12958c2ecf20Sopenharmony_ci * ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status 12968c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 12978c2ecf20Sopenharmony_ci * @ee_reg: EEPROM flag for polling 12988c2ecf20Sopenharmony_ci * 12998c2ecf20Sopenharmony_ci * Polls the status bit (bit 1) of the EERD or EEWR to determine when the 13008c2ecf20Sopenharmony_ci * read or write is done respectively. 13018c2ecf20Sopenharmony_ci **/ 13028c2ecf20Sopenharmony_cistatic s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci u32 i; 13058c2ecf20Sopenharmony_ci u32 reg; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_EERD_EEWR_ATTEMPTS; i++) { 13088c2ecf20Sopenharmony_ci if (ee_reg == IXGBE_NVM_POLL_READ) 13098c2ecf20Sopenharmony_ci reg = IXGBE_READ_REG(hw, IXGBE_EERD); 13108c2ecf20Sopenharmony_ci else 13118c2ecf20Sopenharmony_ci reg = IXGBE_READ_REG(hw, IXGBE_EEWR); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci if (reg & IXGBE_EEPROM_RW_REG_DONE) { 13148c2ecf20Sopenharmony_ci return 0; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci udelay(5); 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci return -EIO; 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci/** 13228c2ecf20Sopenharmony_ci * ixgbe_acquire_eeprom - Acquire EEPROM using bit-bang 13238c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 13248c2ecf20Sopenharmony_ci * 13258c2ecf20Sopenharmony_ci * Prepares EEPROM for access using bit-bang method. This function should 13268c2ecf20Sopenharmony_ci * be called before issuing a command to the EEPROM. 13278c2ecf20Sopenharmony_ci **/ 13288c2ecf20Sopenharmony_cistatic s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci u32 eec; 13318c2ecf20Sopenharmony_ci u32 i; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != 0) 13348c2ecf20Sopenharmony_ci return -EBUSY; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* Request EEPROM Access */ 13398c2ecf20Sopenharmony_ci eec |= IXGBE_EEC_REQ; 13408c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_EEPROM_GRANT_ATTEMPTS; i++) { 13438c2ecf20Sopenharmony_ci eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); 13448c2ecf20Sopenharmony_ci if (eec & IXGBE_EEC_GNT) 13458c2ecf20Sopenharmony_ci break; 13468c2ecf20Sopenharmony_ci udelay(5); 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci /* Release if grant not acquired */ 13508c2ecf20Sopenharmony_ci if (!(eec & IXGBE_EEC_GNT)) { 13518c2ecf20Sopenharmony_ci eec &= ~IXGBE_EEC_REQ; 13528c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec); 13538c2ecf20Sopenharmony_ci hw_dbg(hw, "Could not acquire EEPROM grant\n"); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); 13568c2ecf20Sopenharmony_ci return -EIO; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* Setup EEPROM for Read/Write */ 13608c2ecf20Sopenharmony_ci /* Clear CS and SK */ 13618c2ecf20Sopenharmony_ci eec &= ~(IXGBE_EEC_CS | IXGBE_EEC_SK); 13628c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec); 13638c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 13648c2ecf20Sopenharmony_ci udelay(1); 13658c2ecf20Sopenharmony_ci return 0; 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci/** 13698c2ecf20Sopenharmony_ci * ixgbe_get_eeprom_semaphore - Get hardware semaphore 13708c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 13718c2ecf20Sopenharmony_ci * 13728c2ecf20Sopenharmony_ci * Sets the hardware semaphores so EEPROM access can occur for bit-bang method 13738c2ecf20Sopenharmony_ci **/ 13748c2ecf20Sopenharmony_cistatic s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci u32 timeout = 2000; 13778c2ecf20Sopenharmony_ci u32 i; 13788c2ecf20Sopenharmony_ci u32 swsm; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci /* Get SMBI software semaphore between device drivers first */ 13818c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 13828c2ecf20Sopenharmony_ci /* 13838c2ecf20Sopenharmony_ci * If the SMBI bit is 0 when we read it, then the bit will be 13848c2ecf20Sopenharmony_ci * set and we have the semaphore 13858c2ecf20Sopenharmony_ci */ 13868c2ecf20Sopenharmony_ci swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw)); 13878c2ecf20Sopenharmony_ci if (!(swsm & IXGBE_SWSM_SMBI)) 13888c2ecf20Sopenharmony_ci break; 13898c2ecf20Sopenharmony_ci usleep_range(50, 100); 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci if (i == timeout) { 13938c2ecf20Sopenharmony_ci hw_dbg(hw, "Driver can't access the Eeprom - SMBI Semaphore not granted.\n"); 13948c2ecf20Sopenharmony_ci /* this release is particularly important because our attempts 13958c2ecf20Sopenharmony_ci * above to get the semaphore may have succeeded, and if there 13968c2ecf20Sopenharmony_ci * was a timeout, we should unconditionally clear the semaphore 13978c2ecf20Sopenharmony_ci * bits to free the driver to make progress 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_ci ixgbe_release_eeprom_semaphore(hw); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci usleep_range(50, 100); 14028c2ecf20Sopenharmony_ci /* one last try 14038c2ecf20Sopenharmony_ci * If the SMBI bit is 0 when we read it, then the bit will be 14048c2ecf20Sopenharmony_ci * set and we have the semaphore 14058c2ecf20Sopenharmony_ci */ 14068c2ecf20Sopenharmony_ci swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw)); 14078c2ecf20Sopenharmony_ci if (swsm & IXGBE_SWSM_SMBI) { 14088c2ecf20Sopenharmony_ci hw_dbg(hw, "Software semaphore SMBI between device drivers not granted.\n"); 14098c2ecf20Sopenharmony_ci return -EIO; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci /* Now get the semaphore between SW/FW through the SWESMBI bit */ 14148c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 14158c2ecf20Sopenharmony_ci swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw)); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* Set the SW EEPROM semaphore bit to request access */ 14188c2ecf20Sopenharmony_ci swsm |= IXGBE_SWSM_SWESMBI; 14198c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_SWSM(hw), swsm); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci /* If we set the bit successfully then we got the 14228c2ecf20Sopenharmony_ci * semaphore. 14238c2ecf20Sopenharmony_ci */ 14248c2ecf20Sopenharmony_ci swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw)); 14258c2ecf20Sopenharmony_ci if (swsm & IXGBE_SWSM_SWESMBI) 14268c2ecf20Sopenharmony_ci break; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci usleep_range(50, 100); 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* Release semaphores and return error if SW EEPROM semaphore 14328c2ecf20Sopenharmony_ci * was not granted because we don't have access to the EEPROM 14338c2ecf20Sopenharmony_ci */ 14348c2ecf20Sopenharmony_ci if (i >= timeout) { 14358c2ecf20Sopenharmony_ci hw_dbg(hw, "SWESMBI Software EEPROM semaphore not granted.\n"); 14368c2ecf20Sopenharmony_ci ixgbe_release_eeprom_semaphore(hw); 14378c2ecf20Sopenharmony_ci return -EIO; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci return 0; 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci/** 14448c2ecf20Sopenharmony_ci * ixgbe_release_eeprom_semaphore - Release hardware semaphore 14458c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 14468c2ecf20Sopenharmony_ci * 14478c2ecf20Sopenharmony_ci * This function clears hardware semaphore bits. 14488c2ecf20Sopenharmony_ci **/ 14498c2ecf20Sopenharmony_cistatic void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci u32 swsm; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw)); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */ 14568c2ecf20Sopenharmony_ci swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI); 14578c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_SWSM(hw), swsm); 14588c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci/** 14628c2ecf20Sopenharmony_ci * ixgbe_ready_eeprom - Polls for EEPROM ready 14638c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 14648c2ecf20Sopenharmony_ci **/ 14658c2ecf20Sopenharmony_cistatic s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci u16 i; 14688c2ecf20Sopenharmony_ci u8 spi_stat_reg; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* 14718c2ecf20Sopenharmony_ci * Read "Status Register" repeatedly until the LSB is cleared. The 14728c2ecf20Sopenharmony_ci * EEPROM will signal that the command has been completed by clearing 14738c2ecf20Sopenharmony_ci * bit 0 of the internal status register. If it's not cleared within 14748c2ecf20Sopenharmony_ci * 5 milliseconds, then error out. 14758c2ecf20Sopenharmony_ci */ 14768c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_EEPROM_MAX_RETRY_SPI; i += 5) { 14778c2ecf20Sopenharmony_ci ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_RDSR_OPCODE_SPI, 14788c2ecf20Sopenharmony_ci IXGBE_EEPROM_OPCODE_BITS); 14798c2ecf20Sopenharmony_ci spi_stat_reg = (u8)ixgbe_shift_in_eeprom_bits(hw, 8); 14808c2ecf20Sopenharmony_ci if (!(spi_stat_reg & IXGBE_EEPROM_STATUS_RDY_SPI)) 14818c2ecf20Sopenharmony_ci break; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci udelay(5); 14848c2ecf20Sopenharmony_ci ixgbe_standby_eeprom(hw); 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci /* 14888c2ecf20Sopenharmony_ci * On some parts, SPI write time could vary from 0-20mSec on 3.3V 14898c2ecf20Sopenharmony_ci * devices (and only 0-5mSec on 5V devices) 14908c2ecf20Sopenharmony_ci */ 14918c2ecf20Sopenharmony_ci if (i >= IXGBE_EEPROM_MAX_RETRY_SPI) { 14928c2ecf20Sopenharmony_ci hw_dbg(hw, "SPI EEPROM Status error\n"); 14938c2ecf20Sopenharmony_ci return -EIO; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci return 0; 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci/** 15008c2ecf20Sopenharmony_ci * ixgbe_standby_eeprom - Returns EEPROM to a "standby" state 15018c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 15028c2ecf20Sopenharmony_ci **/ 15038c2ecf20Sopenharmony_cistatic void ixgbe_standby_eeprom(struct ixgbe_hw *hw) 15048c2ecf20Sopenharmony_ci{ 15058c2ecf20Sopenharmony_ci u32 eec; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci /* Toggle CS to flush commands */ 15108c2ecf20Sopenharmony_ci eec |= IXGBE_EEC_CS; 15118c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec); 15128c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 15138c2ecf20Sopenharmony_ci udelay(1); 15148c2ecf20Sopenharmony_ci eec &= ~IXGBE_EEC_CS; 15158c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec); 15168c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 15178c2ecf20Sopenharmony_ci udelay(1); 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci/** 15218c2ecf20Sopenharmony_ci * ixgbe_shift_out_eeprom_bits - Shift data bits out to the EEPROM. 15228c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 15238c2ecf20Sopenharmony_ci * @data: data to send to the EEPROM 15248c2ecf20Sopenharmony_ci * @count: number of bits to shift out 15258c2ecf20Sopenharmony_ci **/ 15268c2ecf20Sopenharmony_cistatic void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, 15278c2ecf20Sopenharmony_ci u16 count) 15288c2ecf20Sopenharmony_ci{ 15298c2ecf20Sopenharmony_ci u32 eec; 15308c2ecf20Sopenharmony_ci u32 mask; 15318c2ecf20Sopenharmony_ci u32 i; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci /* 15368c2ecf20Sopenharmony_ci * Mask is used to shift "count" bits of "data" out to the EEPROM 15378c2ecf20Sopenharmony_ci * one bit at a time. Determine the starting bit based on count 15388c2ecf20Sopenharmony_ci */ 15398c2ecf20Sopenharmony_ci mask = BIT(count - 1); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 15428c2ecf20Sopenharmony_ci /* 15438c2ecf20Sopenharmony_ci * A "1" is shifted out to the EEPROM by setting bit "DI" to a 15448c2ecf20Sopenharmony_ci * "1", and then raising and then lowering the clock (the SK 15458c2ecf20Sopenharmony_ci * bit controls the clock input to the EEPROM). A "0" is 15468c2ecf20Sopenharmony_ci * shifted out to the EEPROM by setting "DI" to "0" and then 15478c2ecf20Sopenharmony_ci * raising and then lowering the clock. 15488c2ecf20Sopenharmony_ci */ 15498c2ecf20Sopenharmony_ci if (data & mask) 15508c2ecf20Sopenharmony_ci eec |= IXGBE_EEC_DI; 15518c2ecf20Sopenharmony_ci else 15528c2ecf20Sopenharmony_ci eec &= ~IXGBE_EEC_DI; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec); 15558c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci udelay(1); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci ixgbe_raise_eeprom_clk(hw, &eec); 15608c2ecf20Sopenharmony_ci ixgbe_lower_eeprom_clk(hw, &eec); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* 15638c2ecf20Sopenharmony_ci * Shift mask to signify next bit of data to shift in to the 15648c2ecf20Sopenharmony_ci * EEPROM 15658c2ecf20Sopenharmony_ci */ 15668c2ecf20Sopenharmony_ci mask = mask >> 1; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci /* We leave the "DI" bit set to "0" when we leave this routine. */ 15708c2ecf20Sopenharmony_ci eec &= ~IXGBE_EEC_DI; 15718c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec); 15728c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci/** 15768c2ecf20Sopenharmony_ci * ixgbe_shift_in_eeprom_bits - Shift data bits in from the EEPROM 15778c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 15788c2ecf20Sopenharmony_ci * @count: number of bits to shift 15798c2ecf20Sopenharmony_ci **/ 15808c2ecf20Sopenharmony_cistatic u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count) 15818c2ecf20Sopenharmony_ci{ 15828c2ecf20Sopenharmony_ci u32 eec; 15838c2ecf20Sopenharmony_ci u32 i; 15848c2ecf20Sopenharmony_ci u16 data = 0; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci /* 15878c2ecf20Sopenharmony_ci * In order to read a register from the EEPROM, we need to shift 15888c2ecf20Sopenharmony_ci * 'count' bits in from the EEPROM. Bits are "shifted in" by raising 15898c2ecf20Sopenharmony_ci * the clock input to the EEPROM (setting the SK bit), and then reading 15908c2ecf20Sopenharmony_ci * the value of the "DO" bit. During this "shifting in" process the 15918c2ecf20Sopenharmony_ci * "DI" bit should always be clear. 15928c2ecf20Sopenharmony_ci */ 15938c2ecf20Sopenharmony_ci eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci eec &= ~(IXGBE_EEC_DO | IXGBE_EEC_DI); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 15988c2ecf20Sopenharmony_ci data = data << 1; 15998c2ecf20Sopenharmony_ci ixgbe_raise_eeprom_clk(hw, &eec); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci eec &= ~(IXGBE_EEC_DI); 16048c2ecf20Sopenharmony_ci if (eec & IXGBE_EEC_DO) 16058c2ecf20Sopenharmony_ci data |= 1; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci ixgbe_lower_eeprom_clk(hw, &eec); 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci return data; 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci/** 16148c2ecf20Sopenharmony_ci * ixgbe_raise_eeprom_clk - Raises the EEPROM's clock input. 16158c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 16168c2ecf20Sopenharmony_ci * @eec: EEC register's current value 16178c2ecf20Sopenharmony_ci **/ 16188c2ecf20Sopenharmony_cistatic void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci /* 16218c2ecf20Sopenharmony_ci * Raise the clock input to the EEPROM 16228c2ecf20Sopenharmony_ci * (setting the SK bit), then delay 16238c2ecf20Sopenharmony_ci */ 16248c2ecf20Sopenharmony_ci *eec = *eec | IXGBE_EEC_SK; 16258c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), *eec); 16268c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 16278c2ecf20Sopenharmony_ci udelay(1); 16288c2ecf20Sopenharmony_ci} 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci/** 16318c2ecf20Sopenharmony_ci * ixgbe_lower_eeprom_clk - Lowers the EEPROM's clock input. 16328c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 16338c2ecf20Sopenharmony_ci * @eec: EEC's current value 16348c2ecf20Sopenharmony_ci **/ 16358c2ecf20Sopenharmony_cistatic void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci /* 16388c2ecf20Sopenharmony_ci * Lower the clock input to the EEPROM (clearing the SK bit), then 16398c2ecf20Sopenharmony_ci * delay 16408c2ecf20Sopenharmony_ci */ 16418c2ecf20Sopenharmony_ci *eec = *eec & ~IXGBE_EEC_SK; 16428c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), *eec); 16438c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 16448c2ecf20Sopenharmony_ci udelay(1); 16458c2ecf20Sopenharmony_ci} 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci/** 16488c2ecf20Sopenharmony_ci * ixgbe_release_eeprom - Release EEPROM, release semaphores 16498c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 16508c2ecf20Sopenharmony_ci **/ 16518c2ecf20Sopenharmony_cistatic void ixgbe_release_eeprom(struct ixgbe_hw *hw) 16528c2ecf20Sopenharmony_ci{ 16538c2ecf20Sopenharmony_ci u32 eec; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci eec |= IXGBE_EEC_CS; /* Pull CS high */ 16588c2ecf20Sopenharmony_ci eec &= ~IXGBE_EEC_SK; /* Lower SCK */ 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec); 16618c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci udelay(1); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci /* Stop requesting EEPROM access */ 16668c2ecf20Sopenharmony_ci eec &= ~IXGBE_EEC_REQ; 16678c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EEC(hw), eec); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci /* 16728c2ecf20Sopenharmony_ci * Delay before attempt to obtain semaphore again to allow FW 16738c2ecf20Sopenharmony_ci * access. semaphore_delay is in ms we need us for usleep_range 16748c2ecf20Sopenharmony_ci */ 16758c2ecf20Sopenharmony_ci usleep_range(hw->eeprom.semaphore_delay * 1000, 16768c2ecf20Sopenharmony_ci hw->eeprom.semaphore_delay * 2000); 16778c2ecf20Sopenharmony_ci} 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci/** 16808c2ecf20Sopenharmony_ci * ixgbe_calc_eeprom_checksum_generic - Calculates and returns the checksum 16818c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 16828c2ecf20Sopenharmony_ci **/ 16838c2ecf20Sopenharmony_cis32 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw) 16848c2ecf20Sopenharmony_ci{ 16858c2ecf20Sopenharmony_ci u16 i; 16868c2ecf20Sopenharmony_ci u16 j; 16878c2ecf20Sopenharmony_ci u16 checksum = 0; 16888c2ecf20Sopenharmony_ci u16 length = 0; 16898c2ecf20Sopenharmony_ci u16 pointer = 0; 16908c2ecf20Sopenharmony_ci u16 word = 0; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci /* Include 0x0-0x3F in the checksum */ 16938c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { 16948c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, i, &word)) { 16958c2ecf20Sopenharmony_ci hw_dbg(hw, "EEPROM read failed\n"); 16968c2ecf20Sopenharmony_ci break; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci checksum += word; 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci /* Include all data from pointers except for the fw pointer */ 17028c2ecf20Sopenharmony_ci for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) { 17038c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, i, &pointer)) { 17048c2ecf20Sopenharmony_ci hw_dbg(hw, "EEPROM read failed\n"); 17058c2ecf20Sopenharmony_ci return -EIO; 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* If the pointer seems invalid */ 17098c2ecf20Sopenharmony_ci if (pointer == 0xFFFF || pointer == 0) 17108c2ecf20Sopenharmony_ci continue; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, pointer, &length)) { 17138c2ecf20Sopenharmony_ci hw_dbg(hw, "EEPROM read failed\n"); 17148c2ecf20Sopenharmony_ci return -EIO; 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci if (length == 0xFFFF || length == 0) 17188c2ecf20Sopenharmony_ci continue; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci for (j = pointer + 1; j <= pointer + length; j++) { 17218c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, j, &word)) { 17228c2ecf20Sopenharmony_ci hw_dbg(hw, "EEPROM read failed\n"); 17238c2ecf20Sopenharmony_ci return -EIO; 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci checksum += word; 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci } 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci checksum = (u16)IXGBE_EEPROM_SUM - checksum; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci return (s32)checksum; 17328c2ecf20Sopenharmony_ci} 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci/** 17358c2ecf20Sopenharmony_ci * ixgbe_validate_eeprom_checksum_generic - Validate EEPROM checksum 17368c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 17378c2ecf20Sopenharmony_ci * @checksum_val: calculated checksum 17388c2ecf20Sopenharmony_ci * 17398c2ecf20Sopenharmony_ci * Performs checksum calculation and validates the EEPROM checksum. If the 17408c2ecf20Sopenharmony_ci * caller does not need checksum_val, the value can be NULL. 17418c2ecf20Sopenharmony_ci **/ 17428c2ecf20Sopenharmony_cis32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, 17438c2ecf20Sopenharmony_ci u16 *checksum_val) 17448c2ecf20Sopenharmony_ci{ 17458c2ecf20Sopenharmony_ci s32 status; 17468c2ecf20Sopenharmony_ci u16 checksum; 17478c2ecf20Sopenharmony_ci u16 read_checksum = 0; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci /* 17508c2ecf20Sopenharmony_ci * Read the first word from the EEPROM. If this times out or fails, do 17518c2ecf20Sopenharmony_ci * not continue or we could be in for a very long wait while every 17528c2ecf20Sopenharmony_ci * EEPROM read fails 17538c2ecf20Sopenharmony_ci */ 17548c2ecf20Sopenharmony_ci status = hw->eeprom.ops.read(hw, 0, &checksum); 17558c2ecf20Sopenharmony_ci if (status) { 17568c2ecf20Sopenharmony_ci hw_dbg(hw, "EEPROM read failed\n"); 17578c2ecf20Sopenharmony_ci return status; 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci status = hw->eeprom.ops.calc_checksum(hw); 17618c2ecf20Sopenharmony_ci if (status < 0) 17628c2ecf20Sopenharmony_ci return status; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci checksum = (u16)(status & 0xffff); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci status = hw->eeprom.ops.read(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); 17678c2ecf20Sopenharmony_ci if (status) { 17688c2ecf20Sopenharmony_ci hw_dbg(hw, "EEPROM read failed\n"); 17698c2ecf20Sopenharmony_ci return status; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci /* Verify read checksum from EEPROM is the same as 17738c2ecf20Sopenharmony_ci * calculated checksum 17748c2ecf20Sopenharmony_ci */ 17758c2ecf20Sopenharmony_ci if (read_checksum != checksum) 17768c2ecf20Sopenharmony_ci status = -EIO; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci /* If the user cares, return the calculated checksum */ 17798c2ecf20Sopenharmony_ci if (checksum_val) 17808c2ecf20Sopenharmony_ci *checksum_val = checksum; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci return status; 17838c2ecf20Sopenharmony_ci} 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci/** 17868c2ecf20Sopenharmony_ci * ixgbe_update_eeprom_checksum_generic - Updates the EEPROM checksum 17878c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 17888c2ecf20Sopenharmony_ci **/ 17898c2ecf20Sopenharmony_cis32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw) 17908c2ecf20Sopenharmony_ci{ 17918c2ecf20Sopenharmony_ci s32 status; 17928c2ecf20Sopenharmony_ci u16 checksum; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci /* 17958c2ecf20Sopenharmony_ci * Read the first word from the EEPROM. If this times out or fails, do 17968c2ecf20Sopenharmony_ci * not continue or we could be in for a very long wait while every 17978c2ecf20Sopenharmony_ci * EEPROM read fails 17988c2ecf20Sopenharmony_ci */ 17998c2ecf20Sopenharmony_ci status = hw->eeprom.ops.read(hw, 0, &checksum); 18008c2ecf20Sopenharmony_ci if (status) { 18018c2ecf20Sopenharmony_ci hw_dbg(hw, "EEPROM read failed\n"); 18028c2ecf20Sopenharmony_ci return status; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci status = hw->eeprom.ops.calc_checksum(hw); 18068c2ecf20Sopenharmony_ci if (status < 0) 18078c2ecf20Sopenharmony_ci return status; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci checksum = (u16)(status & 0xffff); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci status = hw->eeprom.ops.write(hw, IXGBE_EEPROM_CHECKSUM, checksum); 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci return status; 18148c2ecf20Sopenharmony_ci} 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci/** 18178c2ecf20Sopenharmony_ci * ixgbe_set_rar_generic - Set Rx address register 18188c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 18198c2ecf20Sopenharmony_ci * @index: Receive address register to write 18208c2ecf20Sopenharmony_ci * @addr: Address to put into receive address register 18218c2ecf20Sopenharmony_ci * @vmdq: VMDq "set" or "pool" index 18228c2ecf20Sopenharmony_ci * @enable_addr: set flag that address is active 18238c2ecf20Sopenharmony_ci * 18248c2ecf20Sopenharmony_ci * Puts an ethernet address into a receive address register. 18258c2ecf20Sopenharmony_ci **/ 18268c2ecf20Sopenharmony_cis32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, 18278c2ecf20Sopenharmony_ci u32 enable_addr) 18288c2ecf20Sopenharmony_ci{ 18298c2ecf20Sopenharmony_ci u32 rar_low, rar_high; 18308c2ecf20Sopenharmony_ci u32 rar_entries = hw->mac.num_rar_entries; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci /* Make sure we are using a valid rar index range */ 18338c2ecf20Sopenharmony_ci if (index >= rar_entries) { 18348c2ecf20Sopenharmony_ci hw_dbg(hw, "RAR index %d is out of range.\n", index); 18358c2ecf20Sopenharmony_ci return -EINVAL; 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci /* setup VMDq pool selection before this RAR gets enabled */ 18398c2ecf20Sopenharmony_ci hw->mac.ops.set_vmdq(hw, index, vmdq); 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci /* 18428c2ecf20Sopenharmony_ci * HW expects these in little endian so we reverse the byte 18438c2ecf20Sopenharmony_ci * order from network order (big endian) to little endian 18448c2ecf20Sopenharmony_ci */ 18458c2ecf20Sopenharmony_ci rar_low = ((u32)addr[0] | 18468c2ecf20Sopenharmony_ci ((u32)addr[1] << 8) | 18478c2ecf20Sopenharmony_ci ((u32)addr[2] << 16) | 18488c2ecf20Sopenharmony_ci ((u32)addr[3] << 24)); 18498c2ecf20Sopenharmony_ci /* 18508c2ecf20Sopenharmony_ci * Some parts put the VMDq setting in the extra RAH bits, 18518c2ecf20Sopenharmony_ci * so save everything except the lower 16 bits that hold part 18528c2ecf20Sopenharmony_ci * of the address and the address valid bit. 18538c2ecf20Sopenharmony_ci */ 18548c2ecf20Sopenharmony_ci rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); 18558c2ecf20Sopenharmony_ci rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); 18568c2ecf20Sopenharmony_ci rar_high |= ((u32)addr[4] | ((u32)addr[5] << 8)); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci if (enable_addr != 0) 18598c2ecf20Sopenharmony_ci rar_high |= IXGBE_RAH_AV; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci /* Record lower 32 bits of MAC address and then make 18628c2ecf20Sopenharmony_ci * sure that write is flushed to hardware before writing 18638c2ecf20Sopenharmony_ci * the upper 16 bits and setting the valid bit. 18648c2ecf20Sopenharmony_ci */ 18658c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); 18668c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 18678c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci return 0; 18708c2ecf20Sopenharmony_ci} 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci/** 18738c2ecf20Sopenharmony_ci * ixgbe_clear_rar_generic - Remove Rx address register 18748c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 18758c2ecf20Sopenharmony_ci * @index: Receive address register to write 18768c2ecf20Sopenharmony_ci * 18778c2ecf20Sopenharmony_ci * Clears an ethernet address from a receive address register. 18788c2ecf20Sopenharmony_ci **/ 18798c2ecf20Sopenharmony_cis32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) 18808c2ecf20Sopenharmony_ci{ 18818c2ecf20Sopenharmony_ci u32 rar_high; 18828c2ecf20Sopenharmony_ci u32 rar_entries = hw->mac.num_rar_entries; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci /* Make sure we are using a valid rar index range */ 18858c2ecf20Sopenharmony_ci if (index >= rar_entries) { 18868c2ecf20Sopenharmony_ci hw_dbg(hw, "RAR index %d is out of range.\n", index); 18878c2ecf20Sopenharmony_ci return -EINVAL; 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci /* 18918c2ecf20Sopenharmony_ci * Some parts put the VMDq setting in the extra RAH bits, 18928c2ecf20Sopenharmony_ci * so save everything except the lower 16 bits that hold part 18938c2ecf20Sopenharmony_ci * of the address and the address valid bit. 18948c2ecf20Sopenharmony_ci */ 18958c2ecf20Sopenharmony_ci rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); 18968c2ecf20Sopenharmony_ci rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci /* Clear the address valid bit and upper 16 bits of the address 18998c2ecf20Sopenharmony_ci * before clearing the lower bits. This way we aren't updating 19008c2ecf20Sopenharmony_ci * a live filter. 19018c2ecf20Sopenharmony_ci */ 19028c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); 19038c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 19048c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci /* clear VMDq pool/queue selection for this RAR */ 19078c2ecf20Sopenharmony_ci hw->mac.ops.clear_vmdq(hw, index, IXGBE_CLEAR_VMDQ_ALL); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci return 0; 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci/** 19138c2ecf20Sopenharmony_ci * ixgbe_init_rx_addrs_generic - Initializes receive address filters. 19148c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 19158c2ecf20Sopenharmony_ci * 19168c2ecf20Sopenharmony_ci * Places the MAC address in receive address register 0 and clears the rest 19178c2ecf20Sopenharmony_ci * of the receive address registers. Clears the multicast table. Assumes 19188c2ecf20Sopenharmony_ci * the receiver is in reset when the routine is called. 19198c2ecf20Sopenharmony_ci **/ 19208c2ecf20Sopenharmony_cis32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci u32 i; 19238c2ecf20Sopenharmony_ci u32 rar_entries = hw->mac.num_rar_entries; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci /* 19268c2ecf20Sopenharmony_ci * If the current mac address is valid, assume it is a software override 19278c2ecf20Sopenharmony_ci * to the permanent address. 19288c2ecf20Sopenharmony_ci * Otherwise, use the permanent address from the eeprom. 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(hw->mac.addr)) { 19318c2ecf20Sopenharmony_ci /* Get the MAC address from the RAR0 for later reference */ 19328c2ecf20Sopenharmony_ci hw->mac.ops.get_mac_addr(hw, hw->mac.addr); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci hw_dbg(hw, " Keeping Current RAR0 Addr =%pM\n", hw->mac.addr); 19358c2ecf20Sopenharmony_ci } else { 19368c2ecf20Sopenharmony_ci /* Setup the receive address. */ 19378c2ecf20Sopenharmony_ci hw_dbg(hw, "Overriding MAC Address in RAR[0]\n"); 19388c2ecf20Sopenharmony_ci hw_dbg(hw, " New MAC Addr =%pM\n", hw->mac.addr); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci /* clear VMDq pool/queue selection for RAR 0 */ 19448c2ecf20Sopenharmony_ci hw->mac.ops.clear_vmdq(hw, 0, IXGBE_CLEAR_VMDQ_ALL); 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci hw->addr_ctrl.overflow_promisc = 0; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci hw->addr_ctrl.rar_used_count = 1; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci /* Zero out the other receive addresses. */ 19518c2ecf20Sopenharmony_ci hw_dbg(hw, "Clearing RAR[1-%d]\n", rar_entries - 1); 19528c2ecf20Sopenharmony_ci for (i = 1; i < rar_entries; i++) { 19538c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); 19548c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci /* Clear the MTA */ 19588c2ecf20Sopenharmony_ci hw->addr_ctrl.mta_in_use = 0; 19598c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci hw_dbg(hw, " Clearing MTA\n"); 19628c2ecf20Sopenharmony_ci for (i = 0; i < hw->mac.mcft_size; i++) 19638c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci if (hw->mac.ops.init_uta_tables) 19668c2ecf20Sopenharmony_ci hw->mac.ops.init_uta_tables(hw); 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci return 0; 19698c2ecf20Sopenharmony_ci} 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci/** 19728c2ecf20Sopenharmony_ci * ixgbe_mta_vector - Determines bit-vector in multicast table to set 19738c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 19748c2ecf20Sopenharmony_ci * @mc_addr: the multicast address 19758c2ecf20Sopenharmony_ci * 19768c2ecf20Sopenharmony_ci * Extracts the 12 bits, from a multicast address, to determine which 19778c2ecf20Sopenharmony_ci * bit-vector to set in the multicast table. The hardware uses 12 bits, from 19788c2ecf20Sopenharmony_ci * incoming rx multicast addresses, to determine the bit-vector to check in 19798c2ecf20Sopenharmony_ci * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set 19808c2ecf20Sopenharmony_ci * by the MO field of the MCSTCTRL. The MO field is set during initialization 19818c2ecf20Sopenharmony_ci * to mc_filter_type. 19828c2ecf20Sopenharmony_ci **/ 19838c2ecf20Sopenharmony_cistatic s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) 19848c2ecf20Sopenharmony_ci{ 19858c2ecf20Sopenharmony_ci u32 vector = 0; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci switch (hw->mac.mc_filter_type) { 19888c2ecf20Sopenharmony_ci case 0: /* use bits [47:36] of the address */ 19898c2ecf20Sopenharmony_ci vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4)); 19908c2ecf20Sopenharmony_ci break; 19918c2ecf20Sopenharmony_ci case 1: /* use bits [46:35] of the address */ 19928c2ecf20Sopenharmony_ci vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5)); 19938c2ecf20Sopenharmony_ci break; 19948c2ecf20Sopenharmony_ci case 2: /* use bits [45:34] of the address */ 19958c2ecf20Sopenharmony_ci vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6)); 19968c2ecf20Sopenharmony_ci break; 19978c2ecf20Sopenharmony_ci case 3: /* use bits [43:32] of the address */ 19988c2ecf20Sopenharmony_ci vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8)); 19998c2ecf20Sopenharmony_ci break; 20008c2ecf20Sopenharmony_ci default: /* Invalid mc_filter_type */ 20018c2ecf20Sopenharmony_ci hw_dbg(hw, "MC filter type param set incorrectly\n"); 20028c2ecf20Sopenharmony_ci break; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci /* vector can only be 12-bits or boundary will be exceeded */ 20068c2ecf20Sopenharmony_ci vector &= 0xFFF; 20078c2ecf20Sopenharmony_ci return vector; 20088c2ecf20Sopenharmony_ci} 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci/** 20118c2ecf20Sopenharmony_ci * ixgbe_set_mta - Set bit-vector in multicast table 20128c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 20138c2ecf20Sopenharmony_ci * @mc_addr: Multicast address 20148c2ecf20Sopenharmony_ci * 20158c2ecf20Sopenharmony_ci * Sets the bit-vector in the multicast table. 20168c2ecf20Sopenharmony_ci **/ 20178c2ecf20Sopenharmony_cistatic void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr) 20188c2ecf20Sopenharmony_ci{ 20198c2ecf20Sopenharmony_ci u32 vector; 20208c2ecf20Sopenharmony_ci u32 vector_bit; 20218c2ecf20Sopenharmony_ci u32 vector_reg; 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci hw->addr_ctrl.mta_in_use++; 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci vector = ixgbe_mta_vector(hw, mc_addr); 20268c2ecf20Sopenharmony_ci hw_dbg(hw, " bit-vector = 0x%03X\n", vector); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci /* 20298c2ecf20Sopenharmony_ci * The MTA is a register array of 128 32-bit registers. It is treated 20308c2ecf20Sopenharmony_ci * like an array of 4096 bits. We want to set bit 20318c2ecf20Sopenharmony_ci * BitArray[vector_value]. So we figure out what register the bit is 20328c2ecf20Sopenharmony_ci * in, read it, OR in the new bit, then write back the new value. The 20338c2ecf20Sopenharmony_ci * register is determined by the upper 7 bits of the vector value and 20348c2ecf20Sopenharmony_ci * the bit within that register are determined by the lower 5 bits of 20358c2ecf20Sopenharmony_ci * the value. 20368c2ecf20Sopenharmony_ci */ 20378c2ecf20Sopenharmony_ci vector_reg = (vector >> 5) & 0x7F; 20388c2ecf20Sopenharmony_ci vector_bit = vector & 0x1F; 20398c2ecf20Sopenharmony_ci hw->mac.mta_shadow[vector_reg] |= BIT(vector_bit); 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci/** 20438c2ecf20Sopenharmony_ci * ixgbe_update_mc_addr_list_generic - Updates MAC list of multicast addresses 20448c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 20458c2ecf20Sopenharmony_ci * @netdev: pointer to net device structure 20468c2ecf20Sopenharmony_ci * 20478c2ecf20Sopenharmony_ci * The given list replaces any existing list. Clears the MC addrs from receive 20488c2ecf20Sopenharmony_ci * address registers and the multicast table. Uses unused receive address 20498c2ecf20Sopenharmony_ci * registers for the first multicast addresses, and hashes the rest into the 20508c2ecf20Sopenharmony_ci * multicast table. 20518c2ecf20Sopenharmony_ci **/ 20528c2ecf20Sopenharmony_cis32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, 20538c2ecf20Sopenharmony_ci struct net_device *netdev) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 20568c2ecf20Sopenharmony_ci u32 i; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci /* 20598c2ecf20Sopenharmony_ci * Set the new number of MC addresses that we are being requested to 20608c2ecf20Sopenharmony_ci * use. 20618c2ecf20Sopenharmony_ci */ 20628c2ecf20Sopenharmony_ci hw->addr_ctrl.num_mc_addrs = netdev_mc_count(netdev); 20638c2ecf20Sopenharmony_ci hw->addr_ctrl.mta_in_use = 0; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci /* Clear mta_shadow */ 20668c2ecf20Sopenharmony_ci hw_dbg(hw, " Clearing MTA\n"); 20678c2ecf20Sopenharmony_ci memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci /* Update mta shadow */ 20708c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 20718c2ecf20Sopenharmony_ci hw_dbg(hw, " Adding the multicast addresses:\n"); 20728c2ecf20Sopenharmony_ci ixgbe_set_mta(hw, ha->addr); 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci /* Enable mta */ 20768c2ecf20Sopenharmony_ci for (i = 0; i < hw->mac.mcft_size; i++) 20778c2ecf20Sopenharmony_ci IXGBE_WRITE_REG_ARRAY(hw, IXGBE_MTA(0), i, 20788c2ecf20Sopenharmony_ci hw->mac.mta_shadow[i]); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci if (hw->addr_ctrl.mta_in_use > 0) 20818c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, 20828c2ecf20Sopenharmony_ci IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci hw_dbg(hw, "ixgbe_update_mc_addr_list_generic Complete\n"); 20858c2ecf20Sopenharmony_ci return 0; 20868c2ecf20Sopenharmony_ci} 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci/** 20898c2ecf20Sopenharmony_ci * ixgbe_enable_mc_generic - Enable multicast address in RAR 20908c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 20918c2ecf20Sopenharmony_ci * 20928c2ecf20Sopenharmony_ci * Enables multicast address in RAR and the use of the multicast hash table. 20938c2ecf20Sopenharmony_ci **/ 20948c2ecf20Sopenharmony_cis32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw) 20958c2ecf20Sopenharmony_ci{ 20968c2ecf20Sopenharmony_ci struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci if (a->mta_in_use > 0) 20998c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, IXGBE_MCSTCTRL_MFE | 21008c2ecf20Sopenharmony_ci hw->mac.mc_filter_type); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci return 0; 21038c2ecf20Sopenharmony_ci} 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci/** 21068c2ecf20Sopenharmony_ci * ixgbe_disable_mc_generic - Disable multicast address in RAR 21078c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 21088c2ecf20Sopenharmony_ci * 21098c2ecf20Sopenharmony_ci * Disables multicast address in RAR and the use of the multicast hash table. 21108c2ecf20Sopenharmony_ci **/ 21118c2ecf20Sopenharmony_cis32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) 21128c2ecf20Sopenharmony_ci{ 21138c2ecf20Sopenharmony_ci struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci if (a->mta_in_use > 0) 21168c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci return 0; 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci/** 21228c2ecf20Sopenharmony_ci * ixgbe_fc_enable_generic - Enable flow control 21238c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 21248c2ecf20Sopenharmony_ci * 21258c2ecf20Sopenharmony_ci * Enable flow control according to the current settings. 21268c2ecf20Sopenharmony_ci **/ 21278c2ecf20Sopenharmony_cis32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) 21288c2ecf20Sopenharmony_ci{ 21298c2ecf20Sopenharmony_ci u32 mflcn_reg, fccfg_reg; 21308c2ecf20Sopenharmony_ci u32 reg; 21318c2ecf20Sopenharmony_ci u32 fcrtl, fcrth; 21328c2ecf20Sopenharmony_ci int i; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci /* Validate the water mark configuration. */ 21358c2ecf20Sopenharmony_ci if (!hw->fc.pause_time) 21368c2ecf20Sopenharmony_ci return -EINVAL; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci /* Low water mark of zero causes XOFF floods */ 21398c2ecf20Sopenharmony_ci for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { 21408c2ecf20Sopenharmony_ci if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && 21418c2ecf20Sopenharmony_ci hw->fc.high_water[i]) { 21428c2ecf20Sopenharmony_ci if (!hw->fc.low_water[i] || 21438c2ecf20Sopenharmony_ci hw->fc.low_water[i] >= hw->fc.high_water[i]) { 21448c2ecf20Sopenharmony_ci hw_dbg(hw, "Invalid water mark configuration\n"); 21458c2ecf20Sopenharmony_ci return -EINVAL; 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci } 21488c2ecf20Sopenharmony_ci } 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci /* Negotiate the fc mode to use */ 21518c2ecf20Sopenharmony_ci hw->mac.ops.fc_autoneg(hw); 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci /* Disable any previous flow control settings */ 21548c2ecf20Sopenharmony_ci mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); 21558c2ecf20Sopenharmony_ci mflcn_reg &= ~(IXGBE_MFLCN_RPFCE_MASK | IXGBE_MFLCN_RFCE); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci fccfg_reg = IXGBE_READ_REG(hw, IXGBE_FCCFG); 21588c2ecf20Sopenharmony_ci fccfg_reg &= ~(IXGBE_FCCFG_TFCE_802_3X | IXGBE_FCCFG_TFCE_PRIORITY); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci /* 21618c2ecf20Sopenharmony_ci * The possible values of fc.current_mode are: 21628c2ecf20Sopenharmony_ci * 0: Flow control is completely disabled 21638c2ecf20Sopenharmony_ci * 1: Rx flow control is enabled (we can receive pause frames, 21648c2ecf20Sopenharmony_ci * but not send pause frames). 21658c2ecf20Sopenharmony_ci * 2: Tx flow control is enabled (we can send pause frames but 21668c2ecf20Sopenharmony_ci * we do not support receiving pause frames). 21678c2ecf20Sopenharmony_ci * 3: Both Rx and Tx flow control (symmetric) are enabled. 21688c2ecf20Sopenharmony_ci * other: Invalid. 21698c2ecf20Sopenharmony_ci */ 21708c2ecf20Sopenharmony_ci switch (hw->fc.current_mode) { 21718c2ecf20Sopenharmony_ci case ixgbe_fc_none: 21728c2ecf20Sopenharmony_ci /* 21738c2ecf20Sopenharmony_ci * Flow control is disabled by software override or autoneg. 21748c2ecf20Sopenharmony_ci * The code below will actually disable it in the HW. 21758c2ecf20Sopenharmony_ci */ 21768c2ecf20Sopenharmony_ci break; 21778c2ecf20Sopenharmony_ci case ixgbe_fc_rx_pause: 21788c2ecf20Sopenharmony_ci /* 21798c2ecf20Sopenharmony_ci * Rx Flow control is enabled and Tx Flow control is 21808c2ecf20Sopenharmony_ci * disabled by software override. Since there really 21818c2ecf20Sopenharmony_ci * isn't a way to advertise that we are capable of RX 21828c2ecf20Sopenharmony_ci * Pause ONLY, we will advertise that we support both 21838c2ecf20Sopenharmony_ci * symmetric and asymmetric Rx PAUSE. Later, we will 21848c2ecf20Sopenharmony_ci * disable the adapter's ability to send PAUSE frames. 21858c2ecf20Sopenharmony_ci */ 21868c2ecf20Sopenharmony_ci mflcn_reg |= IXGBE_MFLCN_RFCE; 21878c2ecf20Sopenharmony_ci break; 21888c2ecf20Sopenharmony_ci case ixgbe_fc_tx_pause: 21898c2ecf20Sopenharmony_ci /* 21908c2ecf20Sopenharmony_ci * Tx Flow control is enabled, and Rx Flow control is 21918c2ecf20Sopenharmony_ci * disabled by software override. 21928c2ecf20Sopenharmony_ci */ 21938c2ecf20Sopenharmony_ci fccfg_reg |= IXGBE_FCCFG_TFCE_802_3X; 21948c2ecf20Sopenharmony_ci break; 21958c2ecf20Sopenharmony_ci case ixgbe_fc_full: 21968c2ecf20Sopenharmony_ci /* Flow control (both Rx and Tx) is enabled by SW override. */ 21978c2ecf20Sopenharmony_ci mflcn_reg |= IXGBE_MFLCN_RFCE; 21988c2ecf20Sopenharmony_ci fccfg_reg |= IXGBE_FCCFG_TFCE_802_3X; 21998c2ecf20Sopenharmony_ci break; 22008c2ecf20Sopenharmony_ci default: 22018c2ecf20Sopenharmony_ci hw_dbg(hw, "Flow control param set incorrectly\n"); 22028c2ecf20Sopenharmony_ci return -EIO; 22038c2ecf20Sopenharmony_ci } 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci /* Set 802.3x based flow control settings. */ 22068c2ecf20Sopenharmony_ci mflcn_reg |= IXGBE_MFLCN_DPF; 22078c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); 22088c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci /* Set up and enable Rx high/low water mark thresholds, enable XON. */ 22118c2ecf20Sopenharmony_ci for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { 22128c2ecf20Sopenharmony_ci if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && 22138c2ecf20Sopenharmony_ci hw->fc.high_water[i]) { 22148c2ecf20Sopenharmony_ci fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; 22158c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl); 22168c2ecf20Sopenharmony_ci fcrth = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; 22178c2ecf20Sopenharmony_ci } else { 22188c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), 0); 22198c2ecf20Sopenharmony_ci /* 22208c2ecf20Sopenharmony_ci * In order to prevent Tx hangs when the internal Tx 22218c2ecf20Sopenharmony_ci * switch is enabled we must set the high water mark 22228c2ecf20Sopenharmony_ci * to the Rx packet buffer size - 24KB. This allows 22238c2ecf20Sopenharmony_ci * the Tx switch to function even under heavy Rx 22248c2ecf20Sopenharmony_ci * workloads. 22258c2ecf20Sopenharmony_ci */ 22268c2ecf20Sopenharmony_ci fcrth = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 24576; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), fcrth); 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci /* Configure pause time (2 TCs per register) */ 22338c2ecf20Sopenharmony_ci reg = hw->fc.pause_time * 0x00010001U; 22348c2ecf20Sopenharmony_ci for (i = 0; i < (MAX_TRAFFIC_CLASS / 2); i++) 22358c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci return 0; 22408c2ecf20Sopenharmony_ci} 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci/** 22438c2ecf20Sopenharmony_ci * ixgbe_negotiate_fc - Negotiate flow control 22448c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 22458c2ecf20Sopenharmony_ci * @adv_reg: flow control advertised settings 22468c2ecf20Sopenharmony_ci * @lp_reg: link partner's flow control settings 22478c2ecf20Sopenharmony_ci * @adv_sym: symmetric pause bit in advertisement 22488c2ecf20Sopenharmony_ci * @adv_asm: asymmetric pause bit in advertisement 22498c2ecf20Sopenharmony_ci * @lp_sym: symmetric pause bit in link partner advertisement 22508c2ecf20Sopenharmony_ci * @lp_asm: asymmetric pause bit in link partner advertisement 22518c2ecf20Sopenharmony_ci * 22528c2ecf20Sopenharmony_ci * Find the intersection between advertised settings and link partner's 22538c2ecf20Sopenharmony_ci * advertised settings 22548c2ecf20Sopenharmony_ci **/ 22558c2ecf20Sopenharmony_cis32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, 22568c2ecf20Sopenharmony_ci u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm) 22578c2ecf20Sopenharmony_ci{ 22588c2ecf20Sopenharmony_ci if ((!(adv_reg)) || (!(lp_reg))) 22598c2ecf20Sopenharmony_ci return -EINVAL; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) { 22628c2ecf20Sopenharmony_ci /* 22638c2ecf20Sopenharmony_ci * Now we need to check if the user selected Rx ONLY 22648c2ecf20Sopenharmony_ci * of pause frames. In this case, we had to advertise 22658c2ecf20Sopenharmony_ci * FULL flow control because we could not advertise RX 22668c2ecf20Sopenharmony_ci * ONLY. Hence, we must now check to see if we need to 22678c2ecf20Sopenharmony_ci * turn OFF the TRANSMISSION of PAUSE frames. 22688c2ecf20Sopenharmony_ci */ 22698c2ecf20Sopenharmony_ci if (hw->fc.requested_mode == ixgbe_fc_full) { 22708c2ecf20Sopenharmony_ci hw->fc.current_mode = ixgbe_fc_full; 22718c2ecf20Sopenharmony_ci hw_dbg(hw, "Flow Control = FULL.\n"); 22728c2ecf20Sopenharmony_ci } else { 22738c2ecf20Sopenharmony_ci hw->fc.current_mode = ixgbe_fc_rx_pause; 22748c2ecf20Sopenharmony_ci hw_dbg(hw, "Flow Control=RX PAUSE frames only\n"); 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci } else if (!(adv_reg & adv_sym) && (adv_reg & adv_asm) && 22778c2ecf20Sopenharmony_ci (lp_reg & lp_sym) && (lp_reg & lp_asm)) { 22788c2ecf20Sopenharmony_ci hw->fc.current_mode = ixgbe_fc_tx_pause; 22798c2ecf20Sopenharmony_ci hw_dbg(hw, "Flow Control = TX PAUSE frames only.\n"); 22808c2ecf20Sopenharmony_ci } else if ((adv_reg & adv_sym) && (adv_reg & adv_asm) && 22818c2ecf20Sopenharmony_ci !(lp_reg & lp_sym) && (lp_reg & lp_asm)) { 22828c2ecf20Sopenharmony_ci hw->fc.current_mode = ixgbe_fc_rx_pause; 22838c2ecf20Sopenharmony_ci hw_dbg(hw, "Flow Control = RX PAUSE frames only.\n"); 22848c2ecf20Sopenharmony_ci } else { 22858c2ecf20Sopenharmony_ci hw->fc.current_mode = ixgbe_fc_none; 22868c2ecf20Sopenharmony_ci hw_dbg(hw, "Flow Control = NONE.\n"); 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci return 0; 22898c2ecf20Sopenharmony_ci} 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci/** 22928c2ecf20Sopenharmony_ci * ixgbe_fc_autoneg_fiber - Enable flow control on 1 gig fiber 22938c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 22948c2ecf20Sopenharmony_ci * 22958c2ecf20Sopenharmony_ci * Enable flow control according on 1 gig fiber. 22968c2ecf20Sopenharmony_ci **/ 22978c2ecf20Sopenharmony_cistatic s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) 22988c2ecf20Sopenharmony_ci{ 22998c2ecf20Sopenharmony_ci u32 pcs_anadv_reg, pcs_lpab_reg, linkstat; 23008c2ecf20Sopenharmony_ci s32 ret_val; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci /* 23038c2ecf20Sopenharmony_ci * On multispeed fiber at 1g, bail out if 23048c2ecf20Sopenharmony_ci * - link is up but AN did not complete, or if 23058c2ecf20Sopenharmony_ci * - link is up and AN completed but timed out 23068c2ecf20Sopenharmony_ci */ 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); 23098c2ecf20Sopenharmony_ci if ((!!(linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || 23108c2ecf20Sopenharmony_ci (!!(linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) 23118c2ecf20Sopenharmony_ci return -EIO; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); 23148c2ecf20Sopenharmony_ci pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci ret_val = ixgbe_negotiate_fc(hw, pcs_anadv_reg, 23178c2ecf20Sopenharmony_ci pcs_lpab_reg, IXGBE_PCS1GANA_SYM_PAUSE, 23188c2ecf20Sopenharmony_ci IXGBE_PCS1GANA_ASM_PAUSE, 23198c2ecf20Sopenharmony_ci IXGBE_PCS1GANA_SYM_PAUSE, 23208c2ecf20Sopenharmony_ci IXGBE_PCS1GANA_ASM_PAUSE); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci return ret_val; 23238c2ecf20Sopenharmony_ci} 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci/** 23268c2ecf20Sopenharmony_ci * ixgbe_fc_autoneg_backplane - Enable flow control IEEE clause 37 23278c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 23288c2ecf20Sopenharmony_ci * 23298c2ecf20Sopenharmony_ci * Enable flow control according to IEEE clause 37. 23308c2ecf20Sopenharmony_ci **/ 23318c2ecf20Sopenharmony_cistatic s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) 23328c2ecf20Sopenharmony_ci{ 23338c2ecf20Sopenharmony_ci u32 links2, anlp1_reg, autoc_reg, links; 23348c2ecf20Sopenharmony_ci s32 ret_val; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci /* 23378c2ecf20Sopenharmony_ci * On backplane, bail out if 23388c2ecf20Sopenharmony_ci * - backplane autoneg was not completed, or if 23398c2ecf20Sopenharmony_ci * - we are 82599 and link partner is not AN enabled 23408c2ecf20Sopenharmony_ci */ 23418c2ecf20Sopenharmony_ci links = IXGBE_READ_REG(hw, IXGBE_LINKS); 23428c2ecf20Sopenharmony_ci if ((links & IXGBE_LINKS_KX_AN_COMP) == 0) 23438c2ecf20Sopenharmony_ci return -EIO; 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82599EB) { 23468c2ecf20Sopenharmony_ci links2 = IXGBE_READ_REG(hw, IXGBE_LINKS2); 23478c2ecf20Sopenharmony_ci if ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0) 23488c2ecf20Sopenharmony_ci return -EIO; 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci /* 23518c2ecf20Sopenharmony_ci * Read the 10g AN autoc and LP ability registers and resolve 23528c2ecf20Sopenharmony_ci * local flow control settings accordingly 23538c2ecf20Sopenharmony_ci */ 23548c2ecf20Sopenharmony_ci autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); 23558c2ecf20Sopenharmony_ci anlp1_reg = IXGBE_READ_REG(hw, IXGBE_ANLP1); 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci ret_val = ixgbe_negotiate_fc(hw, autoc_reg, 23588c2ecf20Sopenharmony_ci anlp1_reg, IXGBE_AUTOC_SYM_PAUSE, IXGBE_AUTOC_ASM_PAUSE, 23598c2ecf20Sopenharmony_ci IXGBE_ANLP1_SYM_PAUSE, IXGBE_ANLP1_ASM_PAUSE); 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci return ret_val; 23628c2ecf20Sopenharmony_ci} 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci/** 23658c2ecf20Sopenharmony_ci * ixgbe_fc_autoneg_copper - Enable flow control IEEE clause 37 23668c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 23678c2ecf20Sopenharmony_ci * 23688c2ecf20Sopenharmony_ci * Enable flow control according to IEEE clause 37. 23698c2ecf20Sopenharmony_ci **/ 23708c2ecf20Sopenharmony_cistatic s32 ixgbe_fc_autoneg_copper(struct ixgbe_hw *hw) 23718c2ecf20Sopenharmony_ci{ 23728c2ecf20Sopenharmony_ci u16 technology_ability_reg = 0; 23738c2ecf20Sopenharmony_ci u16 lp_technology_ability_reg = 0; 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, 23768c2ecf20Sopenharmony_ci MDIO_MMD_AN, 23778c2ecf20Sopenharmony_ci &technology_ability_reg); 23788c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_LPA, 23798c2ecf20Sopenharmony_ci MDIO_MMD_AN, 23808c2ecf20Sopenharmony_ci &lp_technology_ability_reg); 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci return ixgbe_negotiate_fc(hw, (u32)technology_ability_reg, 23838c2ecf20Sopenharmony_ci (u32)lp_technology_ability_reg, 23848c2ecf20Sopenharmony_ci IXGBE_TAF_SYM_PAUSE, IXGBE_TAF_ASM_PAUSE, 23858c2ecf20Sopenharmony_ci IXGBE_TAF_SYM_PAUSE, IXGBE_TAF_ASM_PAUSE); 23868c2ecf20Sopenharmony_ci} 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci/** 23898c2ecf20Sopenharmony_ci * ixgbe_fc_autoneg - Configure flow control 23908c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 23918c2ecf20Sopenharmony_ci * 23928c2ecf20Sopenharmony_ci * Compares our advertised flow control capabilities to those advertised by 23938c2ecf20Sopenharmony_ci * our link partner, and determines the proper flow control mode to use. 23948c2ecf20Sopenharmony_ci **/ 23958c2ecf20Sopenharmony_civoid ixgbe_fc_autoneg(struct ixgbe_hw *hw) 23968c2ecf20Sopenharmony_ci{ 23978c2ecf20Sopenharmony_ci ixgbe_link_speed speed; 23988c2ecf20Sopenharmony_ci s32 ret_val = -EIO; 23998c2ecf20Sopenharmony_ci bool link_up; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci /* 24028c2ecf20Sopenharmony_ci * AN should have completed when the cable was plugged in. 24038c2ecf20Sopenharmony_ci * Look for reasons to bail out. Bail out if: 24048c2ecf20Sopenharmony_ci * - FC autoneg is disabled, or if 24058c2ecf20Sopenharmony_ci * - link is not up. 24068c2ecf20Sopenharmony_ci * 24078c2ecf20Sopenharmony_ci * Since we're being called from an LSC, link is already known to be up. 24088c2ecf20Sopenharmony_ci * So use link_up_wait_to_complete=false. 24098c2ecf20Sopenharmony_ci */ 24108c2ecf20Sopenharmony_ci if (hw->fc.disable_fc_autoneg) 24118c2ecf20Sopenharmony_ci goto out; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci hw->mac.ops.check_link(hw, &speed, &link_up, false); 24148c2ecf20Sopenharmony_ci if (!link_up) 24158c2ecf20Sopenharmony_ci goto out; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci switch (hw->phy.media_type) { 24188c2ecf20Sopenharmony_ci /* Autoneg flow control on fiber adapters */ 24198c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber: 24208c2ecf20Sopenharmony_ci if (speed == IXGBE_LINK_SPEED_1GB_FULL) 24218c2ecf20Sopenharmony_ci ret_val = ixgbe_fc_autoneg_fiber(hw); 24228c2ecf20Sopenharmony_ci break; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci /* Autoneg flow control on backplane adapters */ 24258c2ecf20Sopenharmony_ci case ixgbe_media_type_backplane: 24268c2ecf20Sopenharmony_ci ret_val = ixgbe_fc_autoneg_backplane(hw); 24278c2ecf20Sopenharmony_ci break; 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci /* Autoneg flow control on copper adapters */ 24308c2ecf20Sopenharmony_ci case ixgbe_media_type_copper: 24318c2ecf20Sopenharmony_ci if (ixgbe_device_supports_autoneg_fc(hw)) 24328c2ecf20Sopenharmony_ci ret_val = ixgbe_fc_autoneg_copper(hw); 24338c2ecf20Sopenharmony_ci break; 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci default: 24368c2ecf20Sopenharmony_ci break; 24378c2ecf20Sopenharmony_ci } 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ciout: 24408c2ecf20Sopenharmony_ci if (ret_val == 0) { 24418c2ecf20Sopenharmony_ci hw->fc.fc_was_autonegged = true; 24428c2ecf20Sopenharmony_ci } else { 24438c2ecf20Sopenharmony_ci hw->fc.fc_was_autonegged = false; 24448c2ecf20Sopenharmony_ci hw->fc.current_mode = hw->fc.requested_mode; 24458c2ecf20Sopenharmony_ci } 24468c2ecf20Sopenharmony_ci} 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci/** 24498c2ecf20Sopenharmony_ci * ixgbe_pcie_timeout_poll - Return number of times to poll for completion 24508c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 24518c2ecf20Sopenharmony_ci * 24528c2ecf20Sopenharmony_ci * System-wide timeout range is encoded in PCIe Device Control2 register. 24538c2ecf20Sopenharmony_ci * 24548c2ecf20Sopenharmony_ci * Add 10% to specified maximum and return the number of times to poll for 24558c2ecf20Sopenharmony_ci * completion timeout, in units of 100 microsec. Never return less than 24568c2ecf20Sopenharmony_ci * 800 = 80 millisec. 24578c2ecf20Sopenharmony_ci **/ 24588c2ecf20Sopenharmony_cistatic u32 ixgbe_pcie_timeout_poll(struct ixgbe_hw *hw) 24598c2ecf20Sopenharmony_ci{ 24608c2ecf20Sopenharmony_ci s16 devctl2; 24618c2ecf20Sopenharmony_ci u32 pollcnt; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci devctl2 = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_CONTROL2); 24648c2ecf20Sopenharmony_ci devctl2 &= IXGBE_PCIDEVCTRL2_TIMEO_MASK; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci switch (devctl2) { 24678c2ecf20Sopenharmony_ci case IXGBE_PCIDEVCTRL2_65_130ms: 24688c2ecf20Sopenharmony_ci pollcnt = 1300; /* 130 millisec */ 24698c2ecf20Sopenharmony_ci break; 24708c2ecf20Sopenharmony_ci case IXGBE_PCIDEVCTRL2_260_520ms: 24718c2ecf20Sopenharmony_ci pollcnt = 5200; /* 520 millisec */ 24728c2ecf20Sopenharmony_ci break; 24738c2ecf20Sopenharmony_ci case IXGBE_PCIDEVCTRL2_1_2s: 24748c2ecf20Sopenharmony_ci pollcnt = 20000; /* 2 sec */ 24758c2ecf20Sopenharmony_ci break; 24768c2ecf20Sopenharmony_ci case IXGBE_PCIDEVCTRL2_4_8s: 24778c2ecf20Sopenharmony_ci pollcnt = 80000; /* 8 sec */ 24788c2ecf20Sopenharmony_ci break; 24798c2ecf20Sopenharmony_ci case IXGBE_PCIDEVCTRL2_17_34s: 24808c2ecf20Sopenharmony_ci pollcnt = 34000; /* 34 sec */ 24818c2ecf20Sopenharmony_ci break; 24828c2ecf20Sopenharmony_ci case IXGBE_PCIDEVCTRL2_50_100us: /* 100 microsecs */ 24838c2ecf20Sopenharmony_ci case IXGBE_PCIDEVCTRL2_1_2ms: /* 2 millisecs */ 24848c2ecf20Sopenharmony_ci case IXGBE_PCIDEVCTRL2_16_32ms: /* 32 millisec */ 24858c2ecf20Sopenharmony_ci case IXGBE_PCIDEVCTRL2_16_32ms_def: /* 32 millisec default */ 24868c2ecf20Sopenharmony_ci default: 24878c2ecf20Sopenharmony_ci pollcnt = 800; /* 80 millisec minimum */ 24888c2ecf20Sopenharmony_ci break; 24898c2ecf20Sopenharmony_ci } 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci /* add 10% to spec maximum */ 24928c2ecf20Sopenharmony_ci return (pollcnt * 11) / 10; 24938c2ecf20Sopenharmony_ci} 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci/** 24968c2ecf20Sopenharmony_ci * ixgbe_disable_pcie_primary - Disable PCI-express primary access 24978c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 24988c2ecf20Sopenharmony_ci * 24998c2ecf20Sopenharmony_ci * Disables PCI-Express primary access and verifies there are no pending 25008c2ecf20Sopenharmony_ci * requests. -EALREADY is returned if primary disable 25018c2ecf20Sopenharmony_ci * bit hasn't caused the primary requests to be disabled, else 0 25028c2ecf20Sopenharmony_ci * is returned signifying primary requests disabled. 25038c2ecf20Sopenharmony_ci **/ 25048c2ecf20Sopenharmony_cistatic s32 ixgbe_disable_pcie_primary(struct ixgbe_hw *hw) 25058c2ecf20Sopenharmony_ci{ 25068c2ecf20Sopenharmony_ci u32 i, poll; 25078c2ecf20Sopenharmony_ci u16 value; 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci /* Always set this bit to ensure any future transactions are blocked */ 25108c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_CTRL, IXGBE_CTRL_GIO_DIS); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci /* Poll for bit to read as set */ 25138c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_PCI_PRIMARY_DISABLE_TIMEOUT; i++) { 25148c2ecf20Sopenharmony_ci if (IXGBE_READ_REG(hw, IXGBE_CTRL) & IXGBE_CTRL_GIO_DIS) 25158c2ecf20Sopenharmony_ci break; 25168c2ecf20Sopenharmony_ci usleep_range(100, 120); 25178c2ecf20Sopenharmony_ci } 25188c2ecf20Sopenharmony_ci if (i >= IXGBE_PCI_PRIMARY_DISABLE_TIMEOUT) { 25198c2ecf20Sopenharmony_ci hw_dbg(hw, "GIO disable did not set - requesting resets\n"); 25208c2ecf20Sopenharmony_ci goto gio_disable_fail; 25218c2ecf20Sopenharmony_ci } 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci /* Exit if primary requests are blocked */ 25248c2ecf20Sopenharmony_ci if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO) || 25258c2ecf20Sopenharmony_ci ixgbe_removed(hw->hw_addr)) 25268c2ecf20Sopenharmony_ci return 0; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci /* Poll for primary request bit to clear */ 25298c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_PCI_PRIMARY_DISABLE_TIMEOUT; i++) { 25308c2ecf20Sopenharmony_ci udelay(100); 25318c2ecf20Sopenharmony_ci if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) 25328c2ecf20Sopenharmony_ci return 0; 25338c2ecf20Sopenharmony_ci } 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci /* 25368c2ecf20Sopenharmony_ci * Two consecutive resets are required via CTRL.RST per datasheet 25378c2ecf20Sopenharmony_ci * 5.2.5.3.2 Primary Disable. We set a flag to inform the reset routine 25388c2ecf20Sopenharmony_ci * of this need. The first reset prevents new primary requests from 25398c2ecf20Sopenharmony_ci * being issued by our device. We then must wait 1usec or more for any 25408c2ecf20Sopenharmony_ci * remaining completions from the PCIe bus to trickle in, and then reset 25418c2ecf20Sopenharmony_ci * again to clear out any effects they may have had on our device. 25428c2ecf20Sopenharmony_ci */ 25438c2ecf20Sopenharmony_ci hw_dbg(hw, "GIO Primary Disable bit didn't clear - requesting resets\n"); 25448c2ecf20Sopenharmony_cigio_disable_fail: 25458c2ecf20Sopenharmony_ci hw->mac.flags |= IXGBE_FLAGS_DOUBLE_RESET_REQUIRED; 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci if (hw->mac.type >= ixgbe_mac_X550) 25488c2ecf20Sopenharmony_ci return 0; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci /* 25518c2ecf20Sopenharmony_ci * Before proceeding, make sure that the PCIe block does not have 25528c2ecf20Sopenharmony_ci * transactions pending. 25538c2ecf20Sopenharmony_ci */ 25548c2ecf20Sopenharmony_ci poll = ixgbe_pcie_timeout_poll(hw); 25558c2ecf20Sopenharmony_ci for (i = 0; i < poll; i++) { 25568c2ecf20Sopenharmony_ci udelay(100); 25578c2ecf20Sopenharmony_ci value = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_STATUS); 25588c2ecf20Sopenharmony_ci if (ixgbe_removed(hw->hw_addr)) 25598c2ecf20Sopenharmony_ci return 0; 25608c2ecf20Sopenharmony_ci if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING)) 25618c2ecf20Sopenharmony_ci return 0; 25628c2ecf20Sopenharmony_ci } 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci hw_dbg(hw, "PCIe transaction pending bit also did not clear.\n"); 25658c2ecf20Sopenharmony_ci return -EALREADY; 25668c2ecf20Sopenharmony_ci} 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci/** 25698c2ecf20Sopenharmony_ci * ixgbe_acquire_swfw_sync - Acquire SWFW semaphore 25708c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 25718c2ecf20Sopenharmony_ci * @mask: Mask to specify which semaphore to acquire 25728c2ecf20Sopenharmony_ci * 25738c2ecf20Sopenharmony_ci * Acquires the SWFW semaphore through the GSSR register for the specified 25748c2ecf20Sopenharmony_ci * function (CSR, PHY0, PHY1, EEPROM, Flash) 25758c2ecf20Sopenharmony_ci **/ 25768c2ecf20Sopenharmony_cis32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u32 mask) 25778c2ecf20Sopenharmony_ci{ 25788c2ecf20Sopenharmony_ci u32 gssr = 0; 25798c2ecf20Sopenharmony_ci u32 swmask = mask; 25808c2ecf20Sopenharmony_ci u32 fwmask = mask << 5; 25818c2ecf20Sopenharmony_ci u32 timeout = 200; 25828c2ecf20Sopenharmony_ci u32 i; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 25858c2ecf20Sopenharmony_ci /* 25868c2ecf20Sopenharmony_ci * SW NVM semaphore bit is used for access to all 25878c2ecf20Sopenharmony_ci * SW_FW_SYNC bits (not just NVM) 25888c2ecf20Sopenharmony_ci */ 25898c2ecf20Sopenharmony_ci if (ixgbe_get_eeprom_semaphore(hw)) 25908c2ecf20Sopenharmony_ci return -EBUSY; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci gssr = IXGBE_READ_REG(hw, IXGBE_GSSR); 25938c2ecf20Sopenharmony_ci if (!(gssr & (fwmask | swmask))) { 25948c2ecf20Sopenharmony_ci gssr |= swmask; 25958c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); 25968c2ecf20Sopenharmony_ci ixgbe_release_eeprom_semaphore(hw); 25978c2ecf20Sopenharmony_ci return 0; 25988c2ecf20Sopenharmony_ci } else { 25998c2ecf20Sopenharmony_ci /* Resource is currently in use by FW or SW */ 26008c2ecf20Sopenharmony_ci ixgbe_release_eeprom_semaphore(hw); 26018c2ecf20Sopenharmony_ci usleep_range(5000, 10000); 26028c2ecf20Sopenharmony_ci } 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci /* If time expired clear the bits holding the lock and retry */ 26068c2ecf20Sopenharmony_ci if (gssr & (fwmask | swmask)) 26078c2ecf20Sopenharmony_ci ixgbe_release_swfw_sync(hw, gssr & (fwmask | swmask)); 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci usleep_range(5000, 10000); 26108c2ecf20Sopenharmony_ci return -EBUSY; 26118c2ecf20Sopenharmony_ci} 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci/** 26148c2ecf20Sopenharmony_ci * ixgbe_release_swfw_sync - Release SWFW semaphore 26158c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 26168c2ecf20Sopenharmony_ci * @mask: Mask to specify which semaphore to release 26178c2ecf20Sopenharmony_ci * 26188c2ecf20Sopenharmony_ci * Releases the SWFW semaphore through the GSSR register for the specified 26198c2ecf20Sopenharmony_ci * function (CSR, PHY0, PHY1, EEPROM, Flash) 26208c2ecf20Sopenharmony_ci **/ 26218c2ecf20Sopenharmony_civoid ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u32 mask) 26228c2ecf20Sopenharmony_ci{ 26238c2ecf20Sopenharmony_ci u32 gssr; 26248c2ecf20Sopenharmony_ci u32 swmask = mask; 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci ixgbe_get_eeprom_semaphore(hw); 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci gssr = IXGBE_READ_REG(hw, IXGBE_GSSR); 26298c2ecf20Sopenharmony_ci gssr &= ~swmask; 26308c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci ixgbe_release_eeprom_semaphore(hw); 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci/** 26368c2ecf20Sopenharmony_ci * prot_autoc_read_generic - Hides MAC differences needed for AUTOC read 26378c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 26388c2ecf20Sopenharmony_ci * @reg_val: Value we read from AUTOC 26398c2ecf20Sopenharmony_ci * @locked: bool to indicate whether the SW/FW lock should be taken. Never 26408c2ecf20Sopenharmony_ci * true in this the generic case. 26418c2ecf20Sopenharmony_ci * 26428c2ecf20Sopenharmony_ci * The default case requires no protection so just to the register read. 26438c2ecf20Sopenharmony_ci **/ 26448c2ecf20Sopenharmony_cis32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *locked, u32 *reg_val) 26458c2ecf20Sopenharmony_ci{ 26468c2ecf20Sopenharmony_ci *locked = false; 26478c2ecf20Sopenharmony_ci *reg_val = IXGBE_READ_REG(hw, IXGBE_AUTOC); 26488c2ecf20Sopenharmony_ci return 0; 26498c2ecf20Sopenharmony_ci} 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci/** 26528c2ecf20Sopenharmony_ci * prot_autoc_write_generic - Hides MAC differences needed for AUTOC write 26538c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 26548c2ecf20Sopenharmony_ci * @reg_val: value to write to AUTOC 26558c2ecf20Sopenharmony_ci * @locked: bool to indicate whether the SW/FW lock was already taken by 26568c2ecf20Sopenharmony_ci * previous read. 26578c2ecf20Sopenharmony_ci **/ 26588c2ecf20Sopenharmony_cis32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked) 26598c2ecf20Sopenharmony_ci{ 26608c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_val); 26618c2ecf20Sopenharmony_ci return 0; 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci/** 26658c2ecf20Sopenharmony_ci * ixgbe_disable_rx_buff_generic - Stops the receive data path 26668c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 26678c2ecf20Sopenharmony_ci * 26688c2ecf20Sopenharmony_ci * Stops the receive data path and waits for the HW to internally 26698c2ecf20Sopenharmony_ci * empty the Rx security block. 26708c2ecf20Sopenharmony_ci **/ 26718c2ecf20Sopenharmony_cis32 ixgbe_disable_rx_buff_generic(struct ixgbe_hw *hw) 26728c2ecf20Sopenharmony_ci{ 26738c2ecf20Sopenharmony_ci#define IXGBE_MAX_SECRX_POLL 40 26748c2ecf20Sopenharmony_ci int i; 26758c2ecf20Sopenharmony_ci int secrxreg; 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci secrxreg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL); 26788c2ecf20Sopenharmony_ci secrxreg |= IXGBE_SECRXCTRL_RX_DIS; 26798c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, secrxreg); 26808c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_MAX_SECRX_POLL; i++) { 26818c2ecf20Sopenharmony_ci secrxreg = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT); 26828c2ecf20Sopenharmony_ci if (secrxreg & IXGBE_SECRXSTAT_SECRX_RDY) 26838c2ecf20Sopenharmony_ci break; 26848c2ecf20Sopenharmony_ci else 26858c2ecf20Sopenharmony_ci /* Use interrupt-safe sleep just in case */ 26868c2ecf20Sopenharmony_ci udelay(1000); 26878c2ecf20Sopenharmony_ci } 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci /* For informational purposes only */ 26908c2ecf20Sopenharmony_ci if (i >= IXGBE_MAX_SECRX_POLL) 26918c2ecf20Sopenharmony_ci hw_dbg(hw, "Rx unit being enabled before security path fully disabled. Continuing with init.\n"); 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci return 0; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci} 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci/** 26988c2ecf20Sopenharmony_ci * ixgbe_enable_rx_buff - Enables the receive data path 26998c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 27008c2ecf20Sopenharmony_ci * 27018c2ecf20Sopenharmony_ci * Enables the receive data path 27028c2ecf20Sopenharmony_ci **/ 27038c2ecf20Sopenharmony_cis32 ixgbe_enable_rx_buff_generic(struct ixgbe_hw *hw) 27048c2ecf20Sopenharmony_ci{ 27058c2ecf20Sopenharmony_ci u32 secrxreg; 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci secrxreg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL); 27088c2ecf20Sopenharmony_ci secrxreg &= ~IXGBE_SECRXCTRL_RX_DIS; 27098c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, secrxreg); 27108c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci return 0; 27138c2ecf20Sopenharmony_ci} 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci/** 27168c2ecf20Sopenharmony_ci * ixgbe_enable_rx_dma_generic - Enable the Rx DMA unit 27178c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 27188c2ecf20Sopenharmony_ci * @regval: register value to write to RXCTRL 27198c2ecf20Sopenharmony_ci * 27208c2ecf20Sopenharmony_ci * Enables the Rx DMA unit 27218c2ecf20Sopenharmony_ci **/ 27228c2ecf20Sopenharmony_cis32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval) 27238c2ecf20Sopenharmony_ci{ 27248c2ecf20Sopenharmony_ci if (regval & IXGBE_RXCTRL_RXEN) 27258c2ecf20Sopenharmony_ci hw->mac.ops.enable_rx(hw); 27268c2ecf20Sopenharmony_ci else 27278c2ecf20Sopenharmony_ci hw->mac.ops.disable_rx(hw); 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci return 0; 27308c2ecf20Sopenharmony_ci} 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci/** 27338c2ecf20Sopenharmony_ci * ixgbe_blink_led_start_generic - Blink LED based on index. 27348c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 27358c2ecf20Sopenharmony_ci * @index: led number to blink 27368c2ecf20Sopenharmony_ci **/ 27378c2ecf20Sopenharmony_cis32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) 27388c2ecf20Sopenharmony_ci{ 27398c2ecf20Sopenharmony_ci ixgbe_link_speed speed = 0; 27408c2ecf20Sopenharmony_ci bool link_up = false; 27418c2ecf20Sopenharmony_ci u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); 27428c2ecf20Sopenharmony_ci u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); 27438c2ecf20Sopenharmony_ci bool locked = false; 27448c2ecf20Sopenharmony_ci s32 ret_val; 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci if (index > 3) 27478c2ecf20Sopenharmony_ci return -EINVAL; 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci /* 27508c2ecf20Sopenharmony_ci * Link must be up to auto-blink the LEDs; 27518c2ecf20Sopenharmony_ci * Force it if link is down. 27528c2ecf20Sopenharmony_ci */ 27538c2ecf20Sopenharmony_ci hw->mac.ops.check_link(hw, &speed, &link_up, false); 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci if (!link_up) { 27568c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg); 27578c2ecf20Sopenharmony_ci if (ret_val) 27588c2ecf20Sopenharmony_ci return ret_val; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci autoc_reg |= IXGBE_AUTOC_AN_RESTART; 27618c2ecf20Sopenharmony_ci autoc_reg |= IXGBE_AUTOC_FLU; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked); 27648c2ecf20Sopenharmony_ci if (ret_val) 27658c2ecf20Sopenharmony_ci return ret_val; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci usleep_range(10000, 20000); 27708c2ecf20Sopenharmony_ci } 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci led_reg &= ~IXGBE_LED_MODE_MASK(index); 27738c2ecf20Sopenharmony_ci led_reg |= IXGBE_LED_BLINK(index); 27748c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); 27758c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci return 0; 27788c2ecf20Sopenharmony_ci} 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci/** 27818c2ecf20Sopenharmony_ci * ixgbe_blink_led_stop_generic - Stop blinking LED based on index. 27828c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 27838c2ecf20Sopenharmony_ci * @index: led number to stop blinking 27848c2ecf20Sopenharmony_ci **/ 27858c2ecf20Sopenharmony_cis32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) 27868c2ecf20Sopenharmony_ci{ 27878c2ecf20Sopenharmony_ci u32 autoc_reg = 0; 27888c2ecf20Sopenharmony_ci u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); 27898c2ecf20Sopenharmony_ci bool locked = false; 27908c2ecf20Sopenharmony_ci s32 ret_val; 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci if (index > 3) 27938c2ecf20Sopenharmony_ci return -EINVAL; 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg); 27968c2ecf20Sopenharmony_ci if (ret_val) 27978c2ecf20Sopenharmony_ci return ret_val; 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci autoc_reg &= ~IXGBE_AUTOC_FLU; 28008c2ecf20Sopenharmony_ci autoc_reg |= IXGBE_AUTOC_AN_RESTART; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked); 28038c2ecf20Sopenharmony_ci if (ret_val) 28048c2ecf20Sopenharmony_ci return ret_val; 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci led_reg &= ~IXGBE_LED_MODE_MASK(index); 28078c2ecf20Sopenharmony_ci led_reg &= ~IXGBE_LED_BLINK(index); 28088c2ecf20Sopenharmony_ci led_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index); 28098c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); 28108c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci return 0; 28138c2ecf20Sopenharmony_ci} 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_ci/** 28168c2ecf20Sopenharmony_ci * ixgbe_get_san_mac_addr_offset - Get SAN MAC address offset from the EEPROM 28178c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 28188c2ecf20Sopenharmony_ci * @san_mac_offset: SAN MAC address offset 28198c2ecf20Sopenharmony_ci * 28208c2ecf20Sopenharmony_ci * This function will read the EEPROM location for the SAN MAC address 28218c2ecf20Sopenharmony_ci * pointer, and returns the value at that location. This is used in both 28228c2ecf20Sopenharmony_ci * get and set mac_addr routines. 28238c2ecf20Sopenharmony_ci **/ 28248c2ecf20Sopenharmony_cistatic s32 ixgbe_get_san_mac_addr_offset(struct ixgbe_hw *hw, 28258c2ecf20Sopenharmony_ci u16 *san_mac_offset) 28268c2ecf20Sopenharmony_ci{ 28278c2ecf20Sopenharmony_ci s32 ret_val; 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci /* 28308c2ecf20Sopenharmony_ci * First read the EEPROM pointer to see if the MAC addresses are 28318c2ecf20Sopenharmony_ci * available. 28328c2ecf20Sopenharmony_ci */ 28338c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, IXGBE_SAN_MAC_ADDR_PTR, 28348c2ecf20Sopenharmony_ci san_mac_offset); 28358c2ecf20Sopenharmony_ci if (ret_val) 28368c2ecf20Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", 28378c2ecf20Sopenharmony_ci IXGBE_SAN_MAC_ADDR_PTR); 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci return ret_val; 28408c2ecf20Sopenharmony_ci} 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci/** 28438c2ecf20Sopenharmony_ci * ixgbe_get_san_mac_addr_generic - SAN MAC address retrieval from the EEPROM 28448c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 28458c2ecf20Sopenharmony_ci * @san_mac_addr: SAN MAC address 28468c2ecf20Sopenharmony_ci * 28478c2ecf20Sopenharmony_ci * Reads the SAN MAC address from the EEPROM, if it's available. This is 28488c2ecf20Sopenharmony_ci * per-port, so set_lan_id() must be called before reading the addresses. 28498c2ecf20Sopenharmony_ci * set_lan_id() is called by identify_sfp(), but this cannot be relied 28508c2ecf20Sopenharmony_ci * upon for non-SFP connections, so we must call it here. 28518c2ecf20Sopenharmony_ci **/ 28528c2ecf20Sopenharmony_cis32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) 28538c2ecf20Sopenharmony_ci{ 28548c2ecf20Sopenharmony_ci u16 san_mac_data, san_mac_offset; 28558c2ecf20Sopenharmony_ci u8 i; 28568c2ecf20Sopenharmony_ci s32 ret_val; 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci /* 28598c2ecf20Sopenharmony_ci * First read the EEPROM pointer to see if the MAC addresses are 28608c2ecf20Sopenharmony_ci * available. If they're not, no point in calling set_lan_id() here. 28618c2ecf20Sopenharmony_ci */ 28628c2ecf20Sopenharmony_ci ret_val = ixgbe_get_san_mac_addr_offset(hw, &san_mac_offset); 28638c2ecf20Sopenharmony_ci if (ret_val || san_mac_offset == 0 || san_mac_offset == 0xFFFF) 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci goto san_mac_addr_clr; 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci /* make sure we know which port we need to program */ 28688c2ecf20Sopenharmony_ci hw->mac.ops.set_lan_id(hw); 28698c2ecf20Sopenharmony_ci /* apply the port offset to the address offset */ 28708c2ecf20Sopenharmony_ci (hw->bus.func) ? (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT1_OFFSET) : 28718c2ecf20Sopenharmony_ci (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT0_OFFSET); 28728c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 28738c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, san_mac_offset, 28748c2ecf20Sopenharmony_ci &san_mac_data); 28758c2ecf20Sopenharmony_ci if (ret_val) { 28768c2ecf20Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", 28778c2ecf20Sopenharmony_ci san_mac_offset); 28788c2ecf20Sopenharmony_ci goto san_mac_addr_clr; 28798c2ecf20Sopenharmony_ci } 28808c2ecf20Sopenharmony_ci san_mac_addr[i * 2] = (u8)(san_mac_data); 28818c2ecf20Sopenharmony_ci san_mac_addr[i * 2 + 1] = (u8)(san_mac_data >> 8); 28828c2ecf20Sopenharmony_ci san_mac_offset++; 28838c2ecf20Sopenharmony_ci } 28848c2ecf20Sopenharmony_ci return 0; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_cisan_mac_addr_clr: 28878c2ecf20Sopenharmony_ci /* No addresses available in this EEPROM. It's not necessarily an 28888c2ecf20Sopenharmony_ci * error though, so just wipe the local address and return. 28898c2ecf20Sopenharmony_ci */ 28908c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 28918c2ecf20Sopenharmony_ci san_mac_addr[i] = 0xFF; 28928c2ecf20Sopenharmony_ci return ret_val; 28938c2ecf20Sopenharmony_ci} 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci/** 28968c2ecf20Sopenharmony_ci * ixgbe_get_pcie_msix_count_generic - Gets MSI-X vector count 28978c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 28988c2ecf20Sopenharmony_ci * 28998c2ecf20Sopenharmony_ci * Read PCIe configuration space, and get the MSI-X vector count from 29008c2ecf20Sopenharmony_ci * the capabilities table. 29018c2ecf20Sopenharmony_ci **/ 29028c2ecf20Sopenharmony_ciu16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw) 29038c2ecf20Sopenharmony_ci{ 29048c2ecf20Sopenharmony_ci u16 msix_count; 29058c2ecf20Sopenharmony_ci u16 max_msix_count; 29068c2ecf20Sopenharmony_ci u16 pcie_offset; 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci switch (hw->mac.type) { 29098c2ecf20Sopenharmony_ci case ixgbe_mac_82598EB: 29108c2ecf20Sopenharmony_ci pcie_offset = IXGBE_PCIE_MSIX_82598_CAPS; 29118c2ecf20Sopenharmony_ci max_msix_count = IXGBE_MAX_MSIX_VECTORS_82598; 29128c2ecf20Sopenharmony_ci break; 29138c2ecf20Sopenharmony_ci case ixgbe_mac_82599EB: 29148c2ecf20Sopenharmony_ci case ixgbe_mac_X540: 29158c2ecf20Sopenharmony_ci case ixgbe_mac_X550: 29168c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 29178c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 29188c2ecf20Sopenharmony_ci pcie_offset = IXGBE_PCIE_MSIX_82599_CAPS; 29198c2ecf20Sopenharmony_ci max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599; 29208c2ecf20Sopenharmony_ci break; 29218c2ecf20Sopenharmony_ci default: 29228c2ecf20Sopenharmony_ci return 1; 29238c2ecf20Sopenharmony_ci } 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci msix_count = ixgbe_read_pci_cfg_word(hw, pcie_offset); 29268c2ecf20Sopenharmony_ci if (ixgbe_removed(hw->hw_addr)) 29278c2ecf20Sopenharmony_ci msix_count = 0; 29288c2ecf20Sopenharmony_ci msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK; 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ci /* MSI-X count is zero-based in HW */ 29318c2ecf20Sopenharmony_ci msix_count++; 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci if (msix_count > max_msix_count) 29348c2ecf20Sopenharmony_ci msix_count = max_msix_count; 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci return msix_count; 29378c2ecf20Sopenharmony_ci} 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci/** 29408c2ecf20Sopenharmony_ci * ixgbe_clear_vmdq_generic - Disassociate a VMDq pool index from a rx address 29418c2ecf20Sopenharmony_ci * @hw: pointer to hardware struct 29428c2ecf20Sopenharmony_ci * @rar: receive address register index to disassociate 29438c2ecf20Sopenharmony_ci * @vmdq: VMDq pool index to remove from the rar 29448c2ecf20Sopenharmony_ci **/ 29458c2ecf20Sopenharmony_cis32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) 29468c2ecf20Sopenharmony_ci{ 29478c2ecf20Sopenharmony_ci u32 mpsar_lo, mpsar_hi; 29488c2ecf20Sopenharmony_ci u32 rar_entries = hw->mac.num_rar_entries; 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci /* Make sure we are using a valid rar index range */ 29518c2ecf20Sopenharmony_ci if (rar >= rar_entries) { 29528c2ecf20Sopenharmony_ci hw_dbg(hw, "RAR index %d is out of range.\n", rar); 29538c2ecf20Sopenharmony_ci return -EINVAL; 29548c2ecf20Sopenharmony_ci } 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci mpsar_lo = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar)); 29578c2ecf20Sopenharmony_ci mpsar_hi = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar)); 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci if (ixgbe_removed(hw->hw_addr)) 29608c2ecf20Sopenharmony_ci return 0; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci if (!mpsar_lo && !mpsar_hi) 29638c2ecf20Sopenharmony_ci return 0; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci if (vmdq == IXGBE_CLEAR_VMDQ_ALL) { 29668c2ecf20Sopenharmony_ci if (mpsar_lo) { 29678c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), 0); 29688c2ecf20Sopenharmony_ci mpsar_lo = 0; 29698c2ecf20Sopenharmony_ci } 29708c2ecf20Sopenharmony_ci if (mpsar_hi) { 29718c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), 0); 29728c2ecf20Sopenharmony_ci mpsar_hi = 0; 29738c2ecf20Sopenharmony_ci } 29748c2ecf20Sopenharmony_ci } else if (vmdq < 32) { 29758c2ecf20Sopenharmony_ci mpsar_lo &= ~BIT(vmdq); 29768c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), mpsar_lo); 29778c2ecf20Sopenharmony_ci } else { 29788c2ecf20Sopenharmony_ci mpsar_hi &= ~BIT(vmdq - 32); 29798c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), mpsar_hi); 29808c2ecf20Sopenharmony_ci } 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci /* was that the last pool using this rar? */ 29838c2ecf20Sopenharmony_ci if (mpsar_lo == 0 && mpsar_hi == 0 && 29848c2ecf20Sopenharmony_ci rar != 0 && rar != hw->mac.san_mac_rar_index) 29858c2ecf20Sopenharmony_ci hw->mac.ops.clear_rar(hw, rar); 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci return 0; 29888c2ecf20Sopenharmony_ci} 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci/** 29918c2ecf20Sopenharmony_ci * ixgbe_set_vmdq_generic - Associate a VMDq pool index with a rx address 29928c2ecf20Sopenharmony_ci * @hw: pointer to hardware struct 29938c2ecf20Sopenharmony_ci * @rar: receive address register index to associate with a VMDq index 29948c2ecf20Sopenharmony_ci * @vmdq: VMDq pool index 29958c2ecf20Sopenharmony_ci **/ 29968c2ecf20Sopenharmony_cis32 ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) 29978c2ecf20Sopenharmony_ci{ 29988c2ecf20Sopenharmony_ci u32 mpsar; 29998c2ecf20Sopenharmony_ci u32 rar_entries = hw->mac.num_rar_entries; 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci /* Make sure we are using a valid rar index range */ 30028c2ecf20Sopenharmony_ci if (rar >= rar_entries) { 30038c2ecf20Sopenharmony_ci hw_dbg(hw, "RAR index %d is out of range.\n", rar); 30048c2ecf20Sopenharmony_ci return -EINVAL; 30058c2ecf20Sopenharmony_ci } 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ci if (vmdq < 32) { 30088c2ecf20Sopenharmony_ci mpsar = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar)); 30098c2ecf20Sopenharmony_ci mpsar |= BIT(vmdq); 30108c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), mpsar); 30118c2ecf20Sopenharmony_ci } else { 30128c2ecf20Sopenharmony_ci mpsar = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar)); 30138c2ecf20Sopenharmony_ci mpsar |= BIT(vmdq - 32); 30148c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), mpsar); 30158c2ecf20Sopenharmony_ci } 30168c2ecf20Sopenharmony_ci return 0; 30178c2ecf20Sopenharmony_ci} 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci/** 30208c2ecf20Sopenharmony_ci * This function should only be involved in the IOV mode. 30218c2ecf20Sopenharmony_ci * In IOV mode, Default pool is next pool after the number of 30228c2ecf20Sopenharmony_ci * VFs advertized and not 0. 30238c2ecf20Sopenharmony_ci * MPSAR table needs to be updated for SAN_MAC RAR [hw->mac.san_mac_rar_index] 30248c2ecf20Sopenharmony_ci * 30258c2ecf20Sopenharmony_ci * ixgbe_set_vmdq_san_mac - Associate default VMDq pool index with a rx address 30268c2ecf20Sopenharmony_ci * @hw: pointer to hardware struct 30278c2ecf20Sopenharmony_ci * @vmdq: VMDq pool index 30288c2ecf20Sopenharmony_ci **/ 30298c2ecf20Sopenharmony_cis32 ixgbe_set_vmdq_san_mac_generic(struct ixgbe_hw *hw, u32 vmdq) 30308c2ecf20Sopenharmony_ci{ 30318c2ecf20Sopenharmony_ci u32 rar = hw->mac.san_mac_rar_index; 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci if (vmdq < 32) { 30348c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), BIT(vmdq)); 30358c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), 0); 30368c2ecf20Sopenharmony_ci } else { 30378c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), 0); 30388c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), BIT(vmdq - 32)); 30398c2ecf20Sopenharmony_ci } 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci return 0; 30428c2ecf20Sopenharmony_ci} 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci/** 30458c2ecf20Sopenharmony_ci * ixgbe_init_uta_tables_generic - Initialize the Unicast Table Array 30468c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 30478c2ecf20Sopenharmony_ci **/ 30488c2ecf20Sopenharmony_cis32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw) 30498c2ecf20Sopenharmony_ci{ 30508c2ecf20Sopenharmony_ci int i; 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci for (i = 0; i < 128; i++) 30538c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_UTA(i), 0); 30548c2ecf20Sopenharmony_ci 30558c2ecf20Sopenharmony_ci return 0; 30568c2ecf20Sopenharmony_ci} 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci/** 30598c2ecf20Sopenharmony_ci * ixgbe_find_vlvf_slot - find the vlanid or the first empty slot 30608c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 30618c2ecf20Sopenharmony_ci * @vlan: VLAN id to write to VLAN filter 30628c2ecf20Sopenharmony_ci * @vlvf_bypass: true to find vlanid only, false returns first empty slot if 30638c2ecf20Sopenharmony_ci * vlanid not found 30648c2ecf20Sopenharmony_ci * 30658c2ecf20Sopenharmony_ci * return the VLVF index where this VLAN id should be placed 30668c2ecf20Sopenharmony_ci * 30678c2ecf20Sopenharmony_ci **/ 30688c2ecf20Sopenharmony_cistatic s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan, bool vlvf_bypass) 30698c2ecf20Sopenharmony_ci{ 30708c2ecf20Sopenharmony_ci s32 regindex, first_empty_slot; 30718c2ecf20Sopenharmony_ci u32 bits; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci /* short cut the special case */ 30748c2ecf20Sopenharmony_ci if (vlan == 0) 30758c2ecf20Sopenharmony_ci return 0; 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci /* if vlvf_bypass is set we don't want to use an empty slot, we 30788c2ecf20Sopenharmony_ci * will simply bypass the VLVF if there are no entries present in the 30798c2ecf20Sopenharmony_ci * VLVF that contain our VLAN 30808c2ecf20Sopenharmony_ci */ 30818c2ecf20Sopenharmony_ci first_empty_slot = vlvf_bypass ? -ENOSPC : 0; 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci /* add VLAN enable bit for comparison */ 30848c2ecf20Sopenharmony_ci vlan |= IXGBE_VLVF_VIEN; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci /* Search for the vlan id in the VLVF entries. Save off the first empty 30878c2ecf20Sopenharmony_ci * slot found along the way. 30888c2ecf20Sopenharmony_ci * 30898c2ecf20Sopenharmony_ci * pre-decrement loop covering (IXGBE_VLVF_ENTRIES - 1) .. 1 30908c2ecf20Sopenharmony_ci */ 30918c2ecf20Sopenharmony_ci for (regindex = IXGBE_VLVF_ENTRIES; --regindex;) { 30928c2ecf20Sopenharmony_ci bits = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex)); 30938c2ecf20Sopenharmony_ci if (bits == vlan) 30948c2ecf20Sopenharmony_ci return regindex; 30958c2ecf20Sopenharmony_ci if (!first_empty_slot && !bits) 30968c2ecf20Sopenharmony_ci first_empty_slot = regindex; 30978c2ecf20Sopenharmony_ci } 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci /* If we are here then we didn't find the VLAN. Return first empty 31008c2ecf20Sopenharmony_ci * slot we found during our search, else error. 31018c2ecf20Sopenharmony_ci */ 31028c2ecf20Sopenharmony_ci if (!first_empty_slot) 31038c2ecf20Sopenharmony_ci hw_dbg(hw, "No space in VLVF.\n"); 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci return first_empty_slot ? : -ENOSPC; 31068c2ecf20Sopenharmony_ci} 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci/** 31098c2ecf20Sopenharmony_ci * ixgbe_set_vfta_generic - Set VLAN filter table 31108c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 31118c2ecf20Sopenharmony_ci * @vlan: VLAN id to write to VLAN filter 31128c2ecf20Sopenharmony_ci * @vind: VMDq output index that maps queue to VLAN id in VFVFB 31138c2ecf20Sopenharmony_ci * @vlan_on: boolean flag to turn on/off VLAN in VFVF 31148c2ecf20Sopenharmony_ci * @vlvf_bypass: boolean flag indicating updating default pool is okay 31158c2ecf20Sopenharmony_ci * 31168c2ecf20Sopenharmony_ci * Turn on/off specified VLAN in the VLAN filter table. 31178c2ecf20Sopenharmony_ci **/ 31188c2ecf20Sopenharmony_cis32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, 31198c2ecf20Sopenharmony_ci bool vlan_on, bool vlvf_bypass) 31208c2ecf20Sopenharmony_ci{ 31218c2ecf20Sopenharmony_ci u32 regidx, vfta_delta, vfta, bits; 31228c2ecf20Sopenharmony_ci s32 vlvf_index; 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci if ((vlan > 4095) || (vind > 63)) 31258c2ecf20Sopenharmony_ci return -EINVAL; 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci /* 31288c2ecf20Sopenharmony_ci * this is a 2 part operation - first the VFTA, then the 31298c2ecf20Sopenharmony_ci * VLVF and VLVFB if VT Mode is set 31308c2ecf20Sopenharmony_ci * We don't write the VFTA until we know the VLVF part succeeded. 31318c2ecf20Sopenharmony_ci */ 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci /* Part 1 31348c2ecf20Sopenharmony_ci * The VFTA is a bitstring made up of 128 32-bit registers 31358c2ecf20Sopenharmony_ci * that enable the particular VLAN id, much like the MTA: 31368c2ecf20Sopenharmony_ci * bits[11-5]: which register 31378c2ecf20Sopenharmony_ci * bits[4-0]: which bit in the register 31388c2ecf20Sopenharmony_ci */ 31398c2ecf20Sopenharmony_ci regidx = vlan / 32; 31408c2ecf20Sopenharmony_ci vfta_delta = BIT(vlan % 32); 31418c2ecf20Sopenharmony_ci vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(regidx)); 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_ci /* vfta_delta represents the difference between the current value 31448c2ecf20Sopenharmony_ci * of vfta and the value we want in the register. Since the diff 31458c2ecf20Sopenharmony_ci * is an XOR mask we can just update vfta using an XOR. 31468c2ecf20Sopenharmony_ci */ 31478c2ecf20Sopenharmony_ci vfta_delta &= vlan_on ? ~vfta : vfta; 31488c2ecf20Sopenharmony_ci vfta ^= vfta_delta; 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci /* Part 2 31518c2ecf20Sopenharmony_ci * If VT Mode is set 31528c2ecf20Sopenharmony_ci * Either vlan_on 31538c2ecf20Sopenharmony_ci * make sure the vlan is in VLVF 31548c2ecf20Sopenharmony_ci * set the vind bit in the matching VLVFB 31558c2ecf20Sopenharmony_ci * Or !vlan_on 31568c2ecf20Sopenharmony_ci * clear the pool bit and possibly the vind 31578c2ecf20Sopenharmony_ci */ 31588c2ecf20Sopenharmony_ci if (!(IXGBE_READ_REG(hw, IXGBE_VT_CTL) & IXGBE_VT_CTL_VT_ENABLE)) 31598c2ecf20Sopenharmony_ci goto vfta_update; 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci vlvf_index = ixgbe_find_vlvf_slot(hw, vlan, vlvf_bypass); 31628c2ecf20Sopenharmony_ci if (vlvf_index < 0) { 31638c2ecf20Sopenharmony_ci if (vlvf_bypass) 31648c2ecf20Sopenharmony_ci goto vfta_update; 31658c2ecf20Sopenharmony_ci return vlvf_index; 31668c2ecf20Sopenharmony_ci } 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci bits = IXGBE_READ_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32)); 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci /* set the pool bit */ 31718c2ecf20Sopenharmony_ci bits |= BIT(vind % 32); 31728c2ecf20Sopenharmony_ci if (vlan_on) 31738c2ecf20Sopenharmony_ci goto vlvf_update; 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci /* clear the pool bit */ 31768c2ecf20Sopenharmony_ci bits ^= BIT(vind % 32); 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci if (!bits && 31798c2ecf20Sopenharmony_ci !IXGBE_READ_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + 1 - vind / 32))) { 31808c2ecf20Sopenharmony_ci /* Clear VFTA first, then disable VLVF. Otherwise 31818c2ecf20Sopenharmony_ci * we run the risk of stray packets leaking into 31828c2ecf20Sopenharmony_ci * the PF via the default pool 31838c2ecf20Sopenharmony_ci */ 31848c2ecf20Sopenharmony_ci if (vfta_delta) 31858c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VFTA(regidx), vfta); 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci /* disable VLVF and clear remaining bit from pool */ 31888c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0); 31898c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32), 0); 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci return 0; 31928c2ecf20Sopenharmony_ci } 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci /* If there are still bits set in the VLVFB registers 31958c2ecf20Sopenharmony_ci * for the VLAN ID indicated we need to see if the 31968c2ecf20Sopenharmony_ci * caller is requesting that we clear the VFTA entry bit. 31978c2ecf20Sopenharmony_ci * If the caller has requested that we clear the VFTA 31988c2ecf20Sopenharmony_ci * entry bit but there are still pools/VFs using this VLAN 31998c2ecf20Sopenharmony_ci * ID entry then ignore the request. We're not worried 32008c2ecf20Sopenharmony_ci * about the case where we're turning the VFTA VLAN ID 32018c2ecf20Sopenharmony_ci * entry bit on, only when requested to turn it off as 32028c2ecf20Sopenharmony_ci * there may be multiple pools and/or VFs using the 32038c2ecf20Sopenharmony_ci * VLAN ID entry. In that case we cannot clear the 32048c2ecf20Sopenharmony_ci * VFTA bit until all pools/VFs using that VLAN ID have also 32058c2ecf20Sopenharmony_ci * been cleared. This will be indicated by "bits" being 32068c2ecf20Sopenharmony_ci * zero. 32078c2ecf20Sopenharmony_ci */ 32088c2ecf20Sopenharmony_ci vfta_delta = 0; 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_civlvf_update: 32118c2ecf20Sopenharmony_ci /* record pool change and enable VLAN ID if not already enabled */ 32128c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32), bits); 32138c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), IXGBE_VLVF_VIEN | vlan); 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_civfta_update: 32168c2ecf20Sopenharmony_ci /* Update VFTA now that we are ready for traffic */ 32178c2ecf20Sopenharmony_ci if (vfta_delta) 32188c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VFTA(regidx), vfta); 32198c2ecf20Sopenharmony_ci 32208c2ecf20Sopenharmony_ci return 0; 32218c2ecf20Sopenharmony_ci} 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci/** 32248c2ecf20Sopenharmony_ci * ixgbe_clear_vfta_generic - Clear VLAN filter table 32258c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 32268c2ecf20Sopenharmony_ci * 32278c2ecf20Sopenharmony_ci * Clears the VLAN filer table, and the VMDq index associated with the filter 32288c2ecf20Sopenharmony_ci **/ 32298c2ecf20Sopenharmony_cis32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw) 32308c2ecf20Sopenharmony_ci{ 32318c2ecf20Sopenharmony_ci u32 offset; 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci for (offset = 0; offset < hw->mac.vft_size; offset++) 32348c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0); 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci for (offset = 0; offset < IXGBE_VLVF_ENTRIES; offset++) { 32378c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VLVF(offset), 0); 32388c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2), 0); 32398c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2 + 1), 0); 32408c2ecf20Sopenharmony_ci } 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci return 0; 32438c2ecf20Sopenharmony_ci} 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci/** 32468c2ecf20Sopenharmony_ci * ixgbe_need_crosstalk_fix - Determine if we need to do cross talk fix 32478c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 32488c2ecf20Sopenharmony_ci * 32498c2ecf20Sopenharmony_ci * Contains the logic to identify if we need to verify link for the 32508c2ecf20Sopenharmony_ci * crosstalk fix 32518c2ecf20Sopenharmony_ci **/ 32528c2ecf20Sopenharmony_cistatic bool ixgbe_need_crosstalk_fix(struct ixgbe_hw *hw) 32538c2ecf20Sopenharmony_ci{ 32548c2ecf20Sopenharmony_ci /* Does FW say we need the fix */ 32558c2ecf20Sopenharmony_ci if (!hw->need_crosstalk_fix) 32568c2ecf20Sopenharmony_ci return false; 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci /* Only consider SFP+ PHYs i.e. media type fiber */ 32598c2ecf20Sopenharmony_ci switch (hw->mac.ops.get_media_type(hw)) { 32608c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber: 32618c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber_qsfp: 32628c2ecf20Sopenharmony_ci break; 32638c2ecf20Sopenharmony_ci default: 32648c2ecf20Sopenharmony_ci return false; 32658c2ecf20Sopenharmony_ci } 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci return true; 32688c2ecf20Sopenharmony_ci} 32698c2ecf20Sopenharmony_ci 32708c2ecf20Sopenharmony_ci/** 32718c2ecf20Sopenharmony_ci * ixgbe_check_mac_link_generic - Determine link and speed status 32728c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 32738c2ecf20Sopenharmony_ci * @speed: pointer to link speed 32748c2ecf20Sopenharmony_ci * @link_up: true when link is up 32758c2ecf20Sopenharmony_ci * @link_up_wait_to_complete: bool used to wait for link up or not 32768c2ecf20Sopenharmony_ci * 32778c2ecf20Sopenharmony_ci * Reads the links register to determine if link is up and the current speed 32788c2ecf20Sopenharmony_ci **/ 32798c2ecf20Sopenharmony_cis32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, 32808c2ecf20Sopenharmony_ci bool *link_up, bool link_up_wait_to_complete) 32818c2ecf20Sopenharmony_ci{ 32828c2ecf20Sopenharmony_ci u32 links_reg, links_orig; 32838c2ecf20Sopenharmony_ci u32 i; 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_ci /* If Crosstalk fix enabled do the sanity check of making sure 32868c2ecf20Sopenharmony_ci * the SFP+ cage is full. 32878c2ecf20Sopenharmony_ci */ 32888c2ecf20Sopenharmony_ci if (ixgbe_need_crosstalk_fix(hw)) { 32898c2ecf20Sopenharmony_ci u32 sfp_cage_full; 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci switch (hw->mac.type) { 32928c2ecf20Sopenharmony_ci case ixgbe_mac_82599EB: 32938c2ecf20Sopenharmony_ci sfp_cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) & 32948c2ecf20Sopenharmony_ci IXGBE_ESDP_SDP2; 32958c2ecf20Sopenharmony_ci break; 32968c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 32978c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 32988c2ecf20Sopenharmony_ci sfp_cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) & 32998c2ecf20Sopenharmony_ci IXGBE_ESDP_SDP0; 33008c2ecf20Sopenharmony_ci break; 33018c2ecf20Sopenharmony_ci default: 33028c2ecf20Sopenharmony_ci /* sanity check - No SFP+ devices here */ 33038c2ecf20Sopenharmony_ci sfp_cage_full = false; 33048c2ecf20Sopenharmony_ci break; 33058c2ecf20Sopenharmony_ci } 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci if (!sfp_cage_full) { 33088c2ecf20Sopenharmony_ci *link_up = false; 33098c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_UNKNOWN; 33108c2ecf20Sopenharmony_ci return 0; 33118c2ecf20Sopenharmony_ci } 33128c2ecf20Sopenharmony_ci } 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci /* clear the old state */ 33158c2ecf20Sopenharmony_ci links_orig = IXGBE_READ_REG(hw, IXGBE_LINKS); 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci if (links_orig != links_reg) { 33208c2ecf20Sopenharmony_ci hw_dbg(hw, "LINKS changed from %08X to %08X\n", 33218c2ecf20Sopenharmony_ci links_orig, links_reg); 33228c2ecf20Sopenharmony_ci } 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ci if (link_up_wait_to_complete) { 33258c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { 33268c2ecf20Sopenharmony_ci if (links_reg & IXGBE_LINKS_UP) { 33278c2ecf20Sopenharmony_ci *link_up = true; 33288c2ecf20Sopenharmony_ci break; 33298c2ecf20Sopenharmony_ci } else { 33308c2ecf20Sopenharmony_ci *link_up = false; 33318c2ecf20Sopenharmony_ci } 33328c2ecf20Sopenharmony_ci msleep(100); 33338c2ecf20Sopenharmony_ci links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); 33348c2ecf20Sopenharmony_ci } 33358c2ecf20Sopenharmony_ci } else { 33368c2ecf20Sopenharmony_ci if (links_reg & IXGBE_LINKS_UP) 33378c2ecf20Sopenharmony_ci *link_up = true; 33388c2ecf20Sopenharmony_ci else 33398c2ecf20Sopenharmony_ci *link_up = false; 33408c2ecf20Sopenharmony_ci } 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci switch (links_reg & IXGBE_LINKS_SPEED_82599) { 33438c2ecf20Sopenharmony_ci case IXGBE_LINKS_SPEED_10G_82599: 33448c2ecf20Sopenharmony_ci if ((hw->mac.type >= ixgbe_mac_X550) && 33458c2ecf20Sopenharmony_ci (links_reg & IXGBE_LINKS_SPEED_NON_STD)) 33468c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_2_5GB_FULL; 33478c2ecf20Sopenharmony_ci else 33488c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_10GB_FULL; 33498c2ecf20Sopenharmony_ci break; 33508c2ecf20Sopenharmony_ci case IXGBE_LINKS_SPEED_1G_82599: 33518c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_1GB_FULL; 33528c2ecf20Sopenharmony_ci break; 33538c2ecf20Sopenharmony_ci case IXGBE_LINKS_SPEED_100_82599: 33548c2ecf20Sopenharmony_ci if ((hw->mac.type >= ixgbe_mac_X550) && 33558c2ecf20Sopenharmony_ci (links_reg & IXGBE_LINKS_SPEED_NON_STD)) 33568c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_5GB_FULL; 33578c2ecf20Sopenharmony_ci else 33588c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_100_FULL; 33598c2ecf20Sopenharmony_ci break; 33608c2ecf20Sopenharmony_ci case IXGBE_LINKS_SPEED_10_X550EM_A: 33618c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_UNKNOWN; 33628c2ecf20Sopenharmony_ci if (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T || 33638c2ecf20Sopenharmony_ci hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L) { 33648c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_10_FULL; 33658c2ecf20Sopenharmony_ci } 33668c2ecf20Sopenharmony_ci break; 33678c2ecf20Sopenharmony_ci default: 33688c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_UNKNOWN; 33698c2ecf20Sopenharmony_ci } 33708c2ecf20Sopenharmony_ci 33718c2ecf20Sopenharmony_ci return 0; 33728c2ecf20Sopenharmony_ci} 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ci/** 33758c2ecf20Sopenharmony_ci * ixgbe_get_wwn_prefix_generic - Get alternative WWNN/WWPN prefix from 33768c2ecf20Sopenharmony_ci * the EEPROM 33778c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 33788c2ecf20Sopenharmony_ci * @wwnn_prefix: the alternative WWNN prefix 33798c2ecf20Sopenharmony_ci * @wwpn_prefix: the alternative WWPN prefix 33808c2ecf20Sopenharmony_ci * 33818c2ecf20Sopenharmony_ci * This function will read the EEPROM from the alternative SAN MAC address 33828c2ecf20Sopenharmony_ci * block to check the support for the alternative WWNN/WWPN prefix support. 33838c2ecf20Sopenharmony_ci **/ 33848c2ecf20Sopenharmony_cis32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, 33858c2ecf20Sopenharmony_ci u16 *wwpn_prefix) 33868c2ecf20Sopenharmony_ci{ 33878c2ecf20Sopenharmony_ci u16 offset, caps; 33888c2ecf20Sopenharmony_ci u16 alt_san_mac_blk_offset; 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci /* clear output first */ 33918c2ecf20Sopenharmony_ci *wwnn_prefix = 0xFFFF; 33928c2ecf20Sopenharmony_ci *wwpn_prefix = 0xFFFF; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci /* check if alternative SAN MAC is supported */ 33958c2ecf20Sopenharmony_ci offset = IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR; 33968c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, offset, &alt_san_mac_blk_offset)) 33978c2ecf20Sopenharmony_ci goto wwn_prefix_err; 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci if ((alt_san_mac_blk_offset == 0) || 34008c2ecf20Sopenharmony_ci (alt_san_mac_blk_offset == 0xFFFF)) 34018c2ecf20Sopenharmony_ci return 0; 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_ci /* check capability in alternative san mac address block */ 34048c2ecf20Sopenharmony_ci offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET; 34058c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, offset, &caps)) 34068c2ecf20Sopenharmony_ci goto wwn_prefix_err; 34078c2ecf20Sopenharmony_ci if (!(caps & IXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN)) 34088c2ecf20Sopenharmony_ci return 0; 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci /* get the corresponding prefix for WWNN/WWPN */ 34118c2ecf20Sopenharmony_ci offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWNN_OFFSET; 34128c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, offset, wwnn_prefix)) 34138c2ecf20Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", offset); 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_ci offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWPN_OFFSET; 34168c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, offset, wwpn_prefix)) 34178c2ecf20Sopenharmony_ci goto wwn_prefix_err; 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_ci return 0; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ciwwn_prefix_err: 34228c2ecf20Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", offset); 34238c2ecf20Sopenharmony_ci return 0; 34248c2ecf20Sopenharmony_ci} 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci/** 34278c2ecf20Sopenharmony_ci * ixgbe_set_mac_anti_spoofing - Enable/Disable MAC anti-spoofing 34288c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 34298c2ecf20Sopenharmony_ci * @enable: enable or disable switch for MAC anti-spoofing 34308c2ecf20Sopenharmony_ci * @vf: Virtual Function pool - VF Pool to set for MAC anti-spoofing 34318c2ecf20Sopenharmony_ci * 34328c2ecf20Sopenharmony_ci **/ 34338c2ecf20Sopenharmony_civoid ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf) 34348c2ecf20Sopenharmony_ci{ 34358c2ecf20Sopenharmony_ci int vf_target_reg = vf >> 3; 34368c2ecf20Sopenharmony_ci int vf_target_shift = vf % 8; 34378c2ecf20Sopenharmony_ci u32 pfvfspoof; 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) 34408c2ecf20Sopenharmony_ci return; 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg)); 34438c2ecf20Sopenharmony_ci if (enable) 34448c2ecf20Sopenharmony_ci pfvfspoof |= BIT(vf_target_shift); 34458c2ecf20Sopenharmony_ci else 34468c2ecf20Sopenharmony_ci pfvfspoof &= ~BIT(vf_target_shift); 34478c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); 34488c2ecf20Sopenharmony_ci} 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci/** 34518c2ecf20Sopenharmony_ci * ixgbe_set_vlan_anti_spoofing - Enable/Disable VLAN anti-spoofing 34528c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 34538c2ecf20Sopenharmony_ci * @enable: enable or disable switch for VLAN anti-spoofing 34548c2ecf20Sopenharmony_ci * @vf: Virtual Function pool - VF Pool to set for VLAN anti-spoofing 34558c2ecf20Sopenharmony_ci * 34568c2ecf20Sopenharmony_ci **/ 34578c2ecf20Sopenharmony_civoid ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf) 34588c2ecf20Sopenharmony_ci{ 34598c2ecf20Sopenharmony_ci int vf_target_reg = vf >> 3; 34608c2ecf20Sopenharmony_ci int vf_target_shift = vf % 8 + IXGBE_SPOOF_VLANAS_SHIFT; 34618c2ecf20Sopenharmony_ci u32 pfvfspoof; 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) 34648c2ecf20Sopenharmony_ci return; 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg)); 34678c2ecf20Sopenharmony_ci if (enable) 34688c2ecf20Sopenharmony_ci pfvfspoof |= BIT(vf_target_shift); 34698c2ecf20Sopenharmony_ci else 34708c2ecf20Sopenharmony_ci pfvfspoof &= ~BIT(vf_target_shift); 34718c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); 34728c2ecf20Sopenharmony_ci} 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci/** 34758c2ecf20Sopenharmony_ci * ixgbe_get_device_caps_generic - Get additional device capabilities 34768c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 34778c2ecf20Sopenharmony_ci * @device_caps: the EEPROM word with the extra device capabilities 34788c2ecf20Sopenharmony_ci * 34798c2ecf20Sopenharmony_ci * This function will read the EEPROM location for the device capabilities, 34808c2ecf20Sopenharmony_ci * and return the word through device_caps. 34818c2ecf20Sopenharmony_ci **/ 34828c2ecf20Sopenharmony_cis32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps) 34838c2ecf20Sopenharmony_ci{ 34848c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci return 0; 34878c2ecf20Sopenharmony_ci} 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_ci/** 34908c2ecf20Sopenharmony_ci * ixgbe_set_rxpba_generic - Initialize RX packet buffer 34918c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 34928c2ecf20Sopenharmony_ci * @num_pb: number of packet buffers to allocate 34938c2ecf20Sopenharmony_ci * @headroom: reserve n KB of headroom 34948c2ecf20Sopenharmony_ci * @strategy: packet buffer allocation strategy 34958c2ecf20Sopenharmony_ci **/ 34968c2ecf20Sopenharmony_civoid ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, 34978c2ecf20Sopenharmony_ci int num_pb, 34988c2ecf20Sopenharmony_ci u32 headroom, 34998c2ecf20Sopenharmony_ci int strategy) 35008c2ecf20Sopenharmony_ci{ 35018c2ecf20Sopenharmony_ci u32 pbsize = hw->mac.rx_pb_size; 35028c2ecf20Sopenharmony_ci int i = 0; 35038c2ecf20Sopenharmony_ci u32 rxpktsize, txpktsize, txpbthresh; 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci /* Reserve headroom */ 35068c2ecf20Sopenharmony_ci pbsize -= headroom; 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci if (!num_pb) 35098c2ecf20Sopenharmony_ci num_pb = 1; 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_ci /* Divide remaining packet buffer space amongst the number 35128c2ecf20Sopenharmony_ci * of packet buffers requested using supplied strategy. 35138c2ecf20Sopenharmony_ci */ 35148c2ecf20Sopenharmony_ci switch (strategy) { 35158c2ecf20Sopenharmony_ci case (PBA_STRATEGY_WEIGHTED): 35168c2ecf20Sopenharmony_ci /* pba_80_48 strategy weight first half of packet buffer with 35178c2ecf20Sopenharmony_ci * 5/8 of the packet buffer space. 35188c2ecf20Sopenharmony_ci */ 35198c2ecf20Sopenharmony_ci rxpktsize = ((pbsize * 5 * 2) / (num_pb * 8)); 35208c2ecf20Sopenharmony_ci pbsize -= rxpktsize * (num_pb / 2); 35218c2ecf20Sopenharmony_ci rxpktsize <<= IXGBE_RXPBSIZE_SHIFT; 35228c2ecf20Sopenharmony_ci for (; i < (num_pb / 2); i++) 35238c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); 35248c2ecf20Sopenharmony_ci fallthrough; /* configure remaining packet buffers */ 35258c2ecf20Sopenharmony_ci case (PBA_STRATEGY_EQUAL): 35268c2ecf20Sopenharmony_ci /* Divide the remaining Rx packet buffer evenly among the TCs */ 35278c2ecf20Sopenharmony_ci rxpktsize = (pbsize / (num_pb - i)) << IXGBE_RXPBSIZE_SHIFT; 35288c2ecf20Sopenharmony_ci for (; i < num_pb; i++) 35298c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); 35308c2ecf20Sopenharmony_ci break; 35318c2ecf20Sopenharmony_ci default: 35328c2ecf20Sopenharmony_ci break; 35338c2ecf20Sopenharmony_ci } 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci /* 35368c2ecf20Sopenharmony_ci * Setup Tx packet buffer and threshold equally for all TCs 35378c2ecf20Sopenharmony_ci * TXPBTHRESH register is set in K so divide by 1024 and subtract 35388c2ecf20Sopenharmony_ci * 10 since the largest packet we support is just over 9K. 35398c2ecf20Sopenharmony_ci */ 35408c2ecf20Sopenharmony_ci txpktsize = IXGBE_TXPBSIZE_MAX / num_pb; 35418c2ecf20Sopenharmony_ci txpbthresh = (txpktsize / 1024) - IXGBE_TXPKT_SIZE_MAX; 35428c2ecf20Sopenharmony_ci for (i = 0; i < num_pb; i++) { 35438c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), txpktsize); 35448c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), txpbthresh); 35458c2ecf20Sopenharmony_ci } 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci /* Clear unused TCs, if any, to zero buffer size*/ 35488c2ecf20Sopenharmony_ci for (; i < IXGBE_MAX_PB; i++) { 35498c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); 35508c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), 0); 35518c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), 0); 35528c2ecf20Sopenharmony_ci } 35538c2ecf20Sopenharmony_ci} 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_ci/** 35568c2ecf20Sopenharmony_ci * ixgbe_calculate_checksum - Calculate checksum for buffer 35578c2ecf20Sopenharmony_ci * @buffer: pointer to EEPROM 35588c2ecf20Sopenharmony_ci * @length: size of EEPROM to calculate a checksum for 35598c2ecf20Sopenharmony_ci * 35608c2ecf20Sopenharmony_ci * Calculates the checksum for some buffer on a specified length. The 35618c2ecf20Sopenharmony_ci * checksum calculated is returned. 35628c2ecf20Sopenharmony_ci **/ 35638c2ecf20Sopenharmony_ciu8 ixgbe_calculate_checksum(u8 *buffer, u32 length) 35648c2ecf20Sopenharmony_ci{ 35658c2ecf20Sopenharmony_ci u32 i; 35668c2ecf20Sopenharmony_ci u8 sum = 0; 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ci if (!buffer) 35698c2ecf20Sopenharmony_ci return 0; 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) 35728c2ecf20Sopenharmony_ci sum += buffer[i]; 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci return (u8) (0 - sum); 35758c2ecf20Sopenharmony_ci} 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci/** 35788c2ecf20Sopenharmony_ci * ixgbe_hic_unlocked - Issue command to manageability block unlocked 35798c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 35808c2ecf20Sopenharmony_ci * @buffer: command to write and where the return status will be placed 35818c2ecf20Sopenharmony_ci * @length: length of buffer, must be multiple of 4 bytes 35828c2ecf20Sopenharmony_ci * @timeout: time in ms to wait for command completion 35838c2ecf20Sopenharmony_ci * 35848c2ecf20Sopenharmony_ci * Communicates with the manageability block. On success return 0 35858c2ecf20Sopenharmony_ci * else returns semaphore error when encountering an error acquiring 35868c2ecf20Sopenharmony_ci * semaphore, -EINVAL when incorrect parameters passed or -EIO when 35878c2ecf20Sopenharmony_ci * command fails. 35888c2ecf20Sopenharmony_ci * 35898c2ecf20Sopenharmony_ci * This function assumes that the IXGBE_GSSR_SW_MNG_SM semaphore is held 35908c2ecf20Sopenharmony_ci * by the caller. 35918c2ecf20Sopenharmony_ci **/ 35928c2ecf20Sopenharmony_cis32 ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 length, 35938c2ecf20Sopenharmony_ci u32 timeout) 35948c2ecf20Sopenharmony_ci{ 35958c2ecf20Sopenharmony_ci u32 hicr, i, fwsts; 35968c2ecf20Sopenharmony_ci u16 dword_len; 35978c2ecf20Sopenharmony_ci 35988c2ecf20Sopenharmony_ci if (!length || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) { 35998c2ecf20Sopenharmony_ci hw_dbg(hw, "Buffer length failure buffersize-%d.\n", length); 36008c2ecf20Sopenharmony_ci return -EINVAL; 36018c2ecf20Sopenharmony_ci } 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci /* Set bit 9 of FWSTS clearing FW reset indication */ 36048c2ecf20Sopenharmony_ci fwsts = IXGBE_READ_REG(hw, IXGBE_FWSTS); 36058c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FWSTS, fwsts | IXGBE_FWSTS_FWRI); 36068c2ecf20Sopenharmony_ci 36078c2ecf20Sopenharmony_ci /* Check that the host interface is enabled. */ 36088c2ecf20Sopenharmony_ci hicr = IXGBE_READ_REG(hw, IXGBE_HICR); 36098c2ecf20Sopenharmony_ci if (!(hicr & IXGBE_HICR_EN)) { 36108c2ecf20Sopenharmony_ci hw_dbg(hw, "IXGBE_HOST_EN bit disabled.\n"); 36118c2ecf20Sopenharmony_ci return -EIO; 36128c2ecf20Sopenharmony_ci } 36138c2ecf20Sopenharmony_ci 36148c2ecf20Sopenharmony_ci /* Calculate length in DWORDs. We must be DWORD aligned */ 36158c2ecf20Sopenharmony_ci if (length % sizeof(u32)) { 36168c2ecf20Sopenharmony_ci hw_dbg(hw, "Buffer length failure, not aligned to dword"); 36178c2ecf20Sopenharmony_ci return -EINVAL; 36188c2ecf20Sopenharmony_ci } 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci dword_len = length >> 2; 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci /* The device driver writes the relevant command block 36238c2ecf20Sopenharmony_ci * into the ram area. 36248c2ecf20Sopenharmony_ci */ 36258c2ecf20Sopenharmony_ci for (i = 0; i < dword_len; i++) 36268c2ecf20Sopenharmony_ci IXGBE_WRITE_REG_ARRAY(hw, IXGBE_FLEX_MNG, 36278c2ecf20Sopenharmony_ci i, (__force u32)cpu_to_le32(buffer[i])); 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_ci /* Setting this bit tells the ARC that a new command is pending. */ 36308c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_HICR, hicr | IXGBE_HICR_C); 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 36338c2ecf20Sopenharmony_ci hicr = IXGBE_READ_REG(hw, IXGBE_HICR); 36348c2ecf20Sopenharmony_ci if (!(hicr & IXGBE_HICR_C)) 36358c2ecf20Sopenharmony_ci break; 36368c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci /* Check command successful completion. */ 36408c2ecf20Sopenharmony_ci if ((timeout && i == timeout) || 36418c2ecf20Sopenharmony_ci !(IXGBE_READ_REG(hw, IXGBE_HICR) & IXGBE_HICR_SV)) 36428c2ecf20Sopenharmony_ci return -EIO; 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci return 0; 36458c2ecf20Sopenharmony_ci} 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci/** 36488c2ecf20Sopenharmony_ci * ixgbe_host_interface_command - Issue command to manageability block 36498c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 36508c2ecf20Sopenharmony_ci * @buffer: contains the command to write and where the return status will 36518c2ecf20Sopenharmony_ci * be placed 36528c2ecf20Sopenharmony_ci * @length: length of buffer, must be multiple of 4 bytes 36538c2ecf20Sopenharmony_ci * @timeout: time in ms to wait for command completion 36548c2ecf20Sopenharmony_ci * @return_data: read and return data from the buffer (true) or not (false) 36558c2ecf20Sopenharmony_ci * Needed because FW structures are big endian and decoding of 36568c2ecf20Sopenharmony_ci * these fields can be 8 bit or 16 bit based on command. Decoding 36578c2ecf20Sopenharmony_ci * is not easily understood without making a table of commands. 36588c2ecf20Sopenharmony_ci * So we will leave this up to the caller to read back the data 36598c2ecf20Sopenharmony_ci * in these cases. 36608c2ecf20Sopenharmony_ci * 36618c2ecf20Sopenharmony_ci * Communicates with the manageability block. On success return 0 36628c2ecf20Sopenharmony_ci * else return -EIO or -EINVAL. 36638c2ecf20Sopenharmony_ci **/ 36648c2ecf20Sopenharmony_cis32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer, 36658c2ecf20Sopenharmony_ci u32 length, u32 timeout, 36668c2ecf20Sopenharmony_ci bool return_data) 36678c2ecf20Sopenharmony_ci{ 36688c2ecf20Sopenharmony_ci u32 hdr_size = sizeof(struct ixgbe_hic_hdr); 36698c2ecf20Sopenharmony_ci union { 36708c2ecf20Sopenharmony_ci struct ixgbe_hic_hdr hdr; 36718c2ecf20Sopenharmony_ci u32 u32arr[1]; 36728c2ecf20Sopenharmony_ci } *bp = buffer; 36738c2ecf20Sopenharmony_ci u16 buf_len, dword_len; 36748c2ecf20Sopenharmony_ci s32 status; 36758c2ecf20Sopenharmony_ci u32 bi; 36768c2ecf20Sopenharmony_ci 36778c2ecf20Sopenharmony_ci if (!length || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) { 36788c2ecf20Sopenharmony_ci hw_dbg(hw, "Buffer length failure buffersize-%d.\n", length); 36798c2ecf20Sopenharmony_ci return -EINVAL; 36808c2ecf20Sopenharmony_ci } 36818c2ecf20Sopenharmony_ci /* Take management host interface semaphore */ 36828c2ecf20Sopenharmony_ci status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM); 36838c2ecf20Sopenharmony_ci if (status) 36848c2ecf20Sopenharmony_ci return status; 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ci status = ixgbe_hic_unlocked(hw, buffer, length, timeout); 36878c2ecf20Sopenharmony_ci if (status) 36888c2ecf20Sopenharmony_ci goto rel_out; 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci if (!return_data) 36918c2ecf20Sopenharmony_ci goto rel_out; 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci /* Calculate length in DWORDs */ 36948c2ecf20Sopenharmony_ci dword_len = hdr_size >> 2; 36958c2ecf20Sopenharmony_ci 36968c2ecf20Sopenharmony_ci /* first pull in the header so we know the buffer length */ 36978c2ecf20Sopenharmony_ci for (bi = 0; bi < dword_len; bi++) { 36988c2ecf20Sopenharmony_ci bp->u32arr[bi] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, bi); 36998c2ecf20Sopenharmony_ci le32_to_cpus(&bp->u32arr[bi]); 37008c2ecf20Sopenharmony_ci } 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci /* If there is any thing in data position pull it in */ 37038c2ecf20Sopenharmony_ci buf_len = bp->hdr.buf_len; 37048c2ecf20Sopenharmony_ci if (!buf_len) 37058c2ecf20Sopenharmony_ci goto rel_out; 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_ci if (length < round_up(buf_len, 4) + hdr_size) { 37088c2ecf20Sopenharmony_ci hw_dbg(hw, "Buffer not large enough for reply message.\n"); 37098c2ecf20Sopenharmony_ci status = -EIO; 37108c2ecf20Sopenharmony_ci goto rel_out; 37118c2ecf20Sopenharmony_ci } 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci /* Calculate length in DWORDs, add 3 for odd lengths */ 37148c2ecf20Sopenharmony_ci dword_len = (buf_len + 3) >> 2; 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ci /* Pull in the rest of the buffer (bi is where we left off) */ 37178c2ecf20Sopenharmony_ci for (; bi <= dword_len; bi++) { 37188c2ecf20Sopenharmony_ci bp->u32arr[bi] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, bi); 37198c2ecf20Sopenharmony_ci le32_to_cpus(&bp->u32arr[bi]); 37208c2ecf20Sopenharmony_ci } 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_cirel_out: 37238c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM); 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci return status; 37268c2ecf20Sopenharmony_ci} 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_ci/** 37298c2ecf20Sopenharmony_ci * ixgbe_set_fw_drv_ver_generic - Sends driver version to firmware 37308c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 37318c2ecf20Sopenharmony_ci * @maj: driver version major number 37328c2ecf20Sopenharmony_ci * @min: driver version minor number 37338c2ecf20Sopenharmony_ci * @build: driver version build number 37348c2ecf20Sopenharmony_ci * @sub: driver version sub build number 37358c2ecf20Sopenharmony_ci * @len: length of driver_ver string 37368c2ecf20Sopenharmony_ci * @driver_ver: driver string 37378c2ecf20Sopenharmony_ci * 37388c2ecf20Sopenharmony_ci * Sends driver version number to firmware through the manageability 37398c2ecf20Sopenharmony_ci * block. On success return 0 37408c2ecf20Sopenharmony_ci * else returns -EBUSY when encountering an error acquiring 37418c2ecf20Sopenharmony_ci * semaphore or -EIO when command fails. 37428c2ecf20Sopenharmony_ci **/ 37438c2ecf20Sopenharmony_cis32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, 37448c2ecf20Sopenharmony_ci u8 build, u8 sub, __always_unused u16 len, 37458c2ecf20Sopenharmony_ci __always_unused const char *driver_ver) 37468c2ecf20Sopenharmony_ci{ 37478c2ecf20Sopenharmony_ci struct ixgbe_hic_drv_info fw_cmd; 37488c2ecf20Sopenharmony_ci int i; 37498c2ecf20Sopenharmony_ci s32 ret_val; 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; 37528c2ecf20Sopenharmony_ci fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN; 37538c2ecf20Sopenharmony_ci fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; 37548c2ecf20Sopenharmony_ci fw_cmd.port_num = hw->bus.func; 37558c2ecf20Sopenharmony_ci fw_cmd.ver_maj = maj; 37568c2ecf20Sopenharmony_ci fw_cmd.ver_min = min; 37578c2ecf20Sopenharmony_ci fw_cmd.ver_build = build; 37588c2ecf20Sopenharmony_ci fw_cmd.ver_sub = sub; 37598c2ecf20Sopenharmony_ci fw_cmd.hdr.checksum = 0; 37608c2ecf20Sopenharmony_ci fw_cmd.pad = 0; 37618c2ecf20Sopenharmony_ci fw_cmd.pad2 = 0; 37628c2ecf20Sopenharmony_ci fw_cmd.hdr.checksum = ixgbe_calculate_checksum((u8 *)&fw_cmd, 37638c2ecf20Sopenharmony_ci (FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len)); 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_ci for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { 37668c2ecf20Sopenharmony_ci ret_val = ixgbe_host_interface_command(hw, &fw_cmd, 37678c2ecf20Sopenharmony_ci sizeof(fw_cmd), 37688c2ecf20Sopenharmony_ci IXGBE_HI_COMMAND_TIMEOUT, 37698c2ecf20Sopenharmony_ci true); 37708c2ecf20Sopenharmony_ci if (ret_val != 0) 37718c2ecf20Sopenharmony_ci continue; 37728c2ecf20Sopenharmony_ci 37738c2ecf20Sopenharmony_ci if (fw_cmd.hdr.cmd_or_resp.ret_status == 37748c2ecf20Sopenharmony_ci FW_CEM_RESP_STATUS_SUCCESS) 37758c2ecf20Sopenharmony_ci ret_val = 0; 37768c2ecf20Sopenharmony_ci else 37778c2ecf20Sopenharmony_ci ret_val = -EIO; 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci break; 37808c2ecf20Sopenharmony_ci } 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci return ret_val; 37838c2ecf20Sopenharmony_ci} 37848c2ecf20Sopenharmony_ci 37858c2ecf20Sopenharmony_ci/** 37868c2ecf20Sopenharmony_ci * ixgbe_clear_tx_pending - Clear pending TX work from the PCIe fifo 37878c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 37888c2ecf20Sopenharmony_ci * 37898c2ecf20Sopenharmony_ci * The 82599 and x540 MACs can experience issues if TX work is still pending 37908c2ecf20Sopenharmony_ci * when a reset occurs. This function prevents this by flushing the PCIe 37918c2ecf20Sopenharmony_ci * buffers on the system. 37928c2ecf20Sopenharmony_ci **/ 37938c2ecf20Sopenharmony_civoid ixgbe_clear_tx_pending(struct ixgbe_hw *hw) 37948c2ecf20Sopenharmony_ci{ 37958c2ecf20Sopenharmony_ci u32 gcr_ext, hlreg0, i, poll; 37968c2ecf20Sopenharmony_ci u16 value; 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci /* 37998c2ecf20Sopenharmony_ci * If double reset is not requested then all transactions should 38008c2ecf20Sopenharmony_ci * already be clear and as such there is no work to do 38018c2ecf20Sopenharmony_ci */ 38028c2ecf20Sopenharmony_ci if (!(hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED)) 38038c2ecf20Sopenharmony_ci return; 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci /* 38068c2ecf20Sopenharmony_ci * Set loopback enable to prevent any transmits from being sent 38078c2ecf20Sopenharmony_ci * should the link come up. This assumes that the RXCTRL.RXEN bit 38088c2ecf20Sopenharmony_ci * has already been cleared. 38098c2ecf20Sopenharmony_ci */ 38108c2ecf20Sopenharmony_ci hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); 38118c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0 | IXGBE_HLREG0_LPBK); 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci /* wait for a last completion before clearing buffers */ 38148c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 38158c2ecf20Sopenharmony_ci usleep_range(3000, 6000); 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_ci /* Before proceeding, make sure that the PCIe block does not have 38188c2ecf20Sopenharmony_ci * transactions pending. 38198c2ecf20Sopenharmony_ci */ 38208c2ecf20Sopenharmony_ci poll = ixgbe_pcie_timeout_poll(hw); 38218c2ecf20Sopenharmony_ci for (i = 0; i < poll; i++) { 38228c2ecf20Sopenharmony_ci usleep_range(100, 200); 38238c2ecf20Sopenharmony_ci value = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_STATUS); 38248c2ecf20Sopenharmony_ci if (ixgbe_removed(hw->hw_addr)) 38258c2ecf20Sopenharmony_ci break; 38268c2ecf20Sopenharmony_ci if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING)) 38278c2ecf20Sopenharmony_ci break; 38288c2ecf20Sopenharmony_ci } 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_ci /* initiate cleaning flow for buffers in the PCIe transaction layer */ 38318c2ecf20Sopenharmony_ci gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); 38328c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, 38338c2ecf20Sopenharmony_ci gcr_ext | IXGBE_GCR_EXT_BUFFERS_CLEAR); 38348c2ecf20Sopenharmony_ci 38358c2ecf20Sopenharmony_ci /* Flush all writes and allow 20usec for all transactions to clear */ 38368c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 38378c2ecf20Sopenharmony_ci udelay(20); 38388c2ecf20Sopenharmony_ci 38398c2ecf20Sopenharmony_ci /* restore previous register values */ 38408c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext); 38418c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); 38428c2ecf20Sopenharmony_ci} 38438c2ecf20Sopenharmony_ci 38448c2ecf20Sopenharmony_cistatic const u8 ixgbe_emc_temp_data[4] = { 38458c2ecf20Sopenharmony_ci IXGBE_EMC_INTERNAL_DATA, 38468c2ecf20Sopenharmony_ci IXGBE_EMC_DIODE1_DATA, 38478c2ecf20Sopenharmony_ci IXGBE_EMC_DIODE2_DATA, 38488c2ecf20Sopenharmony_ci IXGBE_EMC_DIODE3_DATA 38498c2ecf20Sopenharmony_ci}; 38508c2ecf20Sopenharmony_cistatic const u8 ixgbe_emc_therm_limit[4] = { 38518c2ecf20Sopenharmony_ci IXGBE_EMC_INTERNAL_THERM_LIMIT, 38528c2ecf20Sopenharmony_ci IXGBE_EMC_DIODE1_THERM_LIMIT, 38538c2ecf20Sopenharmony_ci IXGBE_EMC_DIODE2_THERM_LIMIT, 38548c2ecf20Sopenharmony_ci IXGBE_EMC_DIODE3_THERM_LIMIT 38558c2ecf20Sopenharmony_ci}; 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_ci/** 38588c2ecf20Sopenharmony_ci * ixgbe_get_ets_data - Extracts the ETS bit data 38598c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 38608c2ecf20Sopenharmony_ci * @ets_cfg: extected ETS data 38618c2ecf20Sopenharmony_ci * @ets_offset: offset of ETS data 38628c2ecf20Sopenharmony_ci * 38638c2ecf20Sopenharmony_ci * Returns error code. 38648c2ecf20Sopenharmony_ci **/ 38658c2ecf20Sopenharmony_cistatic s32 ixgbe_get_ets_data(struct ixgbe_hw *hw, u16 *ets_cfg, 38668c2ecf20Sopenharmony_ci u16 *ets_offset) 38678c2ecf20Sopenharmony_ci{ 38688c2ecf20Sopenharmony_ci s32 status; 38698c2ecf20Sopenharmony_ci 38708c2ecf20Sopenharmony_ci status = hw->eeprom.ops.read(hw, IXGBE_ETS_CFG, ets_offset); 38718c2ecf20Sopenharmony_ci if (status) 38728c2ecf20Sopenharmony_ci return status; 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_ci if ((*ets_offset == 0x0000) || (*ets_offset == 0xFFFF)) 38758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci status = hw->eeprom.ops.read(hw, *ets_offset, ets_cfg); 38788c2ecf20Sopenharmony_ci if (status) 38798c2ecf20Sopenharmony_ci return status; 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci if ((*ets_cfg & IXGBE_ETS_TYPE_MASK) != IXGBE_ETS_TYPE_EMC_SHIFTED) 38828c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci return 0; 38858c2ecf20Sopenharmony_ci} 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci/** 38888c2ecf20Sopenharmony_ci * ixgbe_get_thermal_sensor_data - Gathers thermal sensor data 38898c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 38908c2ecf20Sopenharmony_ci * 38918c2ecf20Sopenharmony_ci * Returns the thermal sensor data structure 38928c2ecf20Sopenharmony_ci **/ 38938c2ecf20Sopenharmony_cis32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) 38948c2ecf20Sopenharmony_ci{ 38958c2ecf20Sopenharmony_ci s32 status; 38968c2ecf20Sopenharmony_ci u16 ets_offset; 38978c2ecf20Sopenharmony_ci u16 ets_cfg; 38988c2ecf20Sopenharmony_ci u16 ets_sensor; 38998c2ecf20Sopenharmony_ci u8 num_sensors; 39008c2ecf20Sopenharmony_ci u8 i; 39018c2ecf20Sopenharmony_ci struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ci /* Only support thermal sensors attached to physical port 0 */ 39048c2ecf20Sopenharmony_ci if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) 39058c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset); 39088c2ecf20Sopenharmony_ci if (status) 39098c2ecf20Sopenharmony_ci return status; 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci num_sensors = (ets_cfg & IXGBE_ETS_NUM_SENSORS_MASK); 39128c2ecf20Sopenharmony_ci if (num_sensors > IXGBE_MAX_SENSORS) 39138c2ecf20Sopenharmony_ci num_sensors = IXGBE_MAX_SENSORS; 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci for (i = 0; i < num_sensors; i++) { 39168c2ecf20Sopenharmony_ci u8 sensor_index; 39178c2ecf20Sopenharmony_ci u8 sensor_location; 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci status = hw->eeprom.ops.read(hw, (ets_offset + 1 + i), 39208c2ecf20Sopenharmony_ci &ets_sensor); 39218c2ecf20Sopenharmony_ci if (status) 39228c2ecf20Sopenharmony_ci return status; 39238c2ecf20Sopenharmony_ci 39248c2ecf20Sopenharmony_ci sensor_index = ((ets_sensor & IXGBE_ETS_DATA_INDEX_MASK) >> 39258c2ecf20Sopenharmony_ci IXGBE_ETS_DATA_INDEX_SHIFT); 39268c2ecf20Sopenharmony_ci sensor_location = ((ets_sensor & IXGBE_ETS_DATA_LOC_MASK) >> 39278c2ecf20Sopenharmony_ci IXGBE_ETS_DATA_LOC_SHIFT); 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci if (sensor_location != 0) { 39308c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_byte(hw, 39318c2ecf20Sopenharmony_ci ixgbe_emc_temp_data[sensor_index], 39328c2ecf20Sopenharmony_ci IXGBE_I2C_THERMAL_SENSOR_ADDR, 39338c2ecf20Sopenharmony_ci &data->sensor[i].temp); 39348c2ecf20Sopenharmony_ci if (status) 39358c2ecf20Sopenharmony_ci return status; 39368c2ecf20Sopenharmony_ci } 39378c2ecf20Sopenharmony_ci } 39388c2ecf20Sopenharmony_ci 39398c2ecf20Sopenharmony_ci return 0; 39408c2ecf20Sopenharmony_ci} 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci/** 39438c2ecf20Sopenharmony_ci * ixgbe_init_thermal_sensor_thresh_generic - Inits thermal sensor thresholds 39448c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 39458c2ecf20Sopenharmony_ci * 39468c2ecf20Sopenharmony_ci * Inits the thermal sensor thresholds according to the NVM map 39478c2ecf20Sopenharmony_ci * and save off the threshold and location values into mac.thermal_sensor_data 39488c2ecf20Sopenharmony_ci **/ 39498c2ecf20Sopenharmony_cis32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw) 39508c2ecf20Sopenharmony_ci{ 39518c2ecf20Sopenharmony_ci s32 status; 39528c2ecf20Sopenharmony_ci u16 ets_offset; 39538c2ecf20Sopenharmony_ci u16 ets_cfg; 39548c2ecf20Sopenharmony_ci u16 ets_sensor; 39558c2ecf20Sopenharmony_ci u8 low_thresh_delta; 39568c2ecf20Sopenharmony_ci u8 num_sensors; 39578c2ecf20Sopenharmony_ci u8 therm_limit; 39588c2ecf20Sopenharmony_ci u8 i; 39598c2ecf20Sopenharmony_ci struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci memset(data, 0, sizeof(struct ixgbe_thermal_sensor_data)); 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci /* Only support thermal sensors attached to physical port 0 */ 39648c2ecf20Sopenharmony_ci if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) 39658c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 39668c2ecf20Sopenharmony_ci 39678c2ecf20Sopenharmony_ci status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset); 39688c2ecf20Sopenharmony_ci if (status) 39698c2ecf20Sopenharmony_ci return status; 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci low_thresh_delta = ((ets_cfg & IXGBE_ETS_LTHRES_DELTA_MASK) >> 39728c2ecf20Sopenharmony_ci IXGBE_ETS_LTHRES_DELTA_SHIFT); 39738c2ecf20Sopenharmony_ci num_sensors = (ets_cfg & IXGBE_ETS_NUM_SENSORS_MASK); 39748c2ecf20Sopenharmony_ci if (num_sensors > IXGBE_MAX_SENSORS) 39758c2ecf20Sopenharmony_ci num_sensors = IXGBE_MAX_SENSORS; 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci for (i = 0; i < num_sensors; i++) { 39788c2ecf20Sopenharmony_ci u8 sensor_index; 39798c2ecf20Sopenharmony_ci u8 sensor_location; 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, ets_offset + 1 + i, &ets_sensor)) { 39828c2ecf20Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", 39838c2ecf20Sopenharmony_ci ets_offset + 1 + i); 39848c2ecf20Sopenharmony_ci continue; 39858c2ecf20Sopenharmony_ci } 39868c2ecf20Sopenharmony_ci sensor_index = ((ets_sensor & IXGBE_ETS_DATA_INDEX_MASK) >> 39878c2ecf20Sopenharmony_ci IXGBE_ETS_DATA_INDEX_SHIFT); 39888c2ecf20Sopenharmony_ci sensor_location = ((ets_sensor & IXGBE_ETS_DATA_LOC_MASK) >> 39898c2ecf20Sopenharmony_ci IXGBE_ETS_DATA_LOC_SHIFT); 39908c2ecf20Sopenharmony_ci therm_limit = ets_sensor & IXGBE_ETS_DATA_HTHRESH_MASK; 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci hw->phy.ops.write_i2c_byte(hw, 39938c2ecf20Sopenharmony_ci ixgbe_emc_therm_limit[sensor_index], 39948c2ecf20Sopenharmony_ci IXGBE_I2C_THERMAL_SENSOR_ADDR, therm_limit); 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci if (sensor_location == 0) 39978c2ecf20Sopenharmony_ci continue; 39988c2ecf20Sopenharmony_ci 39998c2ecf20Sopenharmony_ci data->sensor[i].location = sensor_location; 40008c2ecf20Sopenharmony_ci data->sensor[i].caution_thresh = therm_limit; 40018c2ecf20Sopenharmony_ci data->sensor[i].max_op_thresh = therm_limit - low_thresh_delta; 40028c2ecf20Sopenharmony_ci } 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci return 0; 40058c2ecf20Sopenharmony_ci} 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_ci/** 40088c2ecf20Sopenharmony_ci * ixgbe_get_orom_version - Return option ROM from EEPROM 40098c2ecf20Sopenharmony_ci * 40108c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 40118c2ecf20Sopenharmony_ci * @nvm_ver: pointer to output structure 40128c2ecf20Sopenharmony_ci * 40138c2ecf20Sopenharmony_ci * if valid option ROM version, nvm_ver->or_valid set to true 40148c2ecf20Sopenharmony_ci * else nvm_ver->or_valid is false. 40158c2ecf20Sopenharmony_ci **/ 40168c2ecf20Sopenharmony_civoid ixgbe_get_orom_version(struct ixgbe_hw *hw, 40178c2ecf20Sopenharmony_ci struct ixgbe_nvm_version *nvm_ver) 40188c2ecf20Sopenharmony_ci{ 40198c2ecf20Sopenharmony_ci u16 offset, eeprom_cfg_blkh, eeprom_cfg_blkl; 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci nvm_ver->or_valid = false; 40228c2ecf20Sopenharmony_ci /* Option Rom may or may not be present. Start with pointer */ 40238c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, NVM_OROM_OFFSET, &offset); 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci /* make sure offset is valid */ 40268c2ecf20Sopenharmony_ci if (offset == 0x0 || offset == NVM_INVALID_PTR) 40278c2ecf20Sopenharmony_ci return; 40288c2ecf20Sopenharmony_ci 40298c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, offset + NVM_OROM_BLK_HI, &eeprom_cfg_blkh); 40308c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, offset + NVM_OROM_BLK_LOW, &eeprom_cfg_blkl); 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_ci /* option rom exists and is valid */ 40338c2ecf20Sopenharmony_ci if ((eeprom_cfg_blkl | eeprom_cfg_blkh) == 0x0 || 40348c2ecf20Sopenharmony_ci eeprom_cfg_blkl == NVM_VER_INVALID || 40358c2ecf20Sopenharmony_ci eeprom_cfg_blkh == NVM_VER_INVALID) 40368c2ecf20Sopenharmony_ci return; 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_ci nvm_ver->or_valid = true; 40398c2ecf20Sopenharmony_ci nvm_ver->or_major = eeprom_cfg_blkl >> NVM_OROM_SHIFT; 40408c2ecf20Sopenharmony_ci nvm_ver->or_build = (eeprom_cfg_blkl << NVM_OROM_SHIFT) | 40418c2ecf20Sopenharmony_ci (eeprom_cfg_blkh >> NVM_OROM_SHIFT); 40428c2ecf20Sopenharmony_ci nvm_ver->or_patch = eeprom_cfg_blkh & NVM_OROM_PATCH_MASK; 40438c2ecf20Sopenharmony_ci} 40448c2ecf20Sopenharmony_ci 40458c2ecf20Sopenharmony_ci/** 40468c2ecf20Sopenharmony_ci * ixgbe_get_oem_prod_version Etrack ID from EEPROM 40478c2ecf20Sopenharmony_ci * 40488c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 40498c2ecf20Sopenharmony_ci * @nvm_ver: pointer to output structure 40508c2ecf20Sopenharmony_ci * 40518c2ecf20Sopenharmony_ci * if valid OEM product version, nvm_ver->oem_valid set to true 40528c2ecf20Sopenharmony_ci * else nvm_ver->oem_valid is false. 40538c2ecf20Sopenharmony_ci **/ 40548c2ecf20Sopenharmony_civoid ixgbe_get_oem_prod_version(struct ixgbe_hw *hw, 40558c2ecf20Sopenharmony_ci struct ixgbe_nvm_version *nvm_ver) 40568c2ecf20Sopenharmony_ci{ 40578c2ecf20Sopenharmony_ci u16 rel_num, prod_ver, mod_len, cap, offset; 40588c2ecf20Sopenharmony_ci 40598c2ecf20Sopenharmony_ci nvm_ver->oem_valid = false; 40608c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, NVM_OEM_PROD_VER_PTR, &offset); 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_ci /* Return is offset to OEM Product Version block is invalid */ 40638c2ecf20Sopenharmony_ci if (offset == 0x0 || offset == NVM_INVALID_PTR) 40648c2ecf20Sopenharmony_ci return; 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci /* Read product version block */ 40678c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, offset, &mod_len); 40688c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, offset + NVM_OEM_PROD_VER_CAP_OFF, &cap); 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci /* Return if OEM product version block is invalid */ 40718c2ecf20Sopenharmony_ci if (mod_len != NVM_OEM_PROD_VER_MOD_LEN || 40728c2ecf20Sopenharmony_ci (cap & NVM_OEM_PROD_VER_CAP_MASK) != 0x0) 40738c2ecf20Sopenharmony_ci return; 40748c2ecf20Sopenharmony_ci 40758c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, offset + NVM_OEM_PROD_VER_OFF_L, &prod_ver); 40768c2ecf20Sopenharmony_ci hw->eeprom.ops.read(hw, offset + NVM_OEM_PROD_VER_OFF_H, &rel_num); 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci /* Return if version is invalid */ 40798c2ecf20Sopenharmony_ci if ((rel_num | prod_ver) == 0x0 || 40808c2ecf20Sopenharmony_ci rel_num == NVM_VER_INVALID || prod_ver == NVM_VER_INVALID) 40818c2ecf20Sopenharmony_ci return; 40828c2ecf20Sopenharmony_ci 40838c2ecf20Sopenharmony_ci nvm_ver->oem_major = prod_ver >> NVM_VER_SHIFT; 40848c2ecf20Sopenharmony_ci nvm_ver->oem_minor = prod_ver & NVM_VER_MASK; 40858c2ecf20Sopenharmony_ci nvm_ver->oem_release = rel_num; 40868c2ecf20Sopenharmony_ci nvm_ver->oem_valid = true; 40878c2ecf20Sopenharmony_ci} 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_ci/** 40908c2ecf20Sopenharmony_ci * ixgbe_get_etk_id - Return Etrack ID from EEPROM 40918c2ecf20Sopenharmony_ci * 40928c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 40938c2ecf20Sopenharmony_ci * @nvm_ver: pointer to output structure 40948c2ecf20Sopenharmony_ci * 40958c2ecf20Sopenharmony_ci * word read errors will return 0xFFFF 40968c2ecf20Sopenharmony_ci **/ 40978c2ecf20Sopenharmony_civoid ixgbe_get_etk_id(struct ixgbe_hw *hw, 40988c2ecf20Sopenharmony_ci struct ixgbe_nvm_version *nvm_ver) 40998c2ecf20Sopenharmony_ci{ 41008c2ecf20Sopenharmony_ci u16 etk_id_l, etk_id_h; 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, NVM_ETK_OFF_LOW, &etk_id_l)) 41038c2ecf20Sopenharmony_ci etk_id_l = NVM_VER_INVALID; 41048c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, NVM_ETK_OFF_HI, &etk_id_h)) 41058c2ecf20Sopenharmony_ci etk_id_h = NVM_VER_INVALID; 41068c2ecf20Sopenharmony_ci 41078c2ecf20Sopenharmony_ci /* The word order for the version format is determined by high order 41088c2ecf20Sopenharmony_ci * word bit 15. 41098c2ecf20Sopenharmony_ci */ 41108c2ecf20Sopenharmony_ci if ((etk_id_h & NVM_ETK_VALID) == 0) { 41118c2ecf20Sopenharmony_ci nvm_ver->etk_id = etk_id_h; 41128c2ecf20Sopenharmony_ci nvm_ver->etk_id |= (etk_id_l << NVM_ETK_SHIFT); 41138c2ecf20Sopenharmony_ci } else { 41148c2ecf20Sopenharmony_ci nvm_ver->etk_id = etk_id_l; 41158c2ecf20Sopenharmony_ci nvm_ver->etk_id |= (etk_id_h << NVM_ETK_SHIFT); 41168c2ecf20Sopenharmony_ci } 41178c2ecf20Sopenharmony_ci} 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_civoid ixgbe_disable_rx_generic(struct ixgbe_hw *hw) 41208c2ecf20Sopenharmony_ci{ 41218c2ecf20Sopenharmony_ci u32 rxctrl; 41228c2ecf20Sopenharmony_ci 41238c2ecf20Sopenharmony_ci rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 41248c2ecf20Sopenharmony_ci if (rxctrl & IXGBE_RXCTRL_RXEN) { 41258c2ecf20Sopenharmony_ci if (hw->mac.type != ixgbe_mac_82598EB) { 41268c2ecf20Sopenharmony_ci u32 pfdtxgswc; 41278c2ecf20Sopenharmony_ci 41288c2ecf20Sopenharmony_ci pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC); 41298c2ecf20Sopenharmony_ci if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) { 41308c2ecf20Sopenharmony_ci pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN; 41318c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc); 41328c2ecf20Sopenharmony_ci hw->mac.set_lben = true; 41338c2ecf20Sopenharmony_ci } else { 41348c2ecf20Sopenharmony_ci hw->mac.set_lben = false; 41358c2ecf20Sopenharmony_ci } 41368c2ecf20Sopenharmony_ci } 41378c2ecf20Sopenharmony_ci rxctrl &= ~IXGBE_RXCTRL_RXEN; 41388c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl); 41398c2ecf20Sopenharmony_ci } 41408c2ecf20Sopenharmony_ci} 41418c2ecf20Sopenharmony_ci 41428c2ecf20Sopenharmony_civoid ixgbe_enable_rx_generic(struct ixgbe_hw *hw) 41438c2ecf20Sopenharmony_ci{ 41448c2ecf20Sopenharmony_ci u32 rxctrl; 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 41478c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, (rxctrl | IXGBE_RXCTRL_RXEN)); 41488c2ecf20Sopenharmony_ci 41498c2ecf20Sopenharmony_ci if (hw->mac.type != ixgbe_mac_82598EB) { 41508c2ecf20Sopenharmony_ci if (hw->mac.set_lben) { 41518c2ecf20Sopenharmony_ci u32 pfdtxgswc; 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ci pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC); 41548c2ecf20Sopenharmony_ci pfdtxgswc |= IXGBE_PFDTXGSWC_VT_LBEN; 41558c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc); 41568c2ecf20Sopenharmony_ci hw->mac.set_lben = false; 41578c2ecf20Sopenharmony_ci } 41588c2ecf20Sopenharmony_ci } 41598c2ecf20Sopenharmony_ci} 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci/** ixgbe_mng_present - returns true when management capability is present 41628c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 41638c2ecf20Sopenharmony_ci **/ 41648c2ecf20Sopenharmony_cibool ixgbe_mng_present(struct ixgbe_hw *hw) 41658c2ecf20Sopenharmony_ci{ 41668c2ecf20Sopenharmony_ci u32 fwsm; 41678c2ecf20Sopenharmony_ci 41688c2ecf20Sopenharmony_ci if (hw->mac.type < ixgbe_mac_82599EB) 41698c2ecf20Sopenharmony_ci return false; 41708c2ecf20Sopenharmony_ci 41718c2ecf20Sopenharmony_ci fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw)); 41728c2ecf20Sopenharmony_ci 41738c2ecf20Sopenharmony_ci return !!(fwsm & IXGBE_FWSM_FW_MODE_PT); 41748c2ecf20Sopenharmony_ci} 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci/** 41778c2ecf20Sopenharmony_ci * ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed 41788c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 41798c2ecf20Sopenharmony_ci * @speed: new link speed 41808c2ecf20Sopenharmony_ci * @autoneg_wait_to_complete: true when waiting for completion is needed 41818c2ecf20Sopenharmony_ci * 41828c2ecf20Sopenharmony_ci * Set the link speed in the MAC and/or PHY register and restarts link. 41838c2ecf20Sopenharmony_ci */ 41848c2ecf20Sopenharmony_cis32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, 41858c2ecf20Sopenharmony_ci ixgbe_link_speed speed, 41868c2ecf20Sopenharmony_ci bool autoneg_wait_to_complete) 41878c2ecf20Sopenharmony_ci{ 41888c2ecf20Sopenharmony_ci ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN; 41898c2ecf20Sopenharmony_ci ixgbe_link_speed highest_link_speed = IXGBE_LINK_SPEED_UNKNOWN; 41908c2ecf20Sopenharmony_ci s32 status = 0; 41918c2ecf20Sopenharmony_ci u32 speedcnt = 0; 41928c2ecf20Sopenharmony_ci u32 i = 0; 41938c2ecf20Sopenharmony_ci bool autoneg, link_up = false; 41948c2ecf20Sopenharmony_ci 41958c2ecf20Sopenharmony_ci /* Mask off requested but non-supported speeds */ 41968c2ecf20Sopenharmony_ci status = hw->mac.ops.get_link_capabilities(hw, &link_speed, &autoneg); 41978c2ecf20Sopenharmony_ci if (status) 41988c2ecf20Sopenharmony_ci return status; 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_ci speed &= link_speed; 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci /* Try each speed one by one, highest priority first. We do this in 42038c2ecf20Sopenharmony_ci * software because 10Gb fiber doesn't support speed autonegotiation. 42048c2ecf20Sopenharmony_ci */ 42058c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10GB_FULL) { 42068c2ecf20Sopenharmony_ci speedcnt++; 42078c2ecf20Sopenharmony_ci highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL; 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci /* Set the module link speed */ 42108c2ecf20Sopenharmony_ci switch (hw->phy.media_type) { 42118c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber: 42128c2ecf20Sopenharmony_ci hw->mac.ops.set_rate_select_speed(hw, 42138c2ecf20Sopenharmony_ci IXGBE_LINK_SPEED_10GB_FULL); 42148c2ecf20Sopenharmony_ci break; 42158c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber_qsfp: 42168c2ecf20Sopenharmony_ci /* QSFP module automatically detects MAC link speed */ 42178c2ecf20Sopenharmony_ci break; 42188c2ecf20Sopenharmony_ci default: 42198c2ecf20Sopenharmony_ci hw_dbg(hw, "Unexpected media type\n"); 42208c2ecf20Sopenharmony_ci break; 42218c2ecf20Sopenharmony_ci } 42228c2ecf20Sopenharmony_ci 42238c2ecf20Sopenharmony_ci /* Allow module to change analog characteristics (1G->10G) */ 42248c2ecf20Sopenharmony_ci msleep(40); 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci status = hw->mac.ops.setup_mac_link(hw, 42278c2ecf20Sopenharmony_ci IXGBE_LINK_SPEED_10GB_FULL, 42288c2ecf20Sopenharmony_ci autoneg_wait_to_complete); 42298c2ecf20Sopenharmony_ci if (status) 42308c2ecf20Sopenharmony_ci return status; 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_ci /* Flap the Tx laser if it has not already been done */ 42338c2ecf20Sopenharmony_ci if (hw->mac.ops.flap_tx_laser) 42348c2ecf20Sopenharmony_ci hw->mac.ops.flap_tx_laser(hw); 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_ci /* Wait for the controller to acquire link. Per IEEE 802.3ap, 42378c2ecf20Sopenharmony_ci * Section 73.10.2, we may have to wait up to 500ms if KR is 42388c2ecf20Sopenharmony_ci * attempted. 82599 uses the same timing for 10g SFI. 42398c2ecf20Sopenharmony_ci */ 42408c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 42418c2ecf20Sopenharmony_ci /* Wait for the link partner to also set speed */ 42428c2ecf20Sopenharmony_ci msleep(100); 42438c2ecf20Sopenharmony_ci 42448c2ecf20Sopenharmony_ci /* If we have link, just jump out */ 42458c2ecf20Sopenharmony_ci status = hw->mac.ops.check_link(hw, &link_speed, 42468c2ecf20Sopenharmony_ci &link_up, false); 42478c2ecf20Sopenharmony_ci if (status) 42488c2ecf20Sopenharmony_ci return status; 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci if (link_up) 42518c2ecf20Sopenharmony_ci goto out; 42528c2ecf20Sopenharmony_ci } 42538c2ecf20Sopenharmony_ci } 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_1GB_FULL) { 42568c2ecf20Sopenharmony_ci speedcnt++; 42578c2ecf20Sopenharmony_ci if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN) 42588c2ecf20Sopenharmony_ci highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL; 42598c2ecf20Sopenharmony_ci 42608c2ecf20Sopenharmony_ci /* Set the module link speed */ 42618c2ecf20Sopenharmony_ci switch (hw->phy.media_type) { 42628c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber: 42638c2ecf20Sopenharmony_ci hw->mac.ops.set_rate_select_speed(hw, 42648c2ecf20Sopenharmony_ci IXGBE_LINK_SPEED_1GB_FULL); 42658c2ecf20Sopenharmony_ci break; 42668c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber_qsfp: 42678c2ecf20Sopenharmony_ci /* QSFP module automatically detects link speed */ 42688c2ecf20Sopenharmony_ci break; 42698c2ecf20Sopenharmony_ci default: 42708c2ecf20Sopenharmony_ci hw_dbg(hw, "Unexpected media type\n"); 42718c2ecf20Sopenharmony_ci break; 42728c2ecf20Sopenharmony_ci } 42738c2ecf20Sopenharmony_ci 42748c2ecf20Sopenharmony_ci /* Allow module to change analog characteristics (10G->1G) */ 42758c2ecf20Sopenharmony_ci msleep(40); 42768c2ecf20Sopenharmony_ci 42778c2ecf20Sopenharmony_ci status = hw->mac.ops.setup_mac_link(hw, 42788c2ecf20Sopenharmony_ci IXGBE_LINK_SPEED_1GB_FULL, 42798c2ecf20Sopenharmony_ci autoneg_wait_to_complete); 42808c2ecf20Sopenharmony_ci if (status) 42818c2ecf20Sopenharmony_ci return status; 42828c2ecf20Sopenharmony_ci 42838c2ecf20Sopenharmony_ci /* Flap the Tx laser if it has not already been done */ 42848c2ecf20Sopenharmony_ci if (hw->mac.ops.flap_tx_laser) 42858c2ecf20Sopenharmony_ci hw->mac.ops.flap_tx_laser(hw); 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_ci /* Wait for the link partner to also set speed */ 42888c2ecf20Sopenharmony_ci msleep(100); 42898c2ecf20Sopenharmony_ci 42908c2ecf20Sopenharmony_ci /* If we have link, just jump out */ 42918c2ecf20Sopenharmony_ci status = hw->mac.ops.check_link(hw, &link_speed, &link_up, 42928c2ecf20Sopenharmony_ci false); 42938c2ecf20Sopenharmony_ci if (status) 42948c2ecf20Sopenharmony_ci return status; 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci if (link_up) 42978c2ecf20Sopenharmony_ci goto out; 42988c2ecf20Sopenharmony_ci } 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_ci /* We didn't get link. Configure back to the highest speed we tried, 43018c2ecf20Sopenharmony_ci * (if there was more than one). We call ourselves back with just the 43028c2ecf20Sopenharmony_ci * single highest speed that the user requested. 43038c2ecf20Sopenharmony_ci */ 43048c2ecf20Sopenharmony_ci if (speedcnt > 1) 43058c2ecf20Sopenharmony_ci status = ixgbe_setup_mac_link_multispeed_fiber(hw, 43068c2ecf20Sopenharmony_ci highest_link_speed, 43078c2ecf20Sopenharmony_ci autoneg_wait_to_complete); 43088c2ecf20Sopenharmony_ci 43098c2ecf20Sopenharmony_ciout: 43108c2ecf20Sopenharmony_ci /* Set autoneg_advertised value based on input link speed */ 43118c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised = 0; 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10GB_FULL) 43148c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; 43158c2ecf20Sopenharmony_ci 43168c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_1GB_FULL) 43178c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; 43188c2ecf20Sopenharmony_ci 43198c2ecf20Sopenharmony_ci return status; 43208c2ecf20Sopenharmony_ci} 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_ci/** 43238c2ecf20Sopenharmony_ci * ixgbe_set_soft_rate_select_speed - Set module link speed 43248c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 43258c2ecf20Sopenharmony_ci * @speed: link speed to set 43268c2ecf20Sopenharmony_ci * 43278c2ecf20Sopenharmony_ci * Set module link speed via the soft rate select. 43288c2ecf20Sopenharmony_ci */ 43298c2ecf20Sopenharmony_civoid ixgbe_set_soft_rate_select_speed(struct ixgbe_hw *hw, 43308c2ecf20Sopenharmony_ci ixgbe_link_speed speed) 43318c2ecf20Sopenharmony_ci{ 43328c2ecf20Sopenharmony_ci s32 status; 43338c2ecf20Sopenharmony_ci u8 rs, eeprom_data; 43348c2ecf20Sopenharmony_ci 43358c2ecf20Sopenharmony_ci switch (speed) { 43368c2ecf20Sopenharmony_ci case IXGBE_LINK_SPEED_10GB_FULL: 43378c2ecf20Sopenharmony_ci /* one bit mask same as setting on */ 43388c2ecf20Sopenharmony_ci rs = IXGBE_SFF_SOFT_RS_SELECT_10G; 43398c2ecf20Sopenharmony_ci break; 43408c2ecf20Sopenharmony_ci case IXGBE_LINK_SPEED_1GB_FULL: 43418c2ecf20Sopenharmony_ci rs = IXGBE_SFF_SOFT_RS_SELECT_1G; 43428c2ecf20Sopenharmony_ci break; 43438c2ecf20Sopenharmony_ci default: 43448c2ecf20Sopenharmony_ci hw_dbg(hw, "Invalid fixed module speed\n"); 43458c2ecf20Sopenharmony_ci return; 43468c2ecf20Sopenharmony_ci } 43478c2ecf20Sopenharmony_ci 43488c2ecf20Sopenharmony_ci /* Set RS0 */ 43498c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB, 43508c2ecf20Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR2, 43518c2ecf20Sopenharmony_ci &eeprom_data); 43528c2ecf20Sopenharmony_ci if (status) { 43538c2ecf20Sopenharmony_ci hw_dbg(hw, "Failed to read Rx Rate Select RS0\n"); 43548c2ecf20Sopenharmony_ci return; 43558c2ecf20Sopenharmony_ci } 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) | rs; 43588c2ecf20Sopenharmony_ci 43598c2ecf20Sopenharmony_ci status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB, 43608c2ecf20Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR2, 43618c2ecf20Sopenharmony_ci eeprom_data); 43628c2ecf20Sopenharmony_ci if (status) { 43638c2ecf20Sopenharmony_ci hw_dbg(hw, "Failed to write Rx Rate Select RS0\n"); 43648c2ecf20Sopenharmony_ci return; 43658c2ecf20Sopenharmony_ci } 43668c2ecf20Sopenharmony_ci 43678c2ecf20Sopenharmony_ci /* Set RS1 */ 43688c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB, 43698c2ecf20Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR2, 43708c2ecf20Sopenharmony_ci &eeprom_data); 43718c2ecf20Sopenharmony_ci if (status) { 43728c2ecf20Sopenharmony_ci hw_dbg(hw, "Failed to read Rx Rate Select RS1\n"); 43738c2ecf20Sopenharmony_ci return; 43748c2ecf20Sopenharmony_ci } 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_ci eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) | rs; 43778c2ecf20Sopenharmony_ci 43788c2ecf20Sopenharmony_ci status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB, 43798c2ecf20Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR2, 43808c2ecf20Sopenharmony_ci eeprom_data); 43818c2ecf20Sopenharmony_ci if (status) { 43828c2ecf20Sopenharmony_ci hw_dbg(hw, "Failed to write Rx Rate Select RS1\n"); 43838c2ecf20Sopenharmony_ci return; 43848c2ecf20Sopenharmony_ci } 43858c2ecf20Sopenharmony_ci} 4386