162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/pci.h> 562306a36Sopenharmony_ci#include <linux/delay.h> 662306a36Sopenharmony_ci#include <linux/sched.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "ixgbe.h" 962306a36Sopenharmony_ci#include "ixgbe_phy.h" 1062306a36Sopenharmony_ci#include "ixgbe_mbx.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define IXGBE_82599_MAX_TX_QUEUES 128 1362306a36Sopenharmony_ci#define IXGBE_82599_MAX_RX_QUEUES 128 1462306a36Sopenharmony_ci#define IXGBE_82599_RAR_ENTRIES 128 1562306a36Sopenharmony_ci#define IXGBE_82599_MC_TBL_SIZE 128 1662306a36Sopenharmony_ci#define IXGBE_82599_VFT_TBL_SIZE 128 1762306a36Sopenharmony_ci#define IXGBE_82599_RX_PB_SIZE 512 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); 2062306a36Sopenharmony_cistatic void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); 2162306a36Sopenharmony_cistatic void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); 2262306a36Sopenharmony_cistatic void 2362306a36Sopenharmony_ciixgbe_set_hard_rate_select_speed(struct ixgbe_hw *, ixgbe_link_speed); 2462306a36Sopenharmony_cistatic s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, 2562306a36Sopenharmony_ci ixgbe_link_speed speed, 2662306a36Sopenharmony_ci bool autoneg_wait_to_complete); 2762306a36Sopenharmony_cistatic void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw); 2862306a36Sopenharmony_cistatic s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, 2962306a36Sopenharmony_ci bool autoneg_wait_to_complete); 3062306a36Sopenharmony_cistatic s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, 3162306a36Sopenharmony_ci ixgbe_link_speed speed, 3262306a36Sopenharmony_ci bool autoneg_wait_to_complete); 3362306a36Sopenharmony_cistatic s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, 3462306a36Sopenharmony_ci ixgbe_link_speed speed, 3562306a36Sopenharmony_ci bool autoneg_wait_to_complete); 3662306a36Sopenharmony_cistatic s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); 3762306a36Sopenharmony_cistatic s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, 3862306a36Sopenharmony_ci u8 dev_addr, u8 *data); 3962306a36Sopenharmony_cistatic s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, 4062306a36Sopenharmony_ci u8 dev_addr, u8 data); 4162306a36Sopenharmony_cistatic s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw); 4262306a36Sopenharmony_cistatic bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cibool ixgbe_mng_enabled(struct ixgbe_hw *hw) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci u32 fwsm, manc, factps; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw)); 4962306a36Sopenharmony_ci if ((fwsm & IXGBE_FWSM_MODE_MASK) != IXGBE_FWSM_FW_MODE_PT) 5062306a36Sopenharmony_ci return false; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci manc = IXGBE_READ_REG(hw, IXGBE_MANC); 5362306a36Sopenharmony_ci if (!(manc & IXGBE_MANC_RCV_TCO_EN)) 5462306a36Sopenharmony_ci return false; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci factps = IXGBE_READ_REG(hw, IXGBE_FACTPS(hw)); 5762306a36Sopenharmony_ci if (factps & IXGBE_FACTPS_MNGCG) 5862306a36Sopenharmony_ci return false; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return true; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct ixgbe_mac_info *mac = &hw->mac; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* enable the laser control functions for SFP+ fiber 6862306a36Sopenharmony_ci * and MNG not enabled 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci if ((mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) && 7162306a36Sopenharmony_ci !ixgbe_mng_enabled(hw)) { 7262306a36Sopenharmony_ci mac->ops.disable_tx_laser = 7362306a36Sopenharmony_ci &ixgbe_disable_tx_laser_multispeed_fiber; 7462306a36Sopenharmony_ci mac->ops.enable_tx_laser = 7562306a36Sopenharmony_ci &ixgbe_enable_tx_laser_multispeed_fiber; 7662306a36Sopenharmony_ci mac->ops.flap_tx_laser = &ixgbe_flap_tx_laser_multispeed_fiber; 7762306a36Sopenharmony_ci } else { 7862306a36Sopenharmony_ci mac->ops.disable_tx_laser = NULL; 7962306a36Sopenharmony_ci mac->ops.enable_tx_laser = NULL; 8062306a36Sopenharmony_ci mac->ops.flap_tx_laser = NULL; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (hw->phy.multispeed_fiber) { 8462306a36Sopenharmony_ci /* Set up dual speed SFP+ support */ 8562306a36Sopenharmony_ci mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber; 8662306a36Sopenharmony_ci mac->ops.setup_mac_link = ixgbe_setup_mac_link_82599; 8762306a36Sopenharmony_ci mac->ops.set_rate_select_speed = 8862306a36Sopenharmony_ci ixgbe_set_hard_rate_select_speed; 8962306a36Sopenharmony_ci } else { 9062306a36Sopenharmony_ci if ((mac->ops.get_media_type(hw) == 9162306a36Sopenharmony_ci ixgbe_media_type_backplane) && 9262306a36Sopenharmony_ci (hw->phy.smart_speed == ixgbe_smart_speed_auto || 9362306a36Sopenharmony_ci hw->phy.smart_speed == ixgbe_smart_speed_on) && 9462306a36Sopenharmony_ci !ixgbe_verify_lesm_fw_enabled_82599(hw)) 9562306a36Sopenharmony_ci mac->ops.setup_link = &ixgbe_setup_mac_link_smartspeed; 9662306a36Sopenharmony_ci else 9762306a36Sopenharmony_ci mac->ops.setup_link = &ixgbe_setup_mac_link_82599; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci s32 ret_val; 10462306a36Sopenharmony_ci u16 list_offset, data_offset, data_value; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) { 10762306a36Sopenharmony_ci ixgbe_init_mac_link_ops_82599(hw); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci hw->phy.ops.reset = NULL; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, 11262306a36Sopenharmony_ci &data_offset); 11362306a36Sopenharmony_ci if (ret_val) 11462306a36Sopenharmony_ci return ret_val; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* PHY config will finish before releasing the semaphore */ 11762306a36Sopenharmony_ci ret_val = hw->mac.ops.acquire_swfw_sync(hw, 11862306a36Sopenharmony_ci IXGBE_GSSR_MAC_CSR_SM); 11962306a36Sopenharmony_ci if (ret_val) 12062306a36Sopenharmony_ci return -EBUSY; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (hw->eeprom.ops.read(hw, ++data_offset, &data_value)) 12362306a36Sopenharmony_ci goto setup_sfp_err; 12462306a36Sopenharmony_ci while (data_value != 0xffff) { 12562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_CORECTL, data_value); 12662306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 12762306a36Sopenharmony_ci if (hw->eeprom.ops.read(hw, ++data_offset, &data_value)) 12862306a36Sopenharmony_ci goto setup_sfp_err; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* Release the semaphore */ 13262306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); 13362306a36Sopenharmony_ci /* 13462306a36Sopenharmony_ci * Delay obtaining semaphore again to allow FW access, 13562306a36Sopenharmony_ci * semaphore_delay is in ms usleep_range needs us. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci usleep_range(hw->eeprom.semaphore_delay * 1000, 13862306a36Sopenharmony_ci hw->eeprom.semaphore_delay * 2000); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* Restart DSP and set SFI mode */ 14162306a36Sopenharmony_ci ret_val = hw->mac.ops.prot_autoc_write(hw, 14262306a36Sopenharmony_ci hw->mac.orig_autoc | IXGBE_AUTOC_LMS_10G_SERIAL, 14362306a36Sopenharmony_ci false); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (ret_val) { 14662306a36Sopenharmony_ci hw_dbg(hw, " sfp module setup not complete\n"); 14762306a36Sopenharmony_ci return -EIO; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cisetup_sfp_err: 15462306a36Sopenharmony_ci /* Release the semaphore */ 15562306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); 15662306a36Sopenharmony_ci /* Delay obtaining semaphore again to allow FW access, 15762306a36Sopenharmony_ci * semaphore_delay is in ms usleep_range needs us. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci usleep_range(hw->eeprom.semaphore_delay * 1000, 16062306a36Sopenharmony_ci hw->eeprom.semaphore_delay * 2000); 16162306a36Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", data_offset); 16262306a36Sopenharmony_ci return -EIO; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/** 16662306a36Sopenharmony_ci * prot_autoc_read_82599 - Hides MAC differences needed for AUTOC read 16762306a36Sopenharmony_ci * @hw: pointer to hardware structure 16862306a36Sopenharmony_ci * @locked: Return the if we locked for this read. 16962306a36Sopenharmony_ci * @reg_val: Value we read from AUTOC 17062306a36Sopenharmony_ci * 17162306a36Sopenharmony_ci * For this part (82599) we need to wrap read-modify-writes with a possible 17262306a36Sopenharmony_ci * FW/SW lock. It is assumed this lock will be freed with the next 17362306a36Sopenharmony_ci * prot_autoc_write_82599(). Note, that locked can only be true in cases 17462306a36Sopenharmony_ci * where this function doesn't return an error. 17562306a36Sopenharmony_ci **/ 17662306a36Sopenharmony_cistatic s32 prot_autoc_read_82599(struct ixgbe_hw *hw, bool *locked, 17762306a36Sopenharmony_ci u32 *reg_val) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci s32 ret_val; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci *locked = false; 18262306a36Sopenharmony_ci /* If LESM is on then we need to hold the SW/FW semaphore. */ 18362306a36Sopenharmony_ci if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { 18462306a36Sopenharmony_ci ret_val = hw->mac.ops.acquire_swfw_sync(hw, 18562306a36Sopenharmony_ci IXGBE_GSSR_MAC_CSR_SM); 18662306a36Sopenharmony_ci if (ret_val) 18762306a36Sopenharmony_ci return -EBUSY; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci *locked = true; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci *reg_val = IXGBE_READ_REG(hw, IXGBE_AUTOC); 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/** 19762306a36Sopenharmony_ci * prot_autoc_write_82599 - Hides MAC differences needed for AUTOC write 19862306a36Sopenharmony_ci * @hw: pointer to hardware structure 19962306a36Sopenharmony_ci * @autoc: value to write to AUTOC 20062306a36Sopenharmony_ci * @locked: bool to indicate whether the SW/FW lock was already taken by 20162306a36Sopenharmony_ci * previous proc_autoc_read_82599. 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * This part (82599) may need to hold a the SW/FW lock around all writes to 20462306a36Sopenharmony_ci * AUTOC. Likewise after a write we need to do a pipeline reset. 20562306a36Sopenharmony_ci **/ 20662306a36Sopenharmony_cistatic s32 prot_autoc_write_82599(struct ixgbe_hw *hw, u32 autoc, bool locked) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci s32 ret_val = 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* Blocked by MNG FW so bail */ 21162306a36Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 21262306a36Sopenharmony_ci goto out; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* We only need to get the lock if: 21562306a36Sopenharmony_ci * - We didn't do it already (in the read part of a read-modify-write) 21662306a36Sopenharmony_ci * - LESM is enabled. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci if (!locked && ixgbe_verify_lesm_fw_enabled_82599(hw)) { 21962306a36Sopenharmony_ci ret_val = hw->mac.ops.acquire_swfw_sync(hw, 22062306a36Sopenharmony_ci IXGBE_GSSR_MAC_CSR_SM); 22162306a36Sopenharmony_ci if (ret_val) 22262306a36Sopenharmony_ci return -EBUSY; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci locked = true; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); 22862306a36Sopenharmony_ci ret_val = ixgbe_reset_pipeline_82599(hw); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ciout: 23162306a36Sopenharmony_ci /* Free the SW/FW semaphore as we either grabbed it here or 23262306a36Sopenharmony_ci * already had it when this function was called. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci if (locked) 23562306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return ret_val; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct ixgbe_mac_info *mac = &hw->mac; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci ixgbe_init_mac_link_ops_82599(hw); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci mac->mcft_size = IXGBE_82599_MC_TBL_SIZE; 24762306a36Sopenharmony_ci mac->vft_size = IXGBE_82599_VFT_TBL_SIZE; 24862306a36Sopenharmony_ci mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES; 24962306a36Sopenharmony_ci mac->rx_pb_size = IXGBE_82599_RX_PB_SIZE; 25062306a36Sopenharmony_ci mac->max_rx_queues = IXGBE_82599_MAX_RX_QUEUES; 25162306a36Sopenharmony_ci mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES; 25262306a36Sopenharmony_ci mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/** 25862306a36Sopenharmony_ci * ixgbe_init_phy_ops_82599 - PHY/SFP specific init 25962306a36Sopenharmony_ci * @hw: pointer to hardware structure 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * Initialize any function pointers that were not able to be 26262306a36Sopenharmony_ci * set during get_invariants because the PHY/SFP type was 26362306a36Sopenharmony_ci * not known. Perform the SFP init if necessary. 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci **/ 26662306a36Sopenharmony_cistatic s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct ixgbe_mac_info *mac = &hw->mac; 26962306a36Sopenharmony_ci struct ixgbe_phy_info *phy = &hw->phy; 27062306a36Sopenharmony_ci s32 ret_val; 27162306a36Sopenharmony_ci u32 esdp; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (hw->device_id == IXGBE_DEV_ID_82599_QSFP_SF_QP) { 27462306a36Sopenharmony_ci /* Store flag indicating I2C bus access control unit. */ 27562306a36Sopenharmony_ci hw->phy.qsfp_shared_i2c_bus = true; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* Initialize access to QSFP+ I2C bus */ 27862306a36Sopenharmony_ci esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 27962306a36Sopenharmony_ci esdp |= IXGBE_ESDP_SDP0_DIR; 28062306a36Sopenharmony_ci esdp &= ~IXGBE_ESDP_SDP1_DIR; 28162306a36Sopenharmony_ci esdp &= ~IXGBE_ESDP_SDP0; 28262306a36Sopenharmony_ci esdp &= ~IXGBE_ESDP_SDP0_NATIVE; 28362306a36Sopenharmony_ci esdp &= ~IXGBE_ESDP_SDP1_NATIVE; 28462306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 28562306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci phy->ops.read_i2c_byte = &ixgbe_read_i2c_byte_82599; 28862306a36Sopenharmony_ci phy->ops.write_i2c_byte = &ixgbe_write_i2c_byte_82599; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* Identify the PHY or SFP module */ 29262306a36Sopenharmony_ci ret_val = phy->ops.identify(hw); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* Setup function pointers based on detected SFP module and speeds */ 29562306a36Sopenharmony_ci ixgbe_init_mac_link_ops_82599(hw); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* If copper media, overwrite with copper function pointers */ 29862306a36Sopenharmony_ci if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { 29962306a36Sopenharmony_ci mac->ops.setup_link = &ixgbe_setup_copper_link_82599; 30062306a36Sopenharmony_ci mac->ops.get_link_capabilities = 30162306a36Sopenharmony_ci &ixgbe_get_copper_link_capabilities_generic; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Set necessary function pointers based on phy type */ 30562306a36Sopenharmony_ci switch (hw->phy.type) { 30662306a36Sopenharmony_ci case ixgbe_phy_tn: 30762306a36Sopenharmony_ci phy->ops.check_link = &ixgbe_check_phy_link_tnx; 30862306a36Sopenharmony_ci phy->ops.setup_link = &ixgbe_setup_phy_link_tnx; 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci default: 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return ret_val; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci/** 31862306a36Sopenharmony_ci * ixgbe_get_link_capabilities_82599 - Determines link capabilities 31962306a36Sopenharmony_ci * @hw: pointer to hardware structure 32062306a36Sopenharmony_ci * @speed: pointer to link speed 32162306a36Sopenharmony_ci * @autoneg: true when autoneg or autotry is enabled 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * Determines the link capabilities by reading the AUTOC register. 32462306a36Sopenharmony_ci **/ 32562306a36Sopenharmony_cistatic s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, 32662306a36Sopenharmony_ci ixgbe_link_speed *speed, 32762306a36Sopenharmony_ci bool *autoneg) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci u32 autoc = 0; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* Determine 1G link capabilities off of SFP+ type */ 33262306a36Sopenharmony_ci if (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || 33362306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || 33462306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || 33562306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || 33662306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || 33762306a36Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) { 33862306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_1GB_FULL; 33962306a36Sopenharmony_ci *autoneg = true; 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* 34462306a36Sopenharmony_ci * Determine link capabilities based on the stored value of AUTOC, 34562306a36Sopenharmony_ci * which represents EEPROM defaults. If AUTOC value has not been 34662306a36Sopenharmony_ci * stored, use the current register value. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci if (hw->mac.orig_link_settings_stored) 34962306a36Sopenharmony_ci autoc = hw->mac.orig_autoc; 35062306a36Sopenharmony_ci else 35162306a36Sopenharmony_ci autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci switch (autoc & IXGBE_AUTOC_LMS_MASK) { 35462306a36Sopenharmony_ci case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: 35562306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_1GB_FULL; 35662306a36Sopenharmony_ci *autoneg = false; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: 36062306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_10GB_FULL; 36162306a36Sopenharmony_ci *autoneg = false; 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci case IXGBE_AUTOC_LMS_1G_AN: 36562306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_1GB_FULL; 36662306a36Sopenharmony_ci *autoneg = true; 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci case IXGBE_AUTOC_LMS_10G_SERIAL: 37062306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_10GB_FULL; 37162306a36Sopenharmony_ci *autoneg = false; 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci case IXGBE_AUTOC_LMS_KX4_KX_KR: 37562306a36Sopenharmony_ci case IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN: 37662306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_UNKNOWN; 37762306a36Sopenharmony_ci if (autoc & IXGBE_AUTOC_KR_SUPP) 37862306a36Sopenharmony_ci *speed |= IXGBE_LINK_SPEED_10GB_FULL; 37962306a36Sopenharmony_ci if (autoc & IXGBE_AUTOC_KX4_SUPP) 38062306a36Sopenharmony_ci *speed |= IXGBE_LINK_SPEED_10GB_FULL; 38162306a36Sopenharmony_ci if (autoc & IXGBE_AUTOC_KX_SUPP) 38262306a36Sopenharmony_ci *speed |= IXGBE_LINK_SPEED_1GB_FULL; 38362306a36Sopenharmony_ci *autoneg = true; 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci case IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII: 38762306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_100_FULL; 38862306a36Sopenharmony_ci if (autoc & IXGBE_AUTOC_KR_SUPP) 38962306a36Sopenharmony_ci *speed |= IXGBE_LINK_SPEED_10GB_FULL; 39062306a36Sopenharmony_ci if (autoc & IXGBE_AUTOC_KX4_SUPP) 39162306a36Sopenharmony_ci *speed |= IXGBE_LINK_SPEED_10GB_FULL; 39262306a36Sopenharmony_ci if (autoc & IXGBE_AUTOC_KX_SUPP) 39362306a36Sopenharmony_ci *speed |= IXGBE_LINK_SPEED_1GB_FULL; 39462306a36Sopenharmony_ci *autoneg = true; 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci case IXGBE_AUTOC_LMS_SGMII_1G_100M: 39862306a36Sopenharmony_ci *speed = IXGBE_LINK_SPEED_1GB_FULL | IXGBE_LINK_SPEED_100_FULL; 39962306a36Sopenharmony_ci *autoneg = false; 40062306a36Sopenharmony_ci break; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci default: 40362306a36Sopenharmony_ci return -EIO; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (hw->phy.multispeed_fiber) { 40762306a36Sopenharmony_ci *speed |= IXGBE_LINK_SPEED_10GB_FULL | 40862306a36Sopenharmony_ci IXGBE_LINK_SPEED_1GB_FULL; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* QSFP must not enable auto-negotiation */ 41162306a36Sopenharmony_ci if (hw->phy.media_type == ixgbe_media_type_fiber_qsfp) 41262306a36Sopenharmony_ci *autoneg = false; 41362306a36Sopenharmony_ci else 41462306a36Sopenharmony_ci *autoneg = true; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return 0; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/** 42162306a36Sopenharmony_ci * ixgbe_get_media_type_82599 - Get media type 42262306a36Sopenharmony_ci * @hw: pointer to hardware structure 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * Returns the media type (fiber, copper, backplane) 42562306a36Sopenharmony_ci **/ 42662306a36Sopenharmony_cistatic enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci /* Detect if there is a copper PHY attached. */ 42962306a36Sopenharmony_ci switch (hw->phy.type) { 43062306a36Sopenharmony_ci case ixgbe_phy_cu_unknown: 43162306a36Sopenharmony_ci case ixgbe_phy_tn: 43262306a36Sopenharmony_ci return ixgbe_media_type_copper; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci default: 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci switch (hw->device_id) { 43962306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_KX4: 44062306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_KX4_MEZZ: 44162306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_COMBO_BACKPLANE: 44262306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_KR: 44362306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_BACKPLANE_FCOE: 44462306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_XAUI_LOM: 44562306a36Sopenharmony_ci /* Default device ID is mezzanine card KX/KX4 */ 44662306a36Sopenharmony_ci return ixgbe_media_type_backplane; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_SFP: 44962306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_SFP_FCOE: 45062306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_SFP_EM: 45162306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_SFP_SF2: 45262306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_SFP_SF_QP: 45362306a36Sopenharmony_ci case IXGBE_DEV_ID_82599EN_SFP: 45462306a36Sopenharmony_ci return ixgbe_media_type_fiber; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_CX4: 45762306a36Sopenharmony_ci return ixgbe_media_type_cx4; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_T3_LOM: 46062306a36Sopenharmony_ci return ixgbe_media_type_copper; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_LS: 46362306a36Sopenharmony_ci return ixgbe_media_type_fiber_lco; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci case IXGBE_DEV_ID_82599_QSFP_SF_QP: 46662306a36Sopenharmony_ci return ixgbe_media_type_fiber_qsfp; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci default: 46962306a36Sopenharmony_ci return ixgbe_media_type_unknown; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/** 47462306a36Sopenharmony_ci * ixgbe_stop_mac_link_on_d3_82599 - Disables link on D3 47562306a36Sopenharmony_ci * @hw: pointer to hardware structure 47662306a36Sopenharmony_ci * 47762306a36Sopenharmony_ci * Disables link, should be called during D3 power down sequence. 47862306a36Sopenharmony_ci * 47962306a36Sopenharmony_ci **/ 48062306a36Sopenharmony_cistatic void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci u32 autoc2_reg; 48362306a36Sopenharmony_ci u16 ee_ctrl_2 = 0; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci hw->eeprom.ops.read(hw, IXGBE_EEPROM_CTRL_2, &ee_ctrl_2); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (!ixgbe_mng_present(hw) && !hw->wol_enabled && 48862306a36Sopenharmony_ci ee_ctrl_2 & IXGBE_EEPROM_CCD_BIT) { 48962306a36Sopenharmony_ci autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2); 49062306a36Sopenharmony_ci autoc2_reg |= IXGBE_AUTOC2_LINK_DISABLE_ON_D3_MASK; 49162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2_reg); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci/** 49662306a36Sopenharmony_ci * ixgbe_start_mac_link_82599 - Setup MAC link settings 49762306a36Sopenharmony_ci * @hw: pointer to hardware structure 49862306a36Sopenharmony_ci * @autoneg_wait_to_complete: true when waiting for completion is needed 49962306a36Sopenharmony_ci * 50062306a36Sopenharmony_ci * Configures link settings based on values in the ixgbe_hw struct. 50162306a36Sopenharmony_ci * Restarts the link. Performs autonegotiation if needed. 50262306a36Sopenharmony_ci **/ 50362306a36Sopenharmony_cistatic s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, 50462306a36Sopenharmony_ci bool autoneg_wait_to_complete) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci u32 autoc_reg; 50762306a36Sopenharmony_ci u32 links_reg; 50862306a36Sopenharmony_ci u32 i; 50962306a36Sopenharmony_ci s32 status = 0; 51062306a36Sopenharmony_ci bool got_lock = false; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { 51362306a36Sopenharmony_ci status = hw->mac.ops.acquire_swfw_sync(hw, 51462306a36Sopenharmony_ci IXGBE_GSSR_MAC_CSR_SM); 51562306a36Sopenharmony_ci if (status) 51662306a36Sopenharmony_ci return status; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci got_lock = true; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* Restart link */ 52262306a36Sopenharmony_ci ixgbe_reset_pipeline_82599(hw); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (got_lock) 52562306a36Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* Only poll for autoneg to complete if specified to do so */ 52862306a36Sopenharmony_ci if (autoneg_wait_to_complete) { 52962306a36Sopenharmony_ci autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); 53062306a36Sopenharmony_ci if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) == 53162306a36Sopenharmony_ci IXGBE_AUTOC_LMS_KX4_KX_KR || 53262306a36Sopenharmony_ci (autoc_reg & IXGBE_AUTOC_LMS_MASK) == 53362306a36Sopenharmony_ci IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || 53462306a36Sopenharmony_ci (autoc_reg & IXGBE_AUTOC_LMS_MASK) == 53562306a36Sopenharmony_ci IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { 53662306a36Sopenharmony_ci links_reg = 0; /* Just in case Autoneg time = 0 */ 53762306a36Sopenharmony_ci for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) { 53862306a36Sopenharmony_ci links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); 53962306a36Sopenharmony_ci if (links_reg & IXGBE_LINKS_KX_AN_COMP) 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci msleep(100); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) { 54462306a36Sopenharmony_ci status = -EIO; 54562306a36Sopenharmony_ci hw_dbg(hw, "Autoneg did not complete.\n"); 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* Add delay to filter out noises during initial link setup */ 55162306a36Sopenharmony_ci msleep(50); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci return status; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci/** 55762306a36Sopenharmony_ci * ixgbe_disable_tx_laser_multispeed_fiber - Disable Tx laser 55862306a36Sopenharmony_ci * @hw: pointer to hardware structure 55962306a36Sopenharmony_ci * 56062306a36Sopenharmony_ci * The base drivers may require better control over SFP+ module 56162306a36Sopenharmony_ci * PHY states. This includes selectively shutting down the Tx 56262306a36Sopenharmony_ci * laser on the PHY, effectively halting physical link. 56362306a36Sopenharmony_ci **/ 56462306a36Sopenharmony_cistatic void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* Blocked by MNG FW so bail */ 56962306a36Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 57062306a36Sopenharmony_ci return; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Disable tx laser; allow 100us to go dark per spec */ 57362306a36Sopenharmony_ci esdp_reg |= IXGBE_ESDP_SDP3; 57462306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); 57562306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 57662306a36Sopenharmony_ci udelay(100); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci/** 58062306a36Sopenharmony_ci * ixgbe_enable_tx_laser_multispeed_fiber - Enable Tx laser 58162306a36Sopenharmony_ci * @hw: pointer to hardware structure 58262306a36Sopenharmony_ci * 58362306a36Sopenharmony_ci * The base drivers may require better control over SFP+ module 58462306a36Sopenharmony_ci * PHY states. This includes selectively turning on the Tx 58562306a36Sopenharmony_ci * laser on the PHY, effectively starting physical link. 58662306a36Sopenharmony_ci **/ 58762306a36Sopenharmony_cistatic void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Enable tx laser; allow 100ms to light up */ 59262306a36Sopenharmony_ci esdp_reg &= ~IXGBE_ESDP_SDP3; 59362306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); 59462306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 59562306a36Sopenharmony_ci msleep(100); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/** 59962306a36Sopenharmony_ci * ixgbe_flap_tx_laser_multispeed_fiber - Flap Tx laser 60062306a36Sopenharmony_ci * @hw: pointer to hardware structure 60162306a36Sopenharmony_ci * 60262306a36Sopenharmony_ci * When the driver changes the link speeds that it can support, 60362306a36Sopenharmony_ci * it sets autotry_restart to true to indicate that we need to 60462306a36Sopenharmony_ci * initiate a new autotry session with the link partner. To do 60562306a36Sopenharmony_ci * so, we set the speed then disable and re-enable the tx laser, to 60662306a36Sopenharmony_ci * alert the link partner that it also needs to restart autotry on its 60762306a36Sopenharmony_ci * end. This is consistent with true clause 37 autoneg, which also 60862306a36Sopenharmony_ci * involves a loss of signal. 60962306a36Sopenharmony_ci **/ 61062306a36Sopenharmony_cistatic void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci /* Blocked by MNG FW so bail */ 61362306a36Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 61462306a36Sopenharmony_ci return; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (hw->mac.autotry_restart) { 61762306a36Sopenharmony_ci ixgbe_disable_tx_laser_multispeed_fiber(hw); 61862306a36Sopenharmony_ci ixgbe_enable_tx_laser_multispeed_fiber(hw); 61962306a36Sopenharmony_ci hw->mac.autotry_restart = false; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci/** 62462306a36Sopenharmony_ci * ixgbe_set_hard_rate_select_speed - Set module link speed 62562306a36Sopenharmony_ci * @hw: pointer to hardware structure 62662306a36Sopenharmony_ci * @speed: link speed to set 62762306a36Sopenharmony_ci * 62862306a36Sopenharmony_ci * Set module link speed via RS0/RS1 rate select pins. 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_cistatic void 63162306a36Sopenharmony_ciixgbe_set_hard_rate_select_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci switch (speed) { 63662306a36Sopenharmony_ci case IXGBE_LINK_SPEED_10GB_FULL: 63762306a36Sopenharmony_ci esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5); 63862306a36Sopenharmony_ci break; 63962306a36Sopenharmony_ci case IXGBE_LINK_SPEED_1GB_FULL: 64062306a36Sopenharmony_ci esdp_reg &= ~IXGBE_ESDP_SDP5; 64162306a36Sopenharmony_ci esdp_reg |= IXGBE_ESDP_SDP5_DIR; 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci default: 64462306a36Sopenharmony_ci hw_dbg(hw, "Invalid fixed module speed\n"); 64562306a36Sopenharmony_ci return; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); 64962306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci/** 65362306a36Sopenharmony_ci * ixgbe_setup_mac_link_smartspeed - Set MAC link speed using SmartSpeed 65462306a36Sopenharmony_ci * @hw: pointer to hardware structure 65562306a36Sopenharmony_ci * @speed: new link speed 65662306a36Sopenharmony_ci * @autoneg_wait_to_complete: true when waiting for completion is needed 65762306a36Sopenharmony_ci * 65862306a36Sopenharmony_ci * Implements the Intel SmartSpeed algorithm. 65962306a36Sopenharmony_ci **/ 66062306a36Sopenharmony_cistatic s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, 66162306a36Sopenharmony_ci ixgbe_link_speed speed, 66262306a36Sopenharmony_ci bool autoneg_wait_to_complete) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci s32 status = 0; 66562306a36Sopenharmony_ci ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN; 66662306a36Sopenharmony_ci s32 i, j; 66762306a36Sopenharmony_ci bool link_up = false; 66862306a36Sopenharmony_ci u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* Set autoneg_advertised value based on input link speed */ 67162306a36Sopenharmony_ci hw->phy.autoneg_advertised = 0; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10GB_FULL) 67462306a36Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_1GB_FULL) 67762306a36Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_100_FULL) 68062306a36Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci /* 68362306a36Sopenharmony_ci * Implement Intel SmartSpeed algorithm. SmartSpeed will reduce the 68462306a36Sopenharmony_ci * autoneg advertisement if link is unable to be established at the 68562306a36Sopenharmony_ci * highest negotiated rate. This can sometimes happen due to integrity 68662306a36Sopenharmony_ci * issues with the physical media connection. 68762306a36Sopenharmony_ci */ 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* First, try to get link with full advertisement */ 69062306a36Sopenharmony_ci hw->phy.smart_speed_active = false; 69162306a36Sopenharmony_ci for (j = 0; j < IXGBE_SMARTSPEED_MAX_RETRIES; j++) { 69262306a36Sopenharmony_ci status = ixgbe_setup_mac_link_82599(hw, speed, 69362306a36Sopenharmony_ci autoneg_wait_to_complete); 69462306a36Sopenharmony_ci if (status != 0) 69562306a36Sopenharmony_ci goto out; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* 69862306a36Sopenharmony_ci * Wait for the controller to acquire link. Per IEEE 802.3ap, 69962306a36Sopenharmony_ci * Section 73.10.2, we may have to wait up to 500ms if KR is 70062306a36Sopenharmony_ci * attempted, or 200ms if KX/KX4/BX/BX4 is attempted, per 70162306a36Sopenharmony_ci * Table 9 in the AN MAS. 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 70462306a36Sopenharmony_ci mdelay(100); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* If we have link, just jump out */ 70762306a36Sopenharmony_ci status = hw->mac.ops.check_link(hw, &link_speed, 70862306a36Sopenharmony_ci &link_up, false); 70962306a36Sopenharmony_ci if (status != 0) 71062306a36Sopenharmony_ci goto out; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci if (link_up) 71362306a36Sopenharmony_ci goto out; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* 71862306a36Sopenharmony_ci * We didn't get link. If we advertised KR plus one of KX4/KX 71962306a36Sopenharmony_ci * (or BX4/BX), then disable KR and try again. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci if (((autoc_reg & IXGBE_AUTOC_KR_SUPP) == 0) || 72262306a36Sopenharmony_ci ((autoc_reg & IXGBE_AUTOC_KX4_KX_SUPP_MASK) == 0)) 72362306a36Sopenharmony_ci goto out; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* Turn SmartSpeed on to disable KR support */ 72662306a36Sopenharmony_ci hw->phy.smart_speed_active = true; 72762306a36Sopenharmony_ci status = ixgbe_setup_mac_link_82599(hw, speed, 72862306a36Sopenharmony_ci autoneg_wait_to_complete); 72962306a36Sopenharmony_ci if (status != 0) 73062306a36Sopenharmony_ci goto out; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* 73362306a36Sopenharmony_ci * Wait for the controller to acquire link. 600ms will allow for 73462306a36Sopenharmony_ci * the AN link_fail_inhibit_timer as well for multiple cycles of 73562306a36Sopenharmony_ci * parallel detect, both 10g and 1g. This allows for the maximum 73662306a36Sopenharmony_ci * connect attempts as defined in the AN MAS table 73-7. 73762306a36Sopenharmony_ci */ 73862306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 73962306a36Sopenharmony_ci mdelay(100); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* If we have link, just jump out */ 74262306a36Sopenharmony_ci status = hw->mac.ops.check_link(hw, &link_speed, 74362306a36Sopenharmony_ci &link_up, false); 74462306a36Sopenharmony_ci if (status != 0) 74562306a36Sopenharmony_ci goto out; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (link_up) 74862306a36Sopenharmony_ci goto out; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* We didn't get link. Turn SmartSpeed back off. */ 75262306a36Sopenharmony_ci hw->phy.smart_speed_active = false; 75362306a36Sopenharmony_ci status = ixgbe_setup_mac_link_82599(hw, speed, 75462306a36Sopenharmony_ci autoneg_wait_to_complete); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ciout: 75762306a36Sopenharmony_ci if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL)) 75862306a36Sopenharmony_ci hw_dbg(hw, "Smartspeed has downgraded the link speed from the maximum advertised\n"); 75962306a36Sopenharmony_ci return status; 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci/** 76362306a36Sopenharmony_ci * ixgbe_setup_mac_link_82599 - Set MAC link speed 76462306a36Sopenharmony_ci * @hw: pointer to hardware structure 76562306a36Sopenharmony_ci * @speed: new link speed 76662306a36Sopenharmony_ci * @autoneg_wait_to_complete: true when waiting for completion is needed 76762306a36Sopenharmony_ci * 76862306a36Sopenharmony_ci * Set the link speed in the AUTOC register and restarts link. 76962306a36Sopenharmony_ci **/ 77062306a36Sopenharmony_cistatic s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, 77162306a36Sopenharmony_ci ixgbe_link_speed speed, 77262306a36Sopenharmony_ci bool autoneg_wait_to_complete) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci bool autoneg = false; 77562306a36Sopenharmony_ci s32 status; 77662306a36Sopenharmony_ci u32 pma_pmd_1g, link_mode, links_reg, i; 77762306a36Sopenharmony_ci u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); 77862306a36Sopenharmony_ci u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; 77962306a36Sopenharmony_ci ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* holds the value of AUTOC register at this current point in time */ 78262306a36Sopenharmony_ci u32 current_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); 78362306a36Sopenharmony_ci /* holds the cached value of AUTOC register */ 78462306a36Sopenharmony_ci u32 orig_autoc = 0; 78562306a36Sopenharmony_ci /* temporary variable used for comparison purposes */ 78662306a36Sopenharmony_ci u32 autoc = current_autoc; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* Check to see if speed passed in is supported. */ 78962306a36Sopenharmony_ci status = hw->mac.ops.get_link_capabilities(hw, &link_capabilities, 79062306a36Sopenharmony_ci &autoneg); 79162306a36Sopenharmony_ci if (status) 79262306a36Sopenharmony_ci return status; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci speed &= link_capabilities; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (speed == IXGBE_LINK_SPEED_UNKNOWN) 79762306a36Sopenharmony_ci return -EINVAL; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/ 80062306a36Sopenharmony_ci if (hw->mac.orig_link_settings_stored) 80162306a36Sopenharmony_ci orig_autoc = hw->mac.orig_autoc; 80262306a36Sopenharmony_ci else 80362306a36Sopenharmony_ci orig_autoc = autoc; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci link_mode = autoc & IXGBE_AUTOC_LMS_MASK; 80662306a36Sopenharmony_ci pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || 80962306a36Sopenharmony_ci link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || 81062306a36Sopenharmony_ci link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { 81162306a36Sopenharmony_ci /* Set KX4/KX/KR support according to speed requested */ 81262306a36Sopenharmony_ci autoc &= ~(IXGBE_AUTOC_KX4_KX_SUPP_MASK | IXGBE_AUTOC_KR_SUPP); 81362306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10GB_FULL) { 81462306a36Sopenharmony_ci if (orig_autoc & IXGBE_AUTOC_KX4_SUPP) 81562306a36Sopenharmony_ci autoc |= IXGBE_AUTOC_KX4_SUPP; 81662306a36Sopenharmony_ci if ((orig_autoc & IXGBE_AUTOC_KR_SUPP) && 81762306a36Sopenharmony_ci (hw->phy.smart_speed_active == false)) 81862306a36Sopenharmony_ci autoc |= IXGBE_AUTOC_KR_SUPP; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_1GB_FULL) 82162306a36Sopenharmony_ci autoc |= IXGBE_AUTOC_KX_SUPP; 82262306a36Sopenharmony_ci } else if ((pma_pmd_1g == IXGBE_AUTOC_1G_SFI) && 82362306a36Sopenharmony_ci (link_mode == IXGBE_AUTOC_LMS_1G_LINK_NO_AN || 82462306a36Sopenharmony_ci link_mode == IXGBE_AUTOC_LMS_1G_AN)) { 82562306a36Sopenharmony_ci /* Switch from 1G SFI to 10G SFI if requested */ 82662306a36Sopenharmony_ci if ((speed == IXGBE_LINK_SPEED_10GB_FULL) && 82762306a36Sopenharmony_ci (pma_pmd_10g_serial == IXGBE_AUTOC2_10G_SFI)) { 82862306a36Sopenharmony_ci autoc &= ~IXGBE_AUTOC_LMS_MASK; 82962306a36Sopenharmony_ci autoc |= IXGBE_AUTOC_LMS_10G_SERIAL; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci } else if ((pma_pmd_10g_serial == IXGBE_AUTOC2_10G_SFI) && 83262306a36Sopenharmony_ci (link_mode == IXGBE_AUTOC_LMS_10G_SERIAL)) { 83362306a36Sopenharmony_ci /* Switch from 10G SFI to 1G SFI if requested */ 83462306a36Sopenharmony_ci if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && 83562306a36Sopenharmony_ci (pma_pmd_1g == IXGBE_AUTOC_1G_SFI)) { 83662306a36Sopenharmony_ci autoc &= ~IXGBE_AUTOC_LMS_MASK; 83762306a36Sopenharmony_ci if (autoneg) 83862306a36Sopenharmony_ci autoc |= IXGBE_AUTOC_LMS_1G_AN; 83962306a36Sopenharmony_ci else 84062306a36Sopenharmony_ci autoc |= IXGBE_AUTOC_LMS_1G_LINK_NO_AN; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (autoc != current_autoc) { 84562306a36Sopenharmony_ci /* Restart link */ 84662306a36Sopenharmony_ci status = hw->mac.ops.prot_autoc_write(hw, autoc, false); 84762306a36Sopenharmony_ci if (status) 84862306a36Sopenharmony_ci return status; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* Only poll for autoneg to complete if specified to do so */ 85162306a36Sopenharmony_ci if (autoneg_wait_to_complete) { 85262306a36Sopenharmony_ci if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || 85362306a36Sopenharmony_ci link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || 85462306a36Sopenharmony_ci link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { 85562306a36Sopenharmony_ci links_reg = 0; /*Just in case Autoneg time=0*/ 85662306a36Sopenharmony_ci for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) { 85762306a36Sopenharmony_ci links_reg = 85862306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_LINKS); 85962306a36Sopenharmony_ci if (links_reg & IXGBE_LINKS_KX_AN_COMP) 86062306a36Sopenharmony_ci break; 86162306a36Sopenharmony_ci msleep(100); 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) { 86462306a36Sopenharmony_ci status = -EIO; 86562306a36Sopenharmony_ci hw_dbg(hw, "Autoneg did not complete.\n"); 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* Add delay to filter out noises during initial link setup */ 87162306a36Sopenharmony_ci msleep(50); 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci return status; 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci/** 87862306a36Sopenharmony_ci * ixgbe_setup_copper_link_82599 - Set the PHY autoneg advertised field 87962306a36Sopenharmony_ci * @hw: pointer to hardware structure 88062306a36Sopenharmony_ci * @speed: new link speed 88162306a36Sopenharmony_ci * @autoneg_wait_to_complete: true if waiting is needed to complete 88262306a36Sopenharmony_ci * 88362306a36Sopenharmony_ci * Restarts link on PHY and MAC based on settings passed in. 88462306a36Sopenharmony_ci **/ 88562306a36Sopenharmony_cistatic s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, 88662306a36Sopenharmony_ci ixgbe_link_speed speed, 88762306a36Sopenharmony_ci bool autoneg_wait_to_complete) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci s32 status; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* Setup the PHY according to input speed */ 89262306a36Sopenharmony_ci status = hw->phy.ops.setup_link_speed(hw, speed, 89362306a36Sopenharmony_ci autoneg_wait_to_complete); 89462306a36Sopenharmony_ci /* Set up MAC */ 89562306a36Sopenharmony_ci ixgbe_start_mac_link_82599(hw, autoneg_wait_to_complete); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci return status; 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/** 90162306a36Sopenharmony_ci * ixgbe_reset_hw_82599 - Perform hardware reset 90262306a36Sopenharmony_ci * @hw: pointer to hardware structure 90362306a36Sopenharmony_ci * 90462306a36Sopenharmony_ci * Resets the hardware by resetting the transmit and receive units, masks 90562306a36Sopenharmony_ci * and clears all interrupts, perform a PHY reset, and perform a link (MAC) 90662306a36Sopenharmony_ci * reset. 90762306a36Sopenharmony_ci **/ 90862306a36Sopenharmony_cistatic s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci ixgbe_link_speed link_speed; 91162306a36Sopenharmony_ci s32 status; 91262306a36Sopenharmony_ci u32 ctrl, i, autoc, autoc2; 91362306a36Sopenharmony_ci u32 curr_lms; 91462306a36Sopenharmony_ci bool link_up = false; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* Call adapter stop to disable tx/rx and clear interrupts */ 91762306a36Sopenharmony_ci status = hw->mac.ops.stop_adapter(hw); 91862306a36Sopenharmony_ci if (status) 91962306a36Sopenharmony_ci return status; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* flush pending Tx transactions */ 92262306a36Sopenharmony_ci ixgbe_clear_tx_pending(hw); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* PHY ops must be identified and initialized prior to reset */ 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* Identify PHY and related function pointers */ 92762306a36Sopenharmony_ci status = hw->phy.ops.init(hw); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (status == -EOPNOTSUPP) 93062306a36Sopenharmony_ci return status; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci /* Setup SFP module if there is one present. */ 93362306a36Sopenharmony_ci if (hw->phy.sfp_setup_needed) { 93462306a36Sopenharmony_ci status = hw->mac.ops.setup_sfp(hw); 93562306a36Sopenharmony_ci hw->phy.sfp_setup_needed = false; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (status == -EOPNOTSUPP) 93962306a36Sopenharmony_ci return status; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* Reset PHY */ 94262306a36Sopenharmony_ci if (hw->phy.reset_disable == false && hw->phy.ops.reset != NULL) 94362306a36Sopenharmony_ci hw->phy.ops.reset(hw); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* remember AUTOC from before we reset */ 94662306a36Sopenharmony_ci curr_lms = IXGBE_READ_REG(hw, IXGBE_AUTOC) & IXGBE_AUTOC_LMS_MASK; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cimac_reset_top: 94962306a36Sopenharmony_ci /* 95062306a36Sopenharmony_ci * Issue global reset to the MAC. Needs to be SW reset if link is up. 95162306a36Sopenharmony_ci * If link reset is used when link is up, it might reset the PHY when 95262306a36Sopenharmony_ci * mng is using it. If link is down or the flag to force full link 95362306a36Sopenharmony_ci * reset is set, then perform link reset. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_ci ctrl = IXGBE_CTRL_LNK_RST; 95662306a36Sopenharmony_ci if (!hw->force_full_reset) { 95762306a36Sopenharmony_ci hw->mac.ops.check_link(hw, &link_speed, &link_up, false); 95862306a36Sopenharmony_ci if (link_up) 95962306a36Sopenharmony_ci ctrl = IXGBE_CTRL_RST; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL); 96362306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl); 96462306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 96562306a36Sopenharmony_ci usleep_range(1000, 1200); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* Poll for reset bit to self-clear indicating reset is complete */ 96862306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 96962306a36Sopenharmony_ci ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); 97062306a36Sopenharmony_ci if (!(ctrl & IXGBE_CTRL_RST_MASK)) 97162306a36Sopenharmony_ci break; 97262306a36Sopenharmony_ci udelay(1); 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (ctrl & IXGBE_CTRL_RST_MASK) { 97662306a36Sopenharmony_ci status = -EIO; 97762306a36Sopenharmony_ci hw_dbg(hw, "Reset polling failed to complete.\n"); 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci msleep(50); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* 98362306a36Sopenharmony_ci * Double resets are required for recovery from certain error 98462306a36Sopenharmony_ci * conditions. Between resets, it is necessary to stall to allow time 98562306a36Sopenharmony_ci * for any pending HW events to complete. 98662306a36Sopenharmony_ci */ 98762306a36Sopenharmony_ci if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) { 98862306a36Sopenharmony_ci hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED; 98962306a36Sopenharmony_ci goto mac_reset_top; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* 99362306a36Sopenharmony_ci * Store the original AUTOC/AUTOC2 values if they have not been 99462306a36Sopenharmony_ci * stored off yet. Otherwise restore the stored original 99562306a36Sopenharmony_ci * values since the reset operation sets back to defaults. 99662306a36Sopenharmony_ci */ 99762306a36Sopenharmony_ci autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); 99862306a36Sopenharmony_ci autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* Enable link if disabled in NVM */ 100162306a36Sopenharmony_ci if (autoc2 & IXGBE_AUTOC2_LINK_DISABLE_MASK) { 100262306a36Sopenharmony_ci autoc2 &= ~IXGBE_AUTOC2_LINK_DISABLE_MASK; 100362306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2); 100462306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (hw->mac.orig_link_settings_stored == false) { 100862306a36Sopenharmony_ci hw->mac.orig_autoc = autoc; 100962306a36Sopenharmony_ci hw->mac.orig_autoc2 = autoc2; 101062306a36Sopenharmony_ci hw->mac.orig_link_settings_stored = true; 101162306a36Sopenharmony_ci } else { 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* If MNG FW is running on a multi-speed device that 101462306a36Sopenharmony_ci * doesn't autoneg with out driver support we need to 101562306a36Sopenharmony_ci * leave LMS in the state it was before we MAC reset. 101662306a36Sopenharmony_ci * Likewise if we support WoL we don't want change the 101762306a36Sopenharmony_ci * LMS state either. 101862306a36Sopenharmony_ci */ 101962306a36Sopenharmony_ci if ((hw->phy.multispeed_fiber && ixgbe_mng_enabled(hw)) || 102062306a36Sopenharmony_ci hw->wol_enabled) 102162306a36Sopenharmony_ci hw->mac.orig_autoc = 102262306a36Sopenharmony_ci (hw->mac.orig_autoc & ~IXGBE_AUTOC_LMS_MASK) | 102362306a36Sopenharmony_ci curr_lms; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (autoc != hw->mac.orig_autoc) { 102662306a36Sopenharmony_ci status = hw->mac.ops.prot_autoc_write(hw, 102762306a36Sopenharmony_ci hw->mac.orig_autoc, 102862306a36Sopenharmony_ci false); 102962306a36Sopenharmony_ci if (status) 103062306a36Sopenharmony_ci return status; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) != 103462306a36Sopenharmony_ci (hw->mac.orig_autoc2 & IXGBE_AUTOC2_UPPER_MASK)) { 103562306a36Sopenharmony_ci autoc2 &= ~IXGBE_AUTOC2_UPPER_MASK; 103662306a36Sopenharmony_ci autoc2 |= (hw->mac.orig_autoc2 & 103762306a36Sopenharmony_ci IXGBE_AUTOC2_UPPER_MASK); 103862306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2); 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci /* Store the permanent mac address */ 104362306a36Sopenharmony_ci hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci /* 104662306a36Sopenharmony_ci * Store MAC address from RAR0, clear receive address registers, and 104762306a36Sopenharmony_ci * clear the multicast table. Also reset num_rar_entries to 128, 104862306a36Sopenharmony_ci * since we modify this value when programming the SAN MAC address. 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_ci hw->mac.num_rar_entries = IXGBE_82599_RAR_ENTRIES; 105162306a36Sopenharmony_ci hw->mac.ops.init_rx_addrs(hw); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* Store the permanent SAN mac address */ 105462306a36Sopenharmony_ci hw->mac.ops.get_san_mac_addr(hw, hw->mac.san_addr); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* Add the SAN MAC address to the RAR only if it's a valid address */ 105762306a36Sopenharmony_ci if (is_valid_ether_addr(hw->mac.san_addr)) { 105862306a36Sopenharmony_ci /* Save the SAN MAC RAR index */ 105962306a36Sopenharmony_ci hw->mac.san_mac_rar_index = hw->mac.num_rar_entries - 1; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci hw->mac.ops.set_rar(hw, hw->mac.san_mac_rar_index, 106262306a36Sopenharmony_ci hw->mac.san_addr, 0, IXGBE_RAH_AV); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci /* clear VMDq pool/queue selection for this RAR */ 106562306a36Sopenharmony_ci hw->mac.ops.clear_vmdq(hw, hw->mac.san_mac_rar_index, 106662306a36Sopenharmony_ci IXGBE_CLEAR_VMDQ_ALL); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci /* Reserve the last RAR for the SAN MAC address */ 106962306a36Sopenharmony_ci hw->mac.num_rar_entries--; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci /* Store the alternative WWNN/WWPN prefix */ 107362306a36Sopenharmony_ci hw->mac.ops.get_wwn_prefix(hw, &hw->mac.wwnn_prefix, 107462306a36Sopenharmony_ci &hw->mac.wwpn_prefix); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci return status; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci/** 108062306a36Sopenharmony_ci * ixgbe_fdir_check_cmd_complete - poll to check whether FDIRCMD is complete 108162306a36Sopenharmony_ci * @hw: pointer to hardware structure 108262306a36Sopenharmony_ci * @fdircmd: current value of FDIRCMD register 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_cistatic s32 ixgbe_fdir_check_cmd_complete(struct ixgbe_hw *hw, u32 *fdircmd) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci int i; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci for (i = 0; i < IXGBE_FDIRCMD_CMD_POLL; i++) { 108962306a36Sopenharmony_ci *fdircmd = IXGBE_READ_REG(hw, IXGBE_FDIRCMD); 109062306a36Sopenharmony_ci if (!(*fdircmd & IXGBE_FDIRCMD_CMD_MASK)) 109162306a36Sopenharmony_ci return 0; 109262306a36Sopenharmony_ci udelay(10); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return -EIO; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci/** 109962306a36Sopenharmony_ci * ixgbe_reinit_fdir_tables_82599 - Reinitialize Flow Director tables. 110062306a36Sopenharmony_ci * @hw: pointer to hardware structure 110162306a36Sopenharmony_ci **/ 110262306a36Sopenharmony_cis32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci int i; 110562306a36Sopenharmony_ci u32 fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL); 110662306a36Sopenharmony_ci u32 fdircmd; 110762306a36Sopenharmony_ci s32 err; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci fdirctrl &= ~IXGBE_FDIRCTRL_INIT_DONE; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci /* 111262306a36Sopenharmony_ci * Before starting reinitialization process, 111362306a36Sopenharmony_ci * FDIRCMD.CMD must be zero. 111462306a36Sopenharmony_ci */ 111562306a36Sopenharmony_ci err = ixgbe_fdir_check_cmd_complete(hw, &fdircmd); 111662306a36Sopenharmony_ci if (err) { 111762306a36Sopenharmony_ci hw_dbg(hw, "Flow Director previous command did not complete, aborting table re-initialization.\n"); 111862306a36Sopenharmony_ci return err; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRFREE, 0); 112262306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 112362306a36Sopenharmony_ci /* 112462306a36Sopenharmony_ci * 82599 adapters flow director init flow cannot be restarted, 112562306a36Sopenharmony_ci * Workaround 82599 silicon errata by performing the following steps 112662306a36Sopenharmony_ci * before re-writing the FDIRCTRL control register with the same value. 112762306a36Sopenharmony_ci * - write 1 to bit 8 of FDIRCMD register & 112862306a36Sopenharmony_ci * - write 0 to bit 8 of FDIRCMD register 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, 113162306a36Sopenharmony_ci (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) | 113262306a36Sopenharmony_ci IXGBE_FDIRCMD_CLEARHT)); 113362306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 113462306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, 113562306a36Sopenharmony_ci (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) & 113662306a36Sopenharmony_ci ~IXGBE_FDIRCMD_CLEARHT)); 113762306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 113862306a36Sopenharmony_ci /* 113962306a36Sopenharmony_ci * Clear FDIR Hash register to clear any leftover hashes 114062306a36Sopenharmony_ci * waiting to be programmed. 114162306a36Sopenharmony_ci */ 114262306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, 0x00); 114362306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); 114662306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci /* Poll init-done after we write FDIRCTRL register */ 114962306a36Sopenharmony_ci for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { 115062306a36Sopenharmony_ci if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & 115162306a36Sopenharmony_ci IXGBE_FDIRCTRL_INIT_DONE) 115262306a36Sopenharmony_ci break; 115362306a36Sopenharmony_ci usleep_range(1000, 2000); 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci if (i >= IXGBE_FDIR_INIT_DONE_POLL) { 115662306a36Sopenharmony_ci hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); 115762306a36Sopenharmony_ci return -EIO; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci /* Clear FDIR statistics registers (read to clear) */ 116162306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_FDIRUSTAT); 116262306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_FDIRFSTAT); 116362306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_FDIRMATCH); 116462306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_FDIRMISS); 116562306a36Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_FDIRLEN); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci return 0; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci/** 117162306a36Sopenharmony_ci * ixgbe_fdir_enable_82599 - Initialize Flow Director control registers 117262306a36Sopenharmony_ci * @hw: pointer to hardware structure 117362306a36Sopenharmony_ci * @fdirctrl: value to write to flow director control register 117462306a36Sopenharmony_ci **/ 117562306a36Sopenharmony_cistatic void ixgbe_fdir_enable_82599(struct ixgbe_hw *hw, u32 fdirctrl) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci int i; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci /* Prime the keys for hashing */ 118062306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, IXGBE_ATR_BUCKET_HASH_KEY); 118162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, IXGBE_ATR_SIGNATURE_HASH_KEY); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci /* 118462306a36Sopenharmony_ci * Poll init-done after we write the register. Estimated times: 118562306a36Sopenharmony_ci * 10G: PBALLOC = 11b, timing is 60us 118662306a36Sopenharmony_ci * 1G: PBALLOC = 11b, timing is 600us 118762306a36Sopenharmony_ci * 100M: PBALLOC = 11b, timing is 6ms 118862306a36Sopenharmony_ci * 118962306a36Sopenharmony_ci * Multiple these timings by 4 if under full Rx load 119062306a36Sopenharmony_ci * 119162306a36Sopenharmony_ci * So we'll poll for IXGBE_FDIR_INIT_DONE_POLL times, sleeping for 119262306a36Sopenharmony_ci * 1 msec per poll time. If we're at line rate and drop to 100M, then 119362306a36Sopenharmony_ci * this might not finish in our poll time, but we can live with that 119462306a36Sopenharmony_ci * for now. 119562306a36Sopenharmony_ci */ 119662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); 119762306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 119862306a36Sopenharmony_ci for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { 119962306a36Sopenharmony_ci if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & 120062306a36Sopenharmony_ci IXGBE_FDIRCTRL_INIT_DONE) 120162306a36Sopenharmony_ci break; 120262306a36Sopenharmony_ci usleep_range(1000, 2000); 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (i >= IXGBE_FDIR_INIT_DONE_POLL) 120662306a36Sopenharmony_ci hw_dbg(hw, "Flow Director poll time exceeded!\n"); 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci/** 121062306a36Sopenharmony_ci * ixgbe_init_fdir_signature_82599 - Initialize Flow Director signature filters 121162306a36Sopenharmony_ci * @hw: pointer to hardware structure 121262306a36Sopenharmony_ci * @fdirctrl: value to write to flow director control register, initially 121362306a36Sopenharmony_ci * contains just the value of the Rx packet buffer allocation 121462306a36Sopenharmony_ci **/ 121562306a36Sopenharmony_cis32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 fdirctrl) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci /* 121862306a36Sopenharmony_ci * Continue setup of fdirctrl register bits: 121962306a36Sopenharmony_ci * Move the flexible bytes to use the ethertype - shift 6 words 122062306a36Sopenharmony_ci * Set the maximum length per hash bucket to 0xA filters 122162306a36Sopenharmony_ci * Send interrupt when 64 filters are left 122262306a36Sopenharmony_ci */ 122362306a36Sopenharmony_ci fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT) | 122462306a36Sopenharmony_ci (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT) | 122562306a36Sopenharmony_ci (4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci /* write hashes and fdirctrl register, poll for completion */ 122862306a36Sopenharmony_ci ixgbe_fdir_enable_82599(hw, fdirctrl); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci return 0; 123162306a36Sopenharmony_ci} 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci/** 123462306a36Sopenharmony_ci * ixgbe_init_fdir_perfect_82599 - Initialize Flow Director perfect filters 123562306a36Sopenharmony_ci * @hw: pointer to hardware structure 123662306a36Sopenharmony_ci * @fdirctrl: value to write to flow director control register, initially 123762306a36Sopenharmony_ci * contains just the value of the Rx packet buffer allocation 123862306a36Sopenharmony_ci **/ 123962306a36Sopenharmony_cis32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 fdirctrl) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci /* 124262306a36Sopenharmony_ci * Continue setup of fdirctrl register bits: 124362306a36Sopenharmony_ci * Turn perfect match filtering on 124462306a36Sopenharmony_ci * Initialize the drop queue 124562306a36Sopenharmony_ci * Move the flexible bytes to use the ethertype - shift 6 words 124662306a36Sopenharmony_ci * Set the maximum length per hash bucket to 0xA filters 124762306a36Sopenharmony_ci * Send interrupt when 64 (0x4 * 16) filters are left 124862306a36Sopenharmony_ci */ 124962306a36Sopenharmony_ci fdirctrl |= IXGBE_FDIRCTRL_PERFECT_MATCH | 125062306a36Sopenharmony_ci (IXGBE_FDIR_DROP_QUEUE << IXGBE_FDIRCTRL_DROP_Q_SHIFT) | 125162306a36Sopenharmony_ci (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT) | 125262306a36Sopenharmony_ci (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT) | 125362306a36Sopenharmony_ci (4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci /* write hashes and fdirctrl register, poll for completion */ 125662306a36Sopenharmony_ci ixgbe_fdir_enable_82599(hw, fdirctrl); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci return 0; 125962306a36Sopenharmony_ci} 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci/* 126262306a36Sopenharmony_ci * These defines allow us to quickly generate all of the necessary instructions 126362306a36Sopenharmony_ci * in the function below by simply calling out IXGBE_COMPUTE_SIG_HASH_ITERATION 126462306a36Sopenharmony_ci * for values 0 through 15 126562306a36Sopenharmony_ci */ 126662306a36Sopenharmony_ci#define IXGBE_ATR_COMMON_HASH_KEY \ 126762306a36Sopenharmony_ci (IXGBE_ATR_BUCKET_HASH_KEY & IXGBE_ATR_SIGNATURE_HASH_KEY) 126862306a36Sopenharmony_ci#define IXGBE_COMPUTE_SIG_HASH_ITERATION(_n) \ 126962306a36Sopenharmony_cido { \ 127062306a36Sopenharmony_ci u32 n = (_n); \ 127162306a36Sopenharmony_ci if (IXGBE_ATR_COMMON_HASH_KEY & BIT(n)) \ 127262306a36Sopenharmony_ci common_hash ^= lo_hash_dword >> n; \ 127362306a36Sopenharmony_ci else if (IXGBE_ATR_BUCKET_HASH_KEY & BIT(n)) \ 127462306a36Sopenharmony_ci bucket_hash ^= lo_hash_dword >> n; \ 127562306a36Sopenharmony_ci else if (IXGBE_ATR_SIGNATURE_HASH_KEY & BIT(n)) \ 127662306a36Sopenharmony_ci sig_hash ^= lo_hash_dword << (16 - n); \ 127762306a36Sopenharmony_ci if (IXGBE_ATR_COMMON_HASH_KEY & BIT(n + 16)) \ 127862306a36Sopenharmony_ci common_hash ^= hi_hash_dword >> n; \ 127962306a36Sopenharmony_ci else if (IXGBE_ATR_BUCKET_HASH_KEY & BIT(n + 16)) \ 128062306a36Sopenharmony_ci bucket_hash ^= hi_hash_dword >> n; \ 128162306a36Sopenharmony_ci else if (IXGBE_ATR_SIGNATURE_HASH_KEY & BIT(n + 16)) \ 128262306a36Sopenharmony_ci sig_hash ^= hi_hash_dword << (16 - n); \ 128362306a36Sopenharmony_ci} while (0) 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci/** 128662306a36Sopenharmony_ci * ixgbe_atr_compute_sig_hash_82599 - Compute the signature hash 128762306a36Sopenharmony_ci * @input: input bitstream to compute the hash on 128862306a36Sopenharmony_ci * @common: compressed common input dword 128962306a36Sopenharmony_ci * 129062306a36Sopenharmony_ci * This function is almost identical to the function above but contains 129162306a36Sopenharmony_ci * several optimizations such as unwinding all of the loops, letting the 129262306a36Sopenharmony_ci * compiler work out all of the conditional ifs since the keys are static 129362306a36Sopenharmony_ci * defines, and computing two keys at once since the hashed dword stream 129462306a36Sopenharmony_ci * will be the same for both keys. 129562306a36Sopenharmony_ci **/ 129662306a36Sopenharmony_cistatic u32 ixgbe_atr_compute_sig_hash_82599(union ixgbe_atr_hash_dword input, 129762306a36Sopenharmony_ci union ixgbe_atr_hash_dword common) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan; 130062306a36Sopenharmony_ci u32 sig_hash = 0, bucket_hash = 0, common_hash = 0; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci /* record the flow_vm_vlan bits as they are a key part to the hash */ 130362306a36Sopenharmony_ci flow_vm_vlan = ntohl(input.dword); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci /* generate common hash dword */ 130662306a36Sopenharmony_ci hi_hash_dword = ntohl(common.dword); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci /* low dword is word swapped version of common */ 130962306a36Sopenharmony_ci lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci /* apply flow ID/VM pool/VLAN ID bits to hash words */ 131262306a36Sopenharmony_ci hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci /* Process bits 0 and 16 */ 131562306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(0); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci /* 131862306a36Sopenharmony_ci * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to 131962306a36Sopenharmony_ci * delay this because bit 0 of the stream should not be processed 132062306a36Sopenharmony_ci * so we do not add the vlan until after bit 0 was processed 132162306a36Sopenharmony_ci */ 132262306a36Sopenharmony_ci lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci /* Process remaining 30 bit of the key */ 132562306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(1); 132662306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(2); 132762306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(3); 132862306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(4); 132962306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(5); 133062306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(6); 133162306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(7); 133262306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(8); 133362306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(9); 133462306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(10); 133562306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(11); 133662306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(12); 133762306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(13); 133862306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(14); 133962306a36Sopenharmony_ci IXGBE_COMPUTE_SIG_HASH_ITERATION(15); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci /* combine common_hash result with signature and bucket hashes */ 134262306a36Sopenharmony_ci bucket_hash ^= common_hash; 134362306a36Sopenharmony_ci bucket_hash &= IXGBE_ATR_HASH_MASK; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci sig_hash ^= common_hash << 16; 134662306a36Sopenharmony_ci sig_hash &= IXGBE_ATR_HASH_MASK << 16; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* return completed signature hash */ 134962306a36Sopenharmony_ci return sig_hash ^ bucket_hash; 135062306a36Sopenharmony_ci} 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci/** 135362306a36Sopenharmony_ci * ixgbe_fdir_add_signature_filter_82599 - Adds a signature hash filter 135462306a36Sopenharmony_ci * @hw: pointer to hardware structure 135562306a36Sopenharmony_ci * @input: unique input dword 135662306a36Sopenharmony_ci * @common: compressed common input dword 135762306a36Sopenharmony_ci * @queue: queue index to direct traffic to 135862306a36Sopenharmony_ci * 135962306a36Sopenharmony_ci * Note that the tunnel bit in input must not be set when the hardware 136062306a36Sopenharmony_ci * tunneling support does not exist. 136162306a36Sopenharmony_ci **/ 136262306a36Sopenharmony_cis32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, 136362306a36Sopenharmony_ci union ixgbe_atr_hash_dword input, 136462306a36Sopenharmony_ci union ixgbe_atr_hash_dword common, 136562306a36Sopenharmony_ci u8 queue) 136662306a36Sopenharmony_ci{ 136762306a36Sopenharmony_ci u64 fdirhashcmd; 136862306a36Sopenharmony_ci u8 flow_type; 136962306a36Sopenharmony_ci bool tunnel; 137062306a36Sopenharmony_ci u32 fdircmd; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci /* 137362306a36Sopenharmony_ci * Get the flow_type in order to program FDIRCMD properly 137462306a36Sopenharmony_ci * lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 137562306a36Sopenharmony_ci */ 137662306a36Sopenharmony_ci tunnel = !!(input.formatted.flow_type & IXGBE_ATR_L4TYPE_TUNNEL_MASK); 137762306a36Sopenharmony_ci flow_type = input.formatted.flow_type & 137862306a36Sopenharmony_ci (IXGBE_ATR_L4TYPE_TUNNEL_MASK - 1); 137962306a36Sopenharmony_ci switch (flow_type) { 138062306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_TCPV4: 138162306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_UDPV4: 138262306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_SCTPV4: 138362306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_TCPV6: 138462306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_UDPV6: 138562306a36Sopenharmony_ci case IXGBE_ATR_FLOW_TYPE_SCTPV6: 138662306a36Sopenharmony_ci break; 138762306a36Sopenharmony_ci default: 138862306a36Sopenharmony_ci hw_dbg(hw, " Error on flow type input\n"); 138962306a36Sopenharmony_ci return -EIO; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci /* configure FDIRCMD register */ 139362306a36Sopenharmony_ci fdircmd = IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE | 139462306a36Sopenharmony_ci IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN; 139562306a36Sopenharmony_ci fdircmd |= (u32)flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT; 139662306a36Sopenharmony_ci fdircmd |= (u32)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT; 139762306a36Sopenharmony_ci if (tunnel) 139862306a36Sopenharmony_ci fdircmd |= IXGBE_FDIRCMD_TUNNEL_FILTER; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* 140162306a36Sopenharmony_ci * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits 140262306a36Sopenharmony_ci * is for FDIRCMD. Then do a 64-bit register write from FDIRHASH. 140362306a36Sopenharmony_ci */ 140462306a36Sopenharmony_ci fdirhashcmd = (u64)fdircmd << 32; 140562306a36Sopenharmony_ci fdirhashcmd |= ixgbe_atr_compute_sig_hash_82599(input, common); 140662306a36Sopenharmony_ci IXGBE_WRITE_REG64(hw, IXGBE_FDIRHASH, fdirhashcmd); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci hw_dbg(hw, "Tx Queue=%x hash=%x\n", queue, (u32)fdirhashcmd); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci return 0; 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci#define IXGBE_COMPUTE_BKT_HASH_ITERATION(_n) \ 141462306a36Sopenharmony_cido { \ 141562306a36Sopenharmony_ci u32 n = (_n); \ 141662306a36Sopenharmony_ci if (IXGBE_ATR_BUCKET_HASH_KEY & BIT(n)) \ 141762306a36Sopenharmony_ci bucket_hash ^= lo_hash_dword >> n; \ 141862306a36Sopenharmony_ci if (IXGBE_ATR_BUCKET_HASH_KEY & BIT(n + 16)) \ 141962306a36Sopenharmony_ci bucket_hash ^= hi_hash_dword >> n; \ 142062306a36Sopenharmony_ci} while (0) 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci/** 142362306a36Sopenharmony_ci * ixgbe_atr_compute_perfect_hash_82599 - Compute the perfect filter hash 142462306a36Sopenharmony_ci * @input: input bitstream to compute the hash on 142562306a36Sopenharmony_ci * @input_mask: mask for the input bitstream 142662306a36Sopenharmony_ci * 142762306a36Sopenharmony_ci * This function serves two main purposes. First it applies the input_mask 142862306a36Sopenharmony_ci * to the atr_input resulting in a cleaned up atr_input data stream. 142962306a36Sopenharmony_ci * Secondly it computes the hash and stores it in the bkt_hash field at 143062306a36Sopenharmony_ci * the end of the input byte stream. This way it will be available for 143162306a36Sopenharmony_ci * future use without needing to recompute the hash. 143262306a36Sopenharmony_ci **/ 143362306a36Sopenharmony_civoid ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input, 143462306a36Sopenharmony_ci union ixgbe_atr_input *input_mask) 143562306a36Sopenharmony_ci{ 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan; 143862306a36Sopenharmony_ci u32 bucket_hash = 0; 143962306a36Sopenharmony_ci __be32 hi_dword = 0; 144062306a36Sopenharmony_ci int i; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci /* Apply masks to input data */ 144362306a36Sopenharmony_ci for (i = 0; i <= 10; i++) 144462306a36Sopenharmony_ci input->dword_stream[i] &= input_mask->dword_stream[i]; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci /* record the flow_vm_vlan bits as they are a key part to the hash */ 144762306a36Sopenharmony_ci flow_vm_vlan = ntohl(input->dword_stream[0]); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci /* generate common hash dword */ 145062306a36Sopenharmony_ci for (i = 1; i <= 10; i++) 145162306a36Sopenharmony_ci hi_dword ^= input->dword_stream[i]; 145262306a36Sopenharmony_ci hi_hash_dword = ntohl(hi_dword); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci /* low dword is word swapped version of common */ 145562306a36Sopenharmony_ci lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci /* apply flow ID/VM pool/VLAN ID bits to hash words */ 145862306a36Sopenharmony_ci hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci /* Process bits 0 and 16 */ 146162306a36Sopenharmony_ci IXGBE_COMPUTE_BKT_HASH_ITERATION(0); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* 146462306a36Sopenharmony_ci * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to 146562306a36Sopenharmony_ci * delay this because bit 0 of the stream should not be processed 146662306a36Sopenharmony_ci * so we do not add the vlan until after bit 0 was processed 146762306a36Sopenharmony_ci */ 146862306a36Sopenharmony_ci lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci /* Process remaining 30 bit of the key */ 147162306a36Sopenharmony_ci for (i = 1; i <= 15; i++) 147262306a36Sopenharmony_ci IXGBE_COMPUTE_BKT_HASH_ITERATION(i); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci /* 147562306a36Sopenharmony_ci * Limit hash to 13 bits since max bucket count is 8K. 147662306a36Sopenharmony_ci * Store result at the end of the input stream. 147762306a36Sopenharmony_ci */ 147862306a36Sopenharmony_ci input->formatted.bkt_hash = (__force __be16)(bucket_hash & 0x1FFF); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci/** 148262306a36Sopenharmony_ci * ixgbe_get_fdirtcpm_82599 - generate a tcp port from atr_input_masks 148362306a36Sopenharmony_ci * @input_mask: mask to be bit swapped 148462306a36Sopenharmony_ci * 148562306a36Sopenharmony_ci * The source and destination port masks for flow director are bit swapped 148662306a36Sopenharmony_ci * in that bit 15 effects bit 0, 14 effects 1, 13, 2 etc. In order to 148762306a36Sopenharmony_ci * generate a correctly swapped value we need to bit swap the mask and that 148862306a36Sopenharmony_ci * is what is accomplished by this function. 148962306a36Sopenharmony_ci **/ 149062306a36Sopenharmony_cistatic u32 ixgbe_get_fdirtcpm_82599(union ixgbe_atr_input *input_mask) 149162306a36Sopenharmony_ci{ 149262306a36Sopenharmony_ci u32 mask = ntohs(input_mask->formatted.dst_port); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci mask <<= IXGBE_FDIRTCPM_DPORTM_SHIFT; 149562306a36Sopenharmony_ci mask |= ntohs(input_mask->formatted.src_port); 149662306a36Sopenharmony_ci mask = ((mask & 0x55555555) << 1) | ((mask & 0xAAAAAAAA) >> 1); 149762306a36Sopenharmony_ci mask = ((mask & 0x33333333) << 2) | ((mask & 0xCCCCCCCC) >> 2); 149862306a36Sopenharmony_ci mask = ((mask & 0x0F0F0F0F) << 4) | ((mask & 0xF0F0F0F0) >> 4); 149962306a36Sopenharmony_ci return ((mask & 0x00FF00FF) << 8) | ((mask & 0xFF00FF00) >> 8); 150062306a36Sopenharmony_ci} 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci/* 150362306a36Sopenharmony_ci * These two macros are meant to address the fact that we have registers 150462306a36Sopenharmony_ci * that are either all or in part big-endian. As a result on big-endian 150562306a36Sopenharmony_ci * systems we will end up byte swapping the value to little-endian before 150662306a36Sopenharmony_ci * it is byte swapped again and written to the hardware in the original 150762306a36Sopenharmony_ci * big-endian format. 150862306a36Sopenharmony_ci */ 150962306a36Sopenharmony_ci#define IXGBE_STORE_AS_BE32(_value) \ 151062306a36Sopenharmony_ci (((u32)(_value) >> 24) | (((u32)(_value) & 0x00FF0000) >> 8) | \ 151162306a36Sopenharmony_ci (((u32)(_value) & 0x0000FF00) << 8) | ((u32)(_value) << 24)) 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci#define IXGBE_WRITE_REG_BE32(a, reg, value) \ 151462306a36Sopenharmony_ci IXGBE_WRITE_REG((a), (reg), IXGBE_STORE_AS_BE32(ntohl(value))) 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci#define IXGBE_STORE_AS_BE16(_value) __swab16(ntohs((_value))) 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_cis32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, 151962306a36Sopenharmony_ci union ixgbe_atr_input *input_mask) 152062306a36Sopenharmony_ci{ 152162306a36Sopenharmony_ci /* mask IPv6 since it is currently not supported */ 152262306a36Sopenharmony_ci u32 fdirm = IXGBE_FDIRM_DIPv6; 152362306a36Sopenharmony_ci u32 fdirtcpm; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci /* 152662306a36Sopenharmony_ci * Program the relevant mask registers. If src/dst_port or src/dst_addr 152762306a36Sopenharmony_ci * are zero, then assume a full mask for that field. Also assume that 152862306a36Sopenharmony_ci * a VLAN of 0 is unspecified, so mask that out as well. L4type 152962306a36Sopenharmony_ci * cannot be masked out in this implementation. 153062306a36Sopenharmony_ci * 153162306a36Sopenharmony_ci * This also assumes IPv4 only. IPv6 masking isn't supported at this 153262306a36Sopenharmony_ci * point in time. 153362306a36Sopenharmony_ci */ 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci /* verify bucket hash is cleared on hash generation */ 153662306a36Sopenharmony_ci if (input_mask->formatted.bkt_hash) 153762306a36Sopenharmony_ci hw_dbg(hw, " bucket hash should always be 0 in mask\n"); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci /* Program FDIRM and verify partial masks */ 154062306a36Sopenharmony_ci switch (input_mask->formatted.vm_pool & 0x7F) { 154162306a36Sopenharmony_ci case 0x0: 154262306a36Sopenharmony_ci fdirm |= IXGBE_FDIRM_POOL; 154362306a36Sopenharmony_ci break; 154462306a36Sopenharmony_ci case 0x7F: 154562306a36Sopenharmony_ci break; 154662306a36Sopenharmony_ci default: 154762306a36Sopenharmony_ci hw_dbg(hw, " Error on vm pool mask\n"); 154862306a36Sopenharmony_ci return -EIO; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci switch (input_mask->formatted.flow_type & IXGBE_ATR_L4TYPE_MASK) { 155262306a36Sopenharmony_ci case 0x0: 155362306a36Sopenharmony_ci fdirm |= IXGBE_FDIRM_L4P; 155462306a36Sopenharmony_ci if (input_mask->formatted.dst_port || 155562306a36Sopenharmony_ci input_mask->formatted.src_port) { 155662306a36Sopenharmony_ci hw_dbg(hw, " Error on src/dst port mask\n"); 155762306a36Sopenharmony_ci return -EIO; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci break; 156062306a36Sopenharmony_ci case IXGBE_ATR_L4TYPE_MASK: 156162306a36Sopenharmony_ci break; 156262306a36Sopenharmony_ci default: 156362306a36Sopenharmony_ci hw_dbg(hw, " Error on flow type mask\n"); 156462306a36Sopenharmony_ci return -EIO; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci switch (ntohs(input_mask->formatted.vlan_id) & 0xEFFF) { 156862306a36Sopenharmony_ci case 0x0000: 156962306a36Sopenharmony_ci /* mask VLAN ID */ 157062306a36Sopenharmony_ci fdirm |= IXGBE_FDIRM_VLANID; 157162306a36Sopenharmony_ci fallthrough; 157262306a36Sopenharmony_ci case 0x0FFF: 157362306a36Sopenharmony_ci /* mask VLAN priority */ 157462306a36Sopenharmony_ci fdirm |= IXGBE_FDIRM_VLANP; 157562306a36Sopenharmony_ci break; 157662306a36Sopenharmony_ci case 0xE000: 157762306a36Sopenharmony_ci /* mask VLAN ID only */ 157862306a36Sopenharmony_ci fdirm |= IXGBE_FDIRM_VLANID; 157962306a36Sopenharmony_ci fallthrough; 158062306a36Sopenharmony_ci case 0xEFFF: 158162306a36Sopenharmony_ci /* no VLAN fields masked */ 158262306a36Sopenharmony_ci break; 158362306a36Sopenharmony_ci default: 158462306a36Sopenharmony_ci hw_dbg(hw, " Error on VLAN mask\n"); 158562306a36Sopenharmony_ci return -EIO; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci switch ((__force u16)input_mask->formatted.flex_bytes & 0xFFFF) { 158962306a36Sopenharmony_ci case 0x0000: 159062306a36Sopenharmony_ci /* Mask Flex Bytes */ 159162306a36Sopenharmony_ci fdirm |= IXGBE_FDIRM_FLEX; 159262306a36Sopenharmony_ci fallthrough; 159362306a36Sopenharmony_ci case 0xFFFF: 159462306a36Sopenharmony_ci break; 159562306a36Sopenharmony_ci default: 159662306a36Sopenharmony_ci hw_dbg(hw, " Error on flexible byte mask\n"); 159762306a36Sopenharmony_ci return -EIO; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci /* Now mask VM pool and destination IPv6 - bits 5 and 2 */ 160162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRM, fdirm); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci /* store the TCP/UDP port masks, bit reversed from port layout */ 160462306a36Sopenharmony_ci fdirtcpm = ixgbe_get_fdirtcpm_82599(input_mask); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* write both the same so that UDP and TCP use the same mask */ 160762306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, ~fdirtcpm); 160862306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, ~fdirtcpm); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci /* also use it for SCTP */ 161162306a36Sopenharmony_ci switch (hw->mac.type) { 161262306a36Sopenharmony_ci case ixgbe_mac_X550: 161362306a36Sopenharmony_ci case ixgbe_mac_X550EM_x: 161462306a36Sopenharmony_ci case ixgbe_mac_x550em_a: 161562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRSCTPM, ~fdirtcpm); 161662306a36Sopenharmony_ci break; 161762306a36Sopenharmony_ci default: 161862306a36Sopenharmony_ci break; 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci /* store source and destination IP masks (big-enian) */ 162262306a36Sopenharmony_ci IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIP4M, 162362306a36Sopenharmony_ci ~input_mask->formatted.src_ip[0]); 162462306a36Sopenharmony_ci IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRDIP4M, 162562306a36Sopenharmony_ci ~input_mask->formatted.dst_ip[0]); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci return 0; 162862306a36Sopenharmony_ci} 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_cis32 ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw, 163162306a36Sopenharmony_ci union ixgbe_atr_input *input, 163262306a36Sopenharmony_ci u16 soft_id, u8 queue) 163362306a36Sopenharmony_ci{ 163462306a36Sopenharmony_ci u32 fdirport, fdirvlan, fdirhash, fdircmd; 163562306a36Sopenharmony_ci s32 err; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci /* currently IPv6 is not supported, must be programmed with 0 */ 163862306a36Sopenharmony_ci IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIPv6(0), 163962306a36Sopenharmony_ci input->formatted.src_ip[0]); 164062306a36Sopenharmony_ci IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIPv6(1), 164162306a36Sopenharmony_ci input->formatted.src_ip[1]); 164262306a36Sopenharmony_ci IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIPv6(2), 164362306a36Sopenharmony_ci input->formatted.src_ip[2]); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* record the source address (big-endian) */ 164662306a36Sopenharmony_ci IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRIPSA, input->formatted.src_ip[0]); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci /* record the first 32 bits of the destination address (big-endian) */ 164962306a36Sopenharmony_ci IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRIPDA, input->formatted.dst_ip[0]); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci /* record source and destination port (little-endian)*/ 165262306a36Sopenharmony_ci fdirport = be16_to_cpu(input->formatted.dst_port); 165362306a36Sopenharmony_ci fdirport <<= IXGBE_FDIRPORT_DESTINATION_SHIFT; 165462306a36Sopenharmony_ci fdirport |= be16_to_cpu(input->formatted.src_port); 165562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, fdirport); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci /* record vlan (little-endian) and flex_bytes(big-endian) */ 165862306a36Sopenharmony_ci fdirvlan = IXGBE_STORE_AS_BE16(input->formatted.flex_bytes); 165962306a36Sopenharmony_ci fdirvlan <<= IXGBE_FDIRVLAN_FLEX_SHIFT; 166062306a36Sopenharmony_ci fdirvlan |= ntohs(input->formatted.vlan_id); 166162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, fdirvlan); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci /* configure FDIRHASH register */ 166462306a36Sopenharmony_ci fdirhash = (__force u32)input->formatted.bkt_hash; 166562306a36Sopenharmony_ci fdirhash |= soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT; 166662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci /* 166962306a36Sopenharmony_ci * flush all previous writes to make certain registers are 167062306a36Sopenharmony_ci * programmed prior to issuing the command 167162306a36Sopenharmony_ci */ 167262306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci /* configure FDIRCMD register */ 167562306a36Sopenharmony_ci fdircmd = IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE | 167662306a36Sopenharmony_ci IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN; 167762306a36Sopenharmony_ci if (queue == IXGBE_FDIR_DROP_QUEUE) 167862306a36Sopenharmony_ci fdircmd |= IXGBE_FDIRCMD_DROP; 167962306a36Sopenharmony_ci fdircmd |= input->formatted.flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT; 168062306a36Sopenharmony_ci fdircmd |= (u32)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT; 168162306a36Sopenharmony_ci fdircmd |= (u32)input->formatted.vm_pool << IXGBE_FDIRCMD_VT_POOL_SHIFT; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, fdircmd); 168462306a36Sopenharmony_ci err = ixgbe_fdir_check_cmd_complete(hw, &fdircmd); 168562306a36Sopenharmony_ci if (err) { 168662306a36Sopenharmony_ci hw_dbg(hw, "Flow Director command did not complete!\n"); 168762306a36Sopenharmony_ci return err; 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci return 0; 169162306a36Sopenharmony_ci} 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_cis32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, 169462306a36Sopenharmony_ci union ixgbe_atr_input *input, 169562306a36Sopenharmony_ci u16 soft_id) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci u32 fdirhash; 169862306a36Sopenharmony_ci u32 fdircmd; 169962306a36Sopenharmony_ci s32 err; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci /* configure FDIRHASH register */ 170262306a36Sopenharmony_ci fdirhash = (__force u32)input->formatted.bkt_hash; 170362306a36Sopenharmony_ci fdirhash |= soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT; 170462306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci /* flush hash to HW */ 170762306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci /* Query if filter is present */ 171062306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, IXGBE_FDIRCMD_CMD_QUERY_REM_FILT); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci err = ixgbe_fdir_check_cmd_complete(hw, &fdircmd); 171362306a36Sopenharmony_ci if (err) { 171462306a36Sopenharmony_ci hw_dbg(hw, "Flow Director command did not complete!\n"); 171562306a36Sopenharmony_ci return err; 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci /* if filter exists in hardware then remove it */ 171962306a36Sopenharmony_ci if (fdircmd & IXGBE_FDIRCMD_FILTER_VALID) { 172062306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash); 172162306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 172262306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, 172362306a36Sopenharmony_ci IXGBE_FDIRCMD_CMD_REMOVE_FLOW); 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci return 0; 172762306a36Sopenharmony_ci} 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci/** 173062306a36Sopenharmony_ci * ixgbe_read_analog_reg8_82599 - Reads 8 bit Omer analog register 173162306a36Sopenharmony_ci * @hw: pointer to hardware structure 173262306a36Sopenharmony_ci * @reg: analog register to read 173362306a36Sopenharmony_ci * @val: read value 173462306a36Sopenharmony_ci * 173562306a36Sopenharmony_ci * Performs read operation to Omer analog register specified. 173662306a36Sopenharmony_ci **/ 173762306a36Sopenharmony_cistatic s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci u32 core_ctl; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_CORECTL, IXGBE_CORECTL_WRITE_CMD | 174262306a36Sopenharmony_ci (reg << 8)); 174362306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 174462306a36Sopenharmony_ci udelay(10); 174562306a36Sopenharmony_ci core_ctl = IXGBE_READ_REG(hw, IXGBE_CORECTL); 174662306a36Sopenharmony_ci *val = (u8)core_ctl; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci return 0; 174962306a36Sopenharmony_ci} 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci/** 175262306a36Sopenharmony_ci * ixgbe_write_analog_reg8_82599 - Writes 8 bit Omer analog register 175362306a36Sopenharmony_ci * @hw: pointer to hardware structure 175462306a36Sopenharmony_ci * @reg: atlas register to write 175562306a36Sopenharmony_ci * @val: value to write 175662306a36Sopenharmony_ci * 175762306a36Sopenharmony_ci * Performs write operation to Omer analog register specified. 175862306a36Sopenharmony_ci **/ 175962306a36Sopenharmony_cistatic s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) 176062306a36Sopenharmony_ci{ 176162306a36Sopenharmony_ci u32 core_ctl; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci core_ctl = (reg << 8) | val; 176462306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_CORECTL, core_ctl); 176562306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 176662306a36Sopenharmony_ci udelay(10); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci return 0; 176962306a36Sopenharmony_ci} 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci/** 177262306a36Sopenharmony_ci * ixgbe_start_hw_82599 - Prepare hardware for Tx/Rx 177362306a36Sopenharmony_ci * @hw: pointer to hardware structure 177462306a36Sopenharmony_ci * 177562306a36Sopenharmony_ci * Starts the hardware using the generic start_hw function 177662306a36Sopenharmony_ci * and the generation start_hw function. 177762306a36Sopenharmony_ci * Then performs revision-specific operations, if any. 177862306a36Sopenharmony_ci **/ 177962306a36Sopenharmony_cistatic s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) 178062306a36Sopenharmony_ci{ 178162306a36Sopenharmony_ci s32 ret_val = 0; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci ret_val = ixgbe_start_hw_generic(hw); 178462306a36Sopenharmony_ci if (ret_val) 178562306a36Sopenharmony_ci return ret_val; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci ret_val = ixgbe_start_hw_gen2(hw); 178862306a36Sopenharmony_ci if (ret_val) 178962306a36Sopenharmony_ci return ret_val; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci /* We need to run link autotry after the driver loads */ 179262306a36Sopenharmony_ci hw->mac.autotry_restart = true; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci return ixgbe_verify_fw_version_82599(hw); 179562306a36Sopenharmony_ci} 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci/** 179862306a36Sopenharmony_ci * ixgbe_identify_phy_82599 - Get physical layer module 179962306a36Sopenharmony_ci * @hw: pointer to hardware structure 180062306a36Sopenharmony_ci * 180162306a36Sopenharmony_ci * Determines the physical layer module found on the current adapter. 180262306a36Sopenharmony_ci * If PHY already detected, maintains current PHY type in hw struct, 180362306a36Sopenharmony_ci * otherwise executes the PHY detection routine. 180462306a36Sopenharmony_ci **/ 180562306a36Sopenharmony_cistatic s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) 180662306a36Sopenharmony_ci{ 180762306a36Sopenharmony_ci s32 status; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci /* Detect PHY if not unknown - returns success if already detected. */ 181062306a36Sopenharmony_ci status = ixgbe_identify_phy_generic(hw); 181162306a36Sopenharmony_ci if (status) { 181262306a36Sopenharmony_ci /* 82599 10GBASE-T requires an external PHY */ 181362306a36Sopenharmony_ci if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper) 181462306a36Sopenharmony_ci return status; 181562306a36Sopenharmony_ci status = ixgbe_identify_module_generic(hw); 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci /* Set PHY type none if no PHY detected */ 181962306a36Sopenharmony_ci if (hw->phy.type == ixgbe_phy_unknown) { 182062306a36Sopenharmony_ci hw->phy.type = ixgbe_phy_none; 182162306a36Sopenharmony_ci status = 0; 182262306a36Sopenharmony_ci } 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci /* Return error if SFP module has been detected but is not supported */ 182562306a36Sopenharmony_ci if (hw->phy.type == ixgbe_phy_sfp_unsupported) 182662306a36Sopenharmony_ci return -EOPNOTSUPP; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci return status; 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci/** 183262306a36Sopenharmony_ci * ixgbe_enable_rx_dma_82599 - Enable the Rx DMA unit on 82599 183362306a36Sopenharmony_ci * @hw: pointer to hardware structure 183462306a36Sopenharmony_ci * @regval: register value to write to RXCTRL 183562306a36Sopenharmony_ci * 183662306a36Sopenharmony_ci * Enables the Rx DMA unit for 82599 183762306a36Sopenharmony_ci **/ 183862306a36Sopenharmony_cistatic s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) 183962306a36Sopenharmony_ci{ 184062306a36Sopenharmony_ci /* 184162306a36Sopenharmony_ci * Workaround for 82599 silicon errata when enabling the Rx datapath. 184262306a36Sopenharmony_ci * If traffic is incoming before we enable the Rx unit, it could hang 184362306a36Sopenharmony_ci * the Rx DMA unit. Therefore, make sure the security engine is 184462306a36Sopenharmony_ci * completely disabled prior to enabling the Rx unit. 184562306a36Sopenharmony_ci */ 184662306a36Sopenharmony_ci hw->mac.ops.disable_rx_buff(hw); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci if (regval & IXGBE_RXCTRL_RXEN) 184962306a36Sopenharmony_ci hw->mac.ops.enable_rx(hw); 185062306a36Sopenharmony_ci else 185162306a36Sopenharmony_ci hw->mac.ops.disable_rx(hw); 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci hw->mac.ops.enable_rx_buff(hw); 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci return 0; 185662306a36Sopenharmony_ci} 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci/** 185962306a36Sopenharmony_ci * ixgbe_verify_fw_version_82599 - verify fw version for 82599 186062306a36Sopenharmony_ci * @hw: pointer to hardware structure 186162306a36Sopenharmony_ci * 186262306a36Sopenharmony_ci * Verifies that installed the firmware version is 0.6 or higher 186362306a36Sopenharmony_ci * for SFI devices. All 82599 SFI devices should have version 0.6 or higher. 186462306a36Sopenharmony_ci * 186562306a36Sopenharmony_ci * Return: -EACCES if the FW is not present or if the FW version is 186662306a36Sopenharmony_ci * not supported. 186762306a36Sopenharmony_ci **/ 186862306a36Sopenharmony_cistatic s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) 186962306a36Sopenharmony_ci{ 187062306a36Sopenharmony_ci u16 fw_offset, fw_ptp_cfg_offset; 187162306a36Sopenharmony_ci s32 status = -EACCES; 187262306a36Sopenharmony_ci u16 offset; 187362306a36Sopenharmony_ci u16 fw_version = 0; 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci /* firmware check is only necessary for SFI devices */ 187662306a36Sopenharmony_ci if (hw->phy.media_type != ixgbe_media_type_fiber) 187762306a36Sopenharmony_ci return 0; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci /* get the offset to the Firmware Module block */ 188062306a36Sopenharmony_ci offset = IXGBE_FW_PTR; 188162306a36Sopenharmony_ci if (hw->eeprom.ops.read(hw, offset, &fw_offset)) 188262306a36Sopenharmony_ci goto fw_version_err; 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci if (fw_offset == 0 || fw_offset == 0xFFFF) 188562306a36Sopenharmony_ci return -EACCES; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* get the offset to the Pass Through Patch Configuration block */ 188862306a36Sopenharmony_ci offset = fw_offset + IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR; 188962306a36Sopenharmony_ci if (hw->eeprom.ops.read(hw, offset, &fw_ptp_cfg_offset)) 189062306a36Sopenharmony_ci goto fw_version_err; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (fw_ptp_cfg_offset == 0 || fw_ptp_cfg_offset == 0xFFFF) 189362306a36Sopenharmony_ci return -EACCES; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci /* get the firmware version */ 189662306a36Sopenharmony_ci offset = fw_ptp_cfg_offset + IXGBE_FW_PATCH_VERSION_4; 189762306a36Sopenharmony_ci if (hw->eeprom.ops.read(hw, offset, &fw_version)) 189862306a36Sopenharmony_ci goto fw_version_err; 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci if (fw_version > 0x5) 190162306a36Sopenharmony_ci status = 0; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci return status; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_cifw_version_err: 190662306a36Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", offset); 190762306a36Sopenharmony_ci return -EACCES; 190862306a36Sopenharmony_ci} 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci/** 191162306a36Sopenharmony_ci * ixgbe_verify_lesm_fw_enabled_82599 - Checks LESM FW module state. 191262306a36Sopenharmony_ci * @hw: pointer to hardware structure 191362306a36Sopenharmony_ci * 191462306a36Sopenharmony_ci * Returns true if the LESM FW module is present and enabled. Otherwise 191562306a36Sopenharmony_ci * returns false. Smart Speed must be disabled if LESM FW module is enabled. 191662306a36Sopenharmony_ci **/ 191762306a36Sopenharmony_cistatic bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci u16 fw_offset, fw_lesm_param_offset, fw_lesm_state; 192062306a36Sopenharmony_ci s32 status; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci /* get the offset to the Firmware Module block */ 192362306a36Sopenharmony_ci status = hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci if (status || fw_offset == 0 || fw_offset == 0xFFFF) 192662306a36Sopenharmony_ci return false; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci /* get the offset to the LESM Parameters block */ 192962306a36Sopenharmony_ci status = hw->eeprom.ops.read(hw, (fw_offset + 193062306a36Sopenharmony_ci IXGBE_FW_LESM_PARAMETERS_PTR), 193162306a36Sopenharmony_ci &fw_lesm_param_offset); 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci if (status || 193462306a36Sopenharmony_ci fw_lesm_param_offset == 0 || fw_lesm_param_offset == 0xFFFF) 193562306a36Sopenharmony_ci return false; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci /* get the lesm state word */ 193862306a36Sopenharmony_ci status = hw->eeprom.ops.read(hw, (fw_lesm_param_offset + 193962306a36Sopenharmony_ci IXGBE_FW_LESM_STATE_1), 194062306a36Sopenharmony_ci &fw_lesm_state); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci if (!status && (fw_lesm_state & IXGBE_FW_LESM_STATE_ENABLED)) 194362306a36Sopenharmony_ci return true; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci return false; 194662306a36Sopenharmony_ci} 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci/** 194962306a36Sopenharmony_ci * ixgbe_read_eeprom_buffer_82599 - Read EEPROM word(s) using 195062306a36Sopenharmony_ci * fastest available method 195162306a36Sopenharmony_ci * 195262306a36Sopenharmony_ci * @hw: pointer to hardware structure 195362306a36Sopenharmony_ci * @offset: offset of word in EEPROM to read 195462306a36Sopenharmony_ci * @words: number of words 195562306a36Sopenharmony_ci * @data: word(s) read from the EEPROM 195662306a36Sopenharmony_ci * 195762306a36Sopenharmony_ci * Retrieves 16 bit word(s) read from EEPROM 195862306a36Sopenharmony_ci **/ 195962306a36Sopenharmony_cistatic s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset, 196062306a36Sopenharmony_ci u16 words, u16 *data) 196162306a36Sopenharmony_ci{ 196262306a36Sopenharmony_ci struct ixgbe_eeprom_info *eeprom = &hw->eeprom; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci /* If EEPROM is detected and can be addressed using 14 bits, 196562306a36Sopenharmony_ci * use EERD otherwise use bit bang 196662306a36Sopenharmony_ci */ 196762306a36Sopenharmony_ci if (eeprom->type == ixgbe_eeprom_spi && 196862306a36Sopenharmony_ci offset + (words - 1) <= IXGBE_EERD_MAX_ADDR) 196962306a36Sopenharmony_ci return ixgbe_read_eerd_buffer_generic(hw, offset, words, data); 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci return ixgbe_read_eeprom_buffer_bit_bang_generic(hw, offset, words, 197262306a36Sopenharmony_ci data); 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci/** 197662306a36Sopenharmony_ci * ixgbe_read_eeprom_82599 - Read EEPROM word using 197762306a36Sopenharmony_ci * fastest available method 197862306a36Sopenharmony_ci * 197962306a36Sopenharmony_ci * @hw: pointer to hardware structure 198062306a36Sopenharmony_ci * @offset: offset of word in the EEPROM to read 198162306a36Sopenharmony_ci * @data: word read from the EEPROM 198262306a36Sopenharmony_ci * 198362306a36Sopenharmony_ci * Reads a 16 bit word from the EEPROM 198462306a36Sopenharmony_ci **/ 198562306a36Sopenharmony_cistatic s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, 198662306a36Sopenharmony_ci u16 offset, u16 *data) 198762306a36Sopenharmony_ci{ 198862306a36Sopenharmony_ci struct ixgbe_eeprom_info *eeprom = &hw->eeprom; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci /* 199162306a36Sopenharmony_ci * If EEPROM is detected and can be addressed using 14 bits, 199262306a36Sopenharmony_ci * use EERD otherwise use bit bang 199362306a36Sopenharmony_ci */ 199462306a36Sopenharmony_ci if (eeprom->type == ixgbe_eeprom_spi && offset <= IXGBE_EERD_MAX_ADDR) 199562306a36Sopenharmony_ci return ixgbe_read_eerd_generic(hw, offset, data); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci return ixgbe_read_eeprom_bit_bang_generic(hw, offset, data); 199862306a36Sopenharmony_ci} 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci/** 200162306a36Sopenharmony_ci * ixgbe_reset_pipeline_82599 - perform pipeline reset 200262306a36Sopenharmony_ci * 200362306a36Sopenharmony_ci * @hw: pointer to hardware structure 200462306a36Sopenharmony_ci * 200562306a36Sopenharmony_ci * Reset pipeline by asserting Restart_AN together with LMS change to ensure 200662306a36Sopenharmony_ci * full pipeline reset. Note - We must hold the SW/FW semaphore before writing 200762306a36Sopenharmony_ci * to AUTOC, so this function assumes the semaphore is held. 200862306a36Sopenharmony_ci **/ 200962306a36Sopenharmony_cistatic s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw) 201062306a36Sopenharmony_ci{ 201162306a36Sopenharmony_ci s32 ret_val; 201262306a36Sopenharmony_ci u32 anlp1_reg = 0; 201362306a36Sopenharmony_ci u32 i, autoc_reg, autoc2_reg; 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci /* Enable link if disabled in NVM */ 201662306a36Sopenharmony_ci autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2); 201762306a36Sopenharmony_ci if (autoc2_reg & IXGBE_AUTOC2_LINK_DISABLE_MASK) { 201862306a36Sopenharmony_ci autoc2_reg &= ~IXGBE_AUTOC2_LINK_DISABLE_MASK; 201962306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2_reg); 202062306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); 202462306a36Sopenharmony_ci autoc_reg |= IXGBE_AUTOC_AN_RESTART; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci /* Write AUTOC register with toggled LMS[2] bit and Restart_AN */ 202762306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_AUTOC, 202862306a36Sopenharmony_ci autoc_reg ^ (0x4 << IXGBE_AUTOC_LMS_SHIFT)); 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci /* Wait for AN to leave state 0 */ 203162306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 203262306a36Sopenharmony_ci usleep_range(4000, 8000); 203362306a36Sopenharmony_ci anlp1_reg = IXGBE_READ_REG(hw, IXGBE_ANLP1); 203462306a36Sopenharmony_ci if (anlp1_reg & IXGBE_ANLP1_AN_STATE_MASK) 203562306a36Sopenharmony_ci break; 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci if (!(anlp1_reg & IXGBE_ANLP1_AN_STATE_MASK)) { 203962306a36Sopenharmony_ci hw_dbg(hw, "auto negotiation not completed\n"); 204062306a36Sopenharmony_ci ret_val = -EIO; 204162306a36Sopenharmony_ci goto reset_pipeline_out; 204262306a36Sopenharmony_ci } 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci ret_val = 0; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_cireset_pipeline_out: 204762306a36Sopenharmony_ci /* Write AUTOC register with original LMS field and Restart_AN */ 204862306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); 204962306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci return ret_val; 205262306a36Sopenharmony_ci} 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci/** 205562306a36Sopenharmony_ci * ixgbe_read_i2c_byte_82599 - Reads 8 bit word over I2C 205662306a36Sopenharmony_ci * @hw: pointer to hardware structure 205762306a36Sopenharmony_ci * @byte_offset: byte offset to read 205862306a36Sopenharmony_ci * @dev_addr: address to read from 205962306a36Sopenharmony_ci * @data: value read 206062306a36Sopenharmony_ci * 206162306a36Sopenharmony_ci * Performs byte read operation to SFP module's EEPROM over I2C interface at 206262306a36Sopenharmony_ci * a specified device address. 206362306a36Sopenharmony_ci **/ 206462306a36Sopenharmony_cistatic s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, 206562306a36Sopenharmony_ci u8 dev_addr, u8 *data) 206662306a36Sopenharmony_ci{ 206762306a36Sopenharmony_ci u32 esdp; 206862306a36Sopenharmony_ci s32 status; 206962306a36Sopenharmony_ci s32 timeout = 200; 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci if (hw->phy.qsfp_shared_i2c_bus == true) { 207262306a36Sopenharmony_ci /* Acquire I2C bus ownership. */ 207362306a36Sopenharmony_ci esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 207462306a36Sopenharmony_ci esdp |= IXGBE_ESDP_SDP0; 207562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 207662306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci while (timeout) { 207962306a36Sopenharmony_ci esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 208062306a36Sopenharmony_ci if (esdp & IXGBE_ESDP_SDP1) 208162306a36Sopenharmony_ci break; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci usleep_range(5000, 10000); 208462306a36Sopenharmony_ci timeout--; 208562306a36Sopenharmony_ci } 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci if (!timeout) { 208862306a36Sopenharmony_ci hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n"); 208962306a36Sopenharmony_ci status = -EIO; 209062306a36Sopenharmony_ci goto release_i2c_access; 209162306a36Sopenharmony_ci } 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci status = ixgbe_read_i2c_byte_generic(hw, byte_offset, dev_addr, data); 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_cirelease_i2c_access: 209762306a36Sopenharmony_ci if (hw->phy.qsfp_shared_i2c_bus == true) { 209862306a36Sopenharmony_ci /* Release I2C bus ownership. */ 209962306a36Sopenharmony_ci esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 210062306a36Sopenharmony_ci esdp &= ~IXGBE_ESDP_SDP0; 210162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 210262306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 210362306a36Sopenharmony_ci } 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci return status; 210662306a36Sopenharmony_ci} 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci/** 210962306a36Sopenharmony_ci * ixgbe_write_i2c_byte_82599 - Writes 8 bit word over I2C 211062306a36Sopenharmony_ci * @hw: pointer to hardware structure 211162306a36Sopenharmony_ci * @byte_offset: byte offset to write 211262306a36Sopenharmony_ci * @dev_addr: address to write to 211362306a36Sopenharmony_ci * @data: value to write 211462306a36Sopenharmony_ci * 211562306a36Sopenharmony_ci * Performs byte write operation to SFP module's EEPROM over I2C interface at 211662306a36Sopenharmony_ci * a specified device address. 211762306a36Sopenharmony_ci **/ 211862306a36Sopenharmony_cistatic s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, 211962306a36Sopenharmony_ci u8 dev_addr, u8 data) 212062306a36Sopenharmony_ci{ 212162306a36Sopenharmony_ci u32 esdp; 212262306a36Sopenharmony_ci s32 status; 212362306a36Sopenharmony_ci s32 timeout = 200; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci if (hw->phy.qsfp_shared_i2c_bus == true) { 212662306a36Sopenharmony_ci /* Acquire I2C bus ownership. */ 212762306a36Sopenharmony_ci esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 212862306a36Sopenharmony_ci esdp |= IXGBE_ESDP_SDP0; 212962306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 213062306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci while (timeout) { 213362306a36Sopenharmony_ci esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 213462306a36Sopenharmony_ci if (esdp & IXGBE_ESDP_SDP1) 213562306a36Sopenharmony_ci break; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci usleep_range(5000, 10000); 213862306a36Sopenharmony_ci timeout--; 213962306a36Sopenharmony_ci } 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci if (!timeout) { 214262306a36Sopenharmony_ci hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n"); 214362306a36Sopenharmony_ci status = -EIO; 214462306a36Sopenharmony_ci goto release_i2c_access; 214562306a36Sopenharmony_ci } 214662306a36Sopenharmony_ci } 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci status = ixgbe_write_i2c_byte_generic(hw, byte_offset, dev_addr, data); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_cirelease_i2c_access: 215162306a36Sopenharmony_ci if (hw->phy.qsfp_shared_i2c_bus == true) { 215262306a36Sopenharmony_ci /* Release I2C bus ownership. */ 215362306a36Sopenharmony_ci esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 215462306a36Sopenharmony_ci esdp &= ~IXGBE_ESDP_SDP0; 215562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 215662306a36Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 215762306a36Sopenharmony_ci } 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci return status; 216062306a36Sopenharmony_ci} 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_cistatic const struct ixgbe_mac_operations mac_ops_82599 = { 216362306a36Sopenharmony_ci .init_hw = &ixgbe_init_hw_generic, 216462306a36Sopenharmony_ci .reset_hw = &ixgbe_reset_hw_82599, 216562306a36Sopenharmony_ci .start_hw = &ixgbe_start_hw_82599, 216662306a36Sopenharmony_ci .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic, 216762306a36Sopenharmony_ci .get_media_type = &ixgbe_get_media_type_82599, 216862306a36Sopenharmony_ci .enable_rx_dma = &ixgbe_enable_rx_dma_82599, 216962306a36Sopenharmony_ci .disable_rx_buff = &ixgbe_disable_rx_buff_generic, 217062306a36Sopenharmony_ci .enable_rx_buff = &ixgbe_enable_rx_buff_generic, 217162306a36Sopenharmony_ci .get_mac_addr = &ixgbe_get_mac_addr_generic, 217262306a36Sopenharmony_ci .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, 217362306a36Sopenharmony_ci .get_device_caps = &ixgbe_get_device_caps_generic, 217462306a36Sopenharmony_ci .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, 217562306a36Sopenharmony_ci .stop_adapter = &ixgbe_stop_adapter_generic, 217662306a36Sopenharmony_ci .get_bus_info = &ixgbe_get_bus_info_generic, 217762306a36Sopenharmony_ci .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie, 217862306a36Sopenharmony_ci .read_analog_reg8 = &ixgbe_read_analog_reg8_82599, 217962306a36Sopenharmony_ci .write_analog_reg8 = &ixgbe_write_analog_reg8_82599, 218062306a36Sopenharmony_ci .stop_link_on_d3 = &ixgbe_stop_mac_link_on_d3_82599, 218162306a36Sopenharmony_ci .setup_link = &ixgbe_setup_mac_link_82599, 218262306a36Sopenharmony_ci .set_rxpba = &ixgbe_set_rxpba_generic, 218362306a36Sopenharmony_ci .check_link = &ixgbe_check_mac_link_generic, 218462306a36Sopenharmony_ci .get_link_capabilities = &ixgbe_get_link_capabilities_82599, 218562306a36Sopenharmony_ci .led_on = &ixgbe_led_on_generic, 218662306a36Sopenharmony_ci .led_off = &ixgbe_led_off_generic, 218762306a36Sopenharmony_ci .init_led_link_act = ixgbe_init_led_link_act_generic, 218862306a36Sopenharmony_ci .blink_led_start = &ixgbe_blink_led_start_generic, 218962306a36Sopenharmony_ci .blink_led_stop = &ixgbe_blink_led_stop_generic, 219062306a36Sopenharmony_ci .set_rar = &ixgbe_set_rar_generic, 219162306a36Sopenharmony_ci .clear_rar = &ixgbe_clear_rar_generic, 219262306a36Sopenharmony_ci .set_vmdq = &ixgbe_set_vmdq_generic, 219362306a36Sopenharmony_ci .set_vmdq_san_mac = &ixgbe_set_vmdq_san_mac_generic, 219462306a36Sopenharmony_ci .clear_vmdq = &ixgbe_clear_vmdq_generic, 219562306a36Sopenharmony_ci .init_rx_addrs = &ixgbe_init_rx_addrs_generic, 219662306a36Sopenharmony_ci .update_mc_addr_list = &ixgbe_update_mc_addr_list_generic, 219762306a36Sopenharmony_ci .enable_mc = &ixgbe_enable_mc_generic, 219862306a36Sopenharmony_ci .disable_mc = &ixgbe_disable_mc_generic, 219962306a36Sopenharmony_ci .clear_vfta = &ixgbe_clear_vfta_generic, 220062306a36Sopenharmony_ci .set_vfta = &ixgbe_set_vfta_generic, 220162306a36Sopenharmony_ci .fc_enable = &ixgbe_fc_enable_generic, 220262306a36Sopenharmony_ci .setup_fc = ixgbe_setup_fc_generic, 220362306a36Sopenharmony_ci .fc_autoneg = ixgbe_fc_autoneg, 220462306a36Sopenharmony_ci .set_fw_drv_ver = &ixgbe_set_fw_drv_ver_generic, 220562306a36Sopenharmony_ci .init_uta_tables = &ixgbe_init_uta_tables_generic, 220662306a36Sopenharmony_ci .setup_sfp = &ixgbe_setup_sfp_modules_82599, 220762306a36Sopenharmony_ci .set_mac_anti_spoofing = &ixgbe_set_mac_anti_spoofing, 220862306a36Sopenharmony_ci .set_vlan_anti_spoofing = &ixgbe_set_vlan_anti_spoofing, 220962306a36Sopenharmony_ci .acquire_swfw_sync = &ixgbe_acquire_swfw_sync, 221062306a36Sopenharmony_ci .release_swfw_sync = &ixgbe_release_swfw_sync, 221162306a36Sopenharmony_ci .init_swfw_sync = NULL, 221262306a36Sopenharmony_ci .get_thermal_sensor_data = &ixgbe_get_thermal_sensor_data_generic, 221362306a36Sopenharmony_ci .init_thermal_sensor_thresh = &ixgbe_init_thermal_sensor_thresh_generic, 221462306a36Sopenharmony_ci .prot_autoc_read = &prot_autoc_read_82599, 221562306a36Sopenharmony_ci .prot_autoc_write = &prot_autoc_write_82599, 221662306a36Sopenharmony_ci .enable_rx = &ixgbe_enable_rx_generic, 221762306a36Sopenharmony_ci .disable_rx = &ixgbe_disable_rx_generic, 221862306a36Sopenharmony_ci}; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_cistatic const struct ixgbe_eeprom_operations eeprom_ops_82599 = { 222162306a36Sopenharmony_ci .init_params = &ixgbe_init_eeprom_params_generic, 222262306a36Sopenharmony_ci .read = &ixgbe_read_eeprom_82599, 222362306a36Sopenharmony_ci .read_buffer = &ixgbe_read_eeprom_buffer_82599, 222462306a36Sopenharmony_ci .write = &ixgbe_write_eeprom_generic, 222562306a36Sopenharmony_ci .write_buffer = &ixgbe_write_eeprom_buffer_bit_bang_generic, 222662306a36Sopenharmony_ci .calc_checksum = &ixgbe_calc_eeprom_checksum_generic, 222762306a36Sopenharmony_ci .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, 222862306a36Sopenharmony_ci .update_checksum = &ixgbe_update_eeprom_checksum_generic, 222962306a36Sopenharmony_ci}; 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_cistatic const struct ixgbe_phy_operations phy_ops_82599 = { 223262306a36Sopenharmony_ci .identify = &ixgbe_identify_phy_82599, 223362306a36Sopenharmony_ci .identify_sfp = &ixgbe_identify_module_generic, 223462306a36Sopenharmony_ci .init = &ixgbe_init_phy_ops_82599, 223562306a36Sopenharmony_ci .reset = &ixgbe_reset_phy_generic, 223662306a36Sopenharmony_ci .read_reg = &ixgbe_read_phy_reg_generic, 223762306a36Sopenharmony_ci .write_reg = &ixgbe_write_phy_reg_generic, 223862306a36Sopenharmony_ci .setup_link = &ixgbe_setup_phy_link_generic, 223962306a36Sopenharmony_ci .setup_link_speed = &ixgbe_setup_phy_link_speed_generic, 224062306a36Sopenharmony_ci .read_i2c_byte = &ixgbe_read_i2c_byte_generic, 224162306a36Sopenharmony_ci .write_i2c_byte = &ixgbe_write_i2c_byte_generic, 224262306a36Sopenharmony_ci .read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_generic, 224362306a36Sopenharmony_ci .read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic, 224462306a36Sopenharmony_ci .write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic, 224562306a36Sopenharmony_ci .check_overtemp = &ixgbe_tn_check_overtemp, 224662306a36Sopenharmony_ci}; 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ciconst struct ixgbe_info ixgbe_82599_info = { 224962306a36Sopenharmony_ci .mac = ixgbe_mac_82599EB, 225062306a36Sopenharmony_ci .get_invariants = &ixgbe_get_invariants_82599, 225162306a36Sopenharmony_ci .mac_ops = &mac_ops_82599, 225262306a36Sopenharmony_ci .eeprom_ops = &eeprom_ops_82599, 225362306a36Sopenharmony_ci .phy_ops = &phy_ops_82599, 225462306a36Sopenharmony_ci .mbx_ops = &mbx_ops_generic, 225562306a36Sopenharmony_ci .mvals = ixgbe_mvals_8259X, 225662306a36Sopenharmony_ci}; 2257