18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/pci.h> 58c2ecf20Sopenharmony_ci#include <linux/delay.h> 68c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 78c2ecf20Sopenharmony_ci#include <linux/sched.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "ixgbe.h" 108c2ecf20Sopenharmony_ci#include "ixgbe_phy.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic void ixgbe_i2c_start(struct ixgbe_hw *hw); 138c2ecf20Sopenharmony_cistatic void ixgbe_i2c_stop(struct ixgbe_hw *hw); 148c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data); 158c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data); 168c2ecf20Sopenharmony_cistatic s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw); 178c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data); 188c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data); 198c2ecf20Sopenharmony_cistatic void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); 208c2ecf20Sopenharmony_cistatic void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); 218c2ecf20Sopenharmony_cistatic s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); 228c2ecf20Sopenharmony_cistatic bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl); 238c2ecf20Sopenharmony_cistatic void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw); 248c2ecf20Sopenharmony_cistatic enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id); 258c2ecf20Sopenharmony_cistatic s32 ixgbe_get_phy_id(struct ixgbe_hw *hw); 268c2ecf20Sopenharmony_cistatic s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * ixgbe_out_i2c_byte_ack - Send I2C byte with ack 308c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 318c2ecf20Sopenharmony_ci * @byte: byte to send 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Returns an error code on error. 348c2ecf20Sopenharmony_ci **/ 358c2ecf20Sopenharmony_cistatic s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci s32 status; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, byte); 408c2ecf20Sopenharmony_ci if (status) 418c2ecf20Sopenharmony_ci return status; 428c2ecf20Sopenharmony_ci return ixgbe_get_i2c_ack(hw); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/** 468c2ecf20Sopenharmony_ci * ixgbe_in_i2c_byte_ack - Receive an I2C byte and send ack 478c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 488c2ecf20Sopenharmony_ci * @byte: pointer to a u8 to receive the byte 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * Returns an error code on error. 518c2ecf20Sopenharmony_ci **/ 528c2ecf20Sopenharmony_cistatic s32 ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci s32 status; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci status = ixgbe_clock_in_i2c_byte(hw, byte); 578c2ecf20Sopenharmony_ci if (status) 588c2ecf20Sopenharmony_ci return status; 598c2ecf20Sopenharmony_ci /* ACK */ 608c2ecf20Sopenharmony_ci return ixgbe_clock_out_i2c_bit(hw, false); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/** 648c2ecf20Sopenharmony_ci * ixgbe_ones_comp_byte_add - Perform one's complement addition 658c2ecf20Sopenharmony_ci * @add1: addend 1 668c2ecf20Sopenharmony_ci * @add2: addend 2 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * Returns one's complement 8-bit sum. 698c2ecf20Sopenharmony_ci **/ 708c2ecf20Sopenharmony_cistatic u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci u16 sum = add1 + add2; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci sum = (sum & 0xFF) + (sum >> 8); 758c2ecf20Sopenharmony_ci return sum & 0xFF; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/** 798c2ecf20Sopenharmony_ci * ixgbe_read_i2c_combined_generic_int - Perform I2C read combined operation 808c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 818c2ecf20Sopenharmony_ci * @addr: I2C bus address to read from 828c2ecf20Sopenharmony_ci * @reg: I2C device register to read from 838c2ecf20Sopenharmony_ci * @val: pointer to location to receive read value 848c2ecf20Sopenharmony_ci * @lock: true if to take and release semaphore 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * Returns an error code on error. 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, 898c2ecf20Sopenharmony_ci u16 reg, u16 *val, bool lock) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci u32 swfw_mask = hw->phy.phy_semaphore_mask; 928c2ecf20Sopenharmony_ci int max_retry = 3; 938c2ecf20Sopenharmony_ci int retry = 0; 948c2ecf20Sopenharmony_ci u8 csum_byte; 958c2ecf20Sopenharmony_ci u8 high_bits; 968c2ecf20Sopenharmony_ci u8 low_bits; 978c2ecf20Sopenharmony_ci u8 reg_high; 988c2ecf20Sopenharmony_ci u8 csum; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci reg_high = ((reg >> 7) & 0xFE) | 1; /* Indicate read combined */ 1018c2ecf20Sopenharmony_ci csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); 1028c2ecf20Sopenharmony_ci csum = ~csum; 1038c2ecf20Sopenharmony_ci do { 1048c2ecf20Sopenharmony_ci if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 1058c2ecf20Sopenharmony_ci return -EBUSY; 1068c2ecf20Sopenharmony_ci ixgbe_i2c_start(hw); 1078c2ecf20Sopenharmony_ci /* Device Address and write indication */ 1088c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, addr)) 1098c2ecf20Sopenharmony_ci goto fail; 1108c2ecf20Sopenharmony_ci /* Write bits 14:8 */ 1118c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, reg_high)) 1128c2ecf20Sopenharmony_ci goto fail; 1138c2ecf20Sopenharmony_ci /* Write bits 7:0 */ 1148c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF)) 1158c2ecf20Sopenharmony_ci goto fail; 1168c2ecf20Sopenharmony_ci /* Write csum */ 1178c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, csum)) 1188c2ecf20Sopenharmony_ci goto fail; 1198c2ecf20Sopenharmony_ci /* Re-start condition */ 1208c2ecf20Sopenharmony_ci ixgbe_i2c_start(hw); 1218c2ecf20Sopenharmony_ci /* Device Address and read indication */ 1228c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, addr | 1)) 1238c2ecf20Sopenharmony_ci goto fail; 1248c2ecf20Sopenharmony_ci /* Get upper bits */ 1258c2ecf20Sopenharmony_ci if (ixgbe_in_i2c_byte_ack(hw, &high_bits)) 1268c2ecf20Sopenharmony_ci goto fail; 1278c2ecf20Sopenharmony_ci /* Get low bits */ 1288c2ecf20Sopenharmony_ci if (ixgbe_in_i2c_byte_ack(hw, &low_bits)) 1298c2ecf20Sopenharmony_ci goto fail; 1308c2ecf20Sopenharmony_ci /* Get csum */ 1318c2ecf20Sopenharmony_ci if (ixgbe_clock_in_i2c_byte(hw, &csum_byte)) 1328c2ecf20Sopenharmony_ci goto fail; 1338c2ecf20Sopenharmony_ci /* NACK */ 1348c2ecf20Sopenharmony_ci if (ixgbe_clock_out_i2c_bit(hw, false)) 1358c2ecf20Sopenharmony_ci goto fail; 1368c2ecf20Sopenharmony_ci ixgbe_i2c_stop(hw); 1378c2ecf20Sopenharmony_ci if (lock) 1388c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 1398c2ecf20Sopenharmony_ci *val = (high_bits << 8) | low_bits; 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cifail: 1438c2ecf20Sopenharmony_ci ixgbe_i2c_bus_clear(hw); 1448c2ecf20Sopenharmony_ci if (lock) 1458c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 1468c2ecf20Sopenharmony_ci retry++; 1478c2ecf20Sopenharmony_ci if (retry < max_retry) 1488c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C byte read combined error - Retry.\n"); 1498c2ecf20Sopenharmony_ci else 1508c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C byte read combined error.\n"); 1518c2ecf20Sopenharmony_ci } while (retry < max_retry); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return -EIO; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/** 1578c2ecf20Sopenharmony_ci * ixgbe_write_i2c_combined_generic_int - Perform I2C write combined operation 1588c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 1598c2ecf20Sopenharmony_ci * @addr: I2C bus address to write to 1608c2ecf20Sopenharmony_ci * @reg: I2C device register to write to 1618c2ecf20Sopenharmony_ci * @val: value to write 1628c2ecf20Sopenharmony_ci * @lock: true if to take and release semaphore 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * Returns an error code on error. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_cis32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, 1678c2ecf20Sopenharmony_ci u16 reg, u16 val, bool lock) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci u32 swfw_mask = hw->phy.phy_semaphore_mask; 1708c2ecf20Sopenharmony_ci int max_retry = 1; 1718c2ecf20Sopenharmony_ci int retry = 0; 1728c2ecf20Sopenharmony_ci u8 reg_high; 1738c2ecf20Sopenharmony_ci u8 csum; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci reg_high = (reg >> 7) & 0xFE; /* Indicate write combined */ 1768c2ecf20Sopenharmony_ci csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); 1778c2ecf20Sopenharmony_ci csum = ixgbe_ones_comp_byte_add(csum, val >> 8); 1788c2ecf20Sopenharmony_ci csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF); 1798c2ecf20Sopenharmony_ci csum = ~csum; 1808c2ecf20Sopenharmony_ci do { 1818c2ecf20Sopenharmony_ci if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 1828c2ecf20Sopenharmony_ci return -EBUSY; 1838c2ecf20Sopenharmony_ci ixgbe_i2c_start(hw); 1848c2ecf20Sopenharmony_ci /* Device Address and write indication */ 1858c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, addr)) 1868c2ecf20Sopenharmony_ci goto fail; 1878c2ecf20Sopenharmony_ci /* Write bits 14:8 */ 1888c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, reg_high)) 1898c2ecf20Sopenharmony_ci goto fail; 1908c2ecf20Sopenharmony_ci /* Write bits 7:0 */ 1918c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF)) 1928c2ecf20Sopenharmony_ci goto fail; 1938c2ecf20Sopenharmony_ci /* Write data 15:8 */ 1948c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, val >> 8)) 1958c2ecf20Sopenharmony_ci goto fail; 1968c2ecf20Sopenharmony_ci /* Write data 7:0 */ 1978c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, val & 0xFF)) 1988c2ecf20Sopenharmony_ci goto fail; 1998c2ecf20Sopenharmony_ci /* Write csum */ 2008c2ecf20Sopenharmony_ci if (ixgbe_out_i2c_byte_ack(hw, csum)) 2018c2ecf20Sopenharmony_ci goto fail; 2028c2ecf20Sopenharmony_ci ixgbe_i2c_stop(hw); 2038c2ecf20Sopenharmony_ci if (lock) 2048c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cifail: 2088c2ecf20Sopenharmony_ci ixgbe_i2c_bus_clear(hw); 2098c2ecf20Sopenharmony_ci if (lock) 2108c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 2118c2ecf20Sopenharmony_ci retry++; 2128c2ecf20Sopenharmony_ci if (retry < max_retry) 2138c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C byte write combined error - Retry.\n"); 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C byte write combined error.\n"); 2168c2ecf20Sopenharmony_ci } while (retry < max_retry); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return -EIO; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/** 2228c2ecf20Sopenharmony_ci * ixgbe_probe_phy - Probe a single address for a PHY 2238c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 2248c2ecf20Sopenharmony_ci * @phy_addr: PHY address to probe 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * Returns true if PHY found 2278c2ecf20Sopenharmony_ci **/ 2288c2ecf20Sopenharmony_cistatic bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci u16 ext_ability = 0; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci hw->phy.mdio.prtad = phy_addr; 2338c2ecf20Sopenharmony_ci if (mdio45_probe(&hw->phy.mdio, phy_addr) != 0) 2348c2ecf20Sopenharmony_ci return false; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (ixgbe_get_phy_id(hw)) 2378c2ecf20Sopenharmony_ci return false; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (hw->phy.type == ixgbe_phy_unknown) { 2428c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, 2438c2ecf20Sopenharmony_ci MDIO_PMA_EXTABLE, 2448c2ecf20Sopenharmony_ci MDIO_MMD_PMAPMD, 2458c2ecf20Sopenharmony_ci &ext_ability); 2468c2ecf20Sopenharmony_ci if (ext_ability & 2478c2ecf20Sopenharmony_ci (MDIO_PMA_EXTABLE_10GBT | 2488c2ecf20Sopenharmony_ci MDIO_PMA_EXTABLE_1000BT)) 2498c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_cu_unknown; 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_generic; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return true; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/** 2588c2ecf20Sopenharmony_ci * ixgbe_identify_phy_generic - Get physical layer module 2598c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * Determines the physical layer module found on the current adapter. 2628c2ecf20Sopenharmony_ci **/ 2638c2ecf20Sopenharmony_cis32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci u32 status = -EFAULT; 2668c2ecf20Sopenharmony_ci u32 phy_addr; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (!hw->phy.phy_semaphore_mask) { 2698c2ecf20Sopenharmony_ci if (hw->bus.lan_id) 2708c2ecf20Sopenharmony_ci hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM; 2718c2ecf20Sopenharmony_ci else 2728c2ecf20Sopenharmony_ci hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (hw->phy.type != ixgbe_phy_unknown) 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (hw->phy.nw_mng_if_sel) { 2798c2ecf20Sopenharmony_ci phy_addr = (hw->phy.nw_mng_if_sel & 2808c2ecf20Sopenharmony_ci IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >> 2818c2ecf20Sopenharmony_ci IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT; 2828c2ecf20Sopenharmony_ci if (ixgbe_probe_phy(hw, phy_addr)) 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci else 2858c2ecf20Sopenharmony_ci return -EFAULT; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { 2898c2ecf20Sopenharmony_ci if (ixgbe_probe_phy(hw, phy_addr)) { 2908c2ecf20Sopenharmony_ci status = 0; 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Certain media types do not have a phy so an address will not 2968c2ecf20Sopenharmony_ci * be found and the code will take this path. Caller has to 2978c2ecf20Sopenharmony_ci * decide if it is an error or not. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci if (status) 3008c2ecf20Sopenharmony_ci hw->phy.mdio.prtad = MDIO_PRTAD_NONE; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return status; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/** 3068c2ecf20Sopenharmony_ci * ixgbe_check_reset_blocked - check status of MNG FW veto bit 3078c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * This function checks the MMNGC.MNG_VETO bit to see if there are 3108c2ecf20Sopenharmony_ci * any constraints on link from manageability. For MAC's that don't 3118c2ecf20Sopenharmony_ci * have this bit just return false since the link can not be blocked 3128c2ecf20Sopenharmony_ci * via this method. 3138c2ecf20Sopenharmony_ci **/ 3148c2ecf20Sopenharmony_cibool ixgbe_check_reset_blocked(struct ixgbe_hw *hw) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci u32 mmngc; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* If we don't have this bit, it can't be blocking */ 3198c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) 3208c2ecf20Sopenharmony_ci return false; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci mmngc = IXGBE_READ_REG(hw, IXGBE_MMNGC); 3238c2ecf20Sopenharmony_ci if (mmngc & IXGBE_MMNGC_MNG_VETO) { 3248c2ecf20Sopenharmony_ci hw_dbg(hw, "MNG_VETO bit detected.\n"); 3258c2ecf20Sopenharmony_ci return true; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return false; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/** 3328c2ecf20Sopenharmony_ci * ixgbe_get_phy_id - Get the phy type 3338c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 3348c2ecf20Sopenharmony_ci * 3358c2ecf20Sopenharmony_ci **/ 3368c2ecf20Sopenharmony_cistatic s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci s32 status; 3398c2ecf20Sopenharmony_ci u16 phy_id_high = 0; 3408c2ecf20Sopenharmony_ci u16 phy_id_low = 0; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_DEVID1, MDIO_MMD_PMAPMD, 3438c2ecf20Sopenharmony_ci &phy_id_high); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (!status) { 3468c2ecf20Sopenharmony_ci hw->phy.id = (u32)(phy_id_high << 16); 3478c2ecf20Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_DEVID2, MDIO_MMD_PMAPMD, 3488c2ecf20Sopenharmony_ci &phy_id_low); 3498c2ecf20Sopenharmony_ci hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); 3508c2ecf20Sopenharmony_ci hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci return status; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/** 3568c2ecf20Sopenharmony_ci * ixgbe_get_phy_type_from_id - Get the phy type 3578c2ecf20Sopenharmony_ci * @phy_id: hardware phy id 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci **/ 3608c2ecf20Sopenharmony_cistatic enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci enum ixgbe_phy_type phy_type; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci switch (phy_id) { 3658c2ecf20Sopenharmony_ci case TN1010_PHY_ID: 3668c2ecf20Sopenharmony_ci phy_type = ixgbe_phy_tn; 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci case X550_PHY_ID2: 3698c2ecf20Sopenharmony_ci case X550_PHY_ID3: 3708c2ecf20Sopenharmony_ci case X540_PHY_ID: 3718c2ecf20Sopenharmony_ci phy_type = ixgbe_phy_aq; 3728c2ecf20Sopenharmony_ci break; 3738c2ecf20Sopenharmony_ci case QT2022_PHY_ID: 3748c2ecf20Sopenharmony_ci phy_type = ixgbe_phy_qt; 3758c2ecf20Sopenharmony_ci break; 3768c2ecf20Sopenharmony_ci case ATH_PHY_ID: 3778c2ecf20Sopenharmony_ci phy_type = ixgbe_phy_nl; 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci case X557_PHY_ID: 3808c2ecf20Sopenharmony_ci case X557_PHY_ID2: 3818c2ecf20Sopenharmony_ci phy_type = ixgbe_phy_x550em_ext_t; 3828c2ecf20Sopenharmony_ci break; 3838c2ecf20Sopenharmony_ci default: 3848c2ecf20Sopenharmony_ci phy_type = ixgbe_phy_unknown; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return phy_type; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci/** 3928c2ecf20Sopenharmony_ci * ixgbe_reset_phy_generic - Performs a PHY reset 3938c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 3948c2ecf20Sopenharmony_ci **/ 3958c2ecf20Sopenharmony_cis32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci u32 i; 3988c2ecf20Sopenharmony_ci u16 ctrl = 0; 3998c2ecf20Sopenharmony_ci s32 status = 0; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (hw->phy.type == ixgbe_phy_unknown) 4028c2ecf20Sopenharmony_ci status = ixgbe_identify_phy_generic(hw); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (status != 0 || hw->phy.type == ixgbe_phy_none) 4058c2ecf20Sopenharmony_ci return status; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Don't reset PHY if it's shut down due to overtemp. */ 4088c2ecf20Sopenharmony_ci if (!hw->phy.reset_if_overtemp && hw->phy.ops.check_overtemp(hw)) 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Blocked by MNG FW so bail */ 4128c2ecf20Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* 4168c2ecf20Sopenharmony_ci * Perform soft PHY reset to the PHY_XS. 4178c2ecf20Sopenharmony_ci * This will cause a soft reset to the PHY 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_CTRL1, 4208c2ecf20Sopenharmony_ci MDIO_MMD_PHYXS, 4218c2ecf20Sopenharmony_ci MDIO_CTRL1_RESET); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * Poll for reset bit to self-clear indicating reset is complete. 4258c2ecf20Sopenharmony_ci * Some PHYs could take up to 3 seconds to complete and need about 4268c2ecf20Sopenharmony_ci * 1.7 usec delay after the reset is complete. 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci for (i = 0; i < 30; i++) { 4298c2ecf20Sopenharmony_ci msleep(100); 4308c2ecf20Sopenharmony_ci if (hw->phy.type == ixgbe_phy_x550em_ext_t) { 4318c2ecf20Sopenharmony_ci status = hw->phy.ops.read_reg(hw, 4328c2ecf20Sopenharmony_ci IXGBE_MDIO_TX_VENDOR_ALARMS_3, 4338c2ecf20Sopenharmony_ci MDIO_MMD_PMAPMD, &ctrl); 4348c2ecf20Sopenharmony_ci if (status) 4358c2ecf20Sopenharmony_ci return status; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (ctrl & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) { 4388c2ecf20Sopenharmony_ci udelay(2); 4398c2ecf20Sopenharmony_ci break; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci } else { 4428c2ecf20Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_CTRL1, 4438c2ecf20Sopenharmony_ci MDIO_MMD_PHYXS, &ctrl); 4448c2ecf20Sopenharmony_ci if (status) 4458c2ecf20Sopenharmony_ci return status; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (!(ctrl & MDIO_CTRL1_RESET)) { 4488c2ecf20Sopenharmony_ci udelay(2); 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (ctrl & MDIO_CTRL1_RESET) { 4558c2ecf20Sopenharmony_ci hw_dbg(hw, "PHY reset polling failed to complete.\n"); 4568c2ecf20Sopenharmony_ci return -EIO; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return 0; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci/** 4638c2ecf20Sopenharmony_ci * ixgbe_read_phy_mdi - Reads a value from a specified PHY register without 4648c2ecf20Sopenharmony_ci * the SWFW lock 4658c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 4668c2ecf20Sopenharmony_ci * @reg_addr: 32 bit address of PHY register to read 4678c2ecf20Sopenharmony_ci * @device_type: 5 bit device type 4688c2ecf20Sopenharmony_ci * @phy_data: Pointer to read data from PHY register 4698c2ecf20Sopenharmony_ci **/ 4708c2ecf20Sopenharmony_cis32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, 4718c2ecf20Sopenharmony_ci u16 *phy_data) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci u32 i, data, command; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Setup and write the address cycle command */ 4768c2ecf20Sopenharmony_ci command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 4778c2ecf20Sopenharmony_ci (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 4788c2ecf20Sopenharmony_ci (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | 4798c2ecf20Sopenharmony_ci (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* Check every 10 usec to see if the address cycle completed. 4848c2ecf20Sopenharmony_ci * The MDI Command bit will clear when the operation is 4858c2ecf20Sopenharmony_ci * complete 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 4888c2ecf20Sopenharmony_ci udelay(10); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci command = IXGBE_READ_REG(hw, IXGBE_MSCA); 4918c2ecf20Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 4978c2ecf20Sopenharmony_ci hw_dbg(hw, "PHY address command did not complete.\n"); 4988c2ecf20Sopenharmony_ci return -EIO; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* Address cycle complete, setup and write the read 5028c2ecf20Sopenharmony_ci * command 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_ci command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 5058c2ecf20Sopenharmony_ci (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 5068c2ecf20Sopenharmony_ci (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | 5078c2ecf20Sopenharmony_ci (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* Check every 10 usec to see if the address cycle 5128c2ecf20Sopenharmony_ci * completed. The MDI Command bit will clear when the 5138c2ecf20Sopenharmony_ci * operation is complete 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 5168c2ecf20Sopenharmony_ci udelay(10); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci command = IXGBE_READ_REG(hw, IXGBE_MSCA); 5198c2ecf20Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 5248c2ecf20Sopenharmony_ci hw_dbg(hw, "PHY read command didn't complete\n"); 5258c2ecf20Sopenharmony_ci return -EIO; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Read operation is complete. Get the data 5298c2ecf20Sopenharmony_ci * from MSRWD 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_ci data = IXGBE_READ_REG(hw, IXGBE_MSRWD); 5328c2ecf20Sopenharmony_ci data >>= IXGBE_MSRWD_READ_DATA_SHIFT; 5338c2ecf20Sopenharmony_ci *phy_data = (u16)(data); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return 0; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/** 5398c2ecf20Sopenharmony_ci * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register 5408c2ecf20Sopenharmony_ci * using the SWFW lock - this function is needed in most cases 5418c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 5428c2ecf20Sopenharmony_ci * @reg_addr: 32 bit address of PHY register to read 5438c2ecf20Sopenharmony_ci * @device_type: 5 bit device type 5448c2ecf20Sopenharmony_ci * @phy_data: Pointer to read data from PHY register 5458c2ecf20Sopenharmony_ci **/ 5468c2ecf20Sopenharmony_cis32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, 5478c2ecf20Sopenharmony_ci u32 device_type, u16 *phy_data) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci s32 status; 5508c2ecf20Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) { 5538c2ecf20Sopenharmony_ci status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type, 5548c2ecf20Sopenharmony_ci phy_data); 5558c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 5568c2ecf20Sopenharmony_ci } else { 5578c2ecf20Sopenharmony_ci return -EBUSY; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return status; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci/** 5648c2ecf20Sopenharmony_ci * ixgbe_write_phy_reg_mdi - Writes a value to specified PHY register 5658c2ecf20Sopenharmony_ci * without SWFW lock 5668c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 5678c2ecf20Sopenharmony_ci * @reg_addr: 32 bit PHY register to write 5688c2ecf20Sopenharmony_ci * @device_type: 5 bit device type 5698c2ecf20Sopenharmony_ci * @phy_data: Data to write to the PHY register 5708c2ecf20Sopenharmony_ci **/ 5718c2ecf20Sopenharmony_cis32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, 5728c2ecf20Sopenharmony_ci u32 device_type, u16 phy_data) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci u32 i, command; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /* Put the data in the MDI single read and write data register*/ 5778c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* Setup and write the address cycle command */ 5808c2ecf20Sopenharmony_ci command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 5818c2ecf20Sopenharmony_ci (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 5828c2ecf20Sopenharmony_ci (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | 5838c2ecf20Sopenharmony_ci (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* 5888c2ecf20Sopenharmony_ci * Check every 10 usec to see if the address cycle completed. 5898c2ecf20Sopenharmony_ci * The MDI Command bit will clear when the operation is 5908c2ecf20Sopenharmony_ci * complete 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 5938c2ecf20Sopenharmony_ci udelay(10); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci command = IXGBE_READ_REG(hw, IXGBE_MSCA); 5968c2ecf20Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 6018c2ecf20Sopenharmony_ci hw_dbg(hw, "PHY address cmd didn't complete\n"); 6028c2ecf20Sopenharmony_ci return -EIO; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* 6068c2ecf20Sopenharmony_ci * Address cycle complete, setup and write the write 6078c2ecf20Sopenharmony_ci * command 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 6108c2ecf20Sopenharmony_ci (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 6118c2ecf20Sopenharmony_ci (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | 6128c2ecf20Sopenharmony_ci (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* Check every 10 usec to see if the address cycle 6178c2ecf20Sopenharmony_ci * completed. The MDI Command bit will clear when the 6188c2ecf20Sopenharmony_ci * operation is complete 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_ci for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 6218c2ecf20Sopenharmony_ci udelay(10); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci command = IXGBE_READ_REG(hw, IXGBE_MSCA); 6248c2ecf20Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 6258c2ecf20Sopenharmony_ci break; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 6298c2ecf20Sopenharmony_ci hw_dbg(hw, "PHY write cmd didn't complete\n"); 6308c2ecf20Sopenharmony_ci return -EIO; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci return 0; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci/** 6378c2ecf20Sopenharmony_ci * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register 6388c2ecf20Sopenharmony_ci * using SWFW lock- this function is needed in most cases 6398c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 6408c2ecf20Sopenharmony_ci * @reg_addr: 32 bit PHY register to write 6418c2ecf20Sopenharmony_ci * @device_type: 5 bit device type 6428c2ecf20Sopenharmony_ci * @phy_data: Data to write to the PHY register 6438c2ecf20Sopenharmony_ci **/ 6448c2ecf20Sopenharmony_cis32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, 6458c2ecf20Sopenharmony_ci u32 device_type, u16 phy_data) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci s32 status; 6488c2ecf20Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) { 6518c2ecf20Sopenharmony_ci status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, 6528c2ecf20Sopenharmony_ci phy_data); 6538c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 6548c2ecf20Sopenharmony_ci } else { 6558c2ecf20Sopenharmony_ci return -EBUSY; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return status; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci#define IXGBE_HW_READ_REG(addr) IXGBE_READ_REG(hw, addr) 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/** 6648c2ecf20Sopenharmony_ci * ixgbe_msca_cmd - Write the command register and poll for completion/timeout 6658c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 6668c2ecf20Sopenharmony_ci * @cmd: command register value to write 6678c2ecf20Sopenharmony_ci **/ 6688c2ecf20Sopenharmony_cistatic s32 ixgbe_msca_cmd(struct ixgbe_hw *hw, u32 cmd) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSCA, cmd); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return readx_poll_timeout(IXGBE_HW_READ_REG, IXGBE_MSCA, cmd, 6738c2ecf20Sopenharmony_ci !(cmd & IXGBE_MSCA_MDI_COMMAND), 10, 6748c2ecf20Sopenharmony_ci 10 * IXGBE_MDIO_COMMAND_TIMEOUT); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci/** 6788c2ecf20Sopenharmony_ci * ixgbe_mii_bus_read_generic - Read a clause 22/45 register with gssr flags 6798c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 6808c2ecf20Sopenharmony_ci * @addr: address 6818c2ecf20Sopenharmony_ci * @regnum: register number 6828c2ecf20Sopenharmony_ci * @gssr: semaphore flags to acquire 6838c2ecf20Sopenharmony_ci **/ 6848c2ecf20Sopenharmony_cistatic s32 ixgbe_mii_bus_read_generic(struct ixgbe_hw *hw, int addr, 6858c2ecf20Sopenharmony_ci int regnum, u32 gssr) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci u32 hwaddr, cmd; 6888c2ecf20Sopenharmony_ci s32 data; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) 6918c2ecf20Sopenharmony_ci return -EBUSY; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci hwaddr = addr << IXGBE_MSCA_PHY_ADDR_SHIFT; 6948c2ecf20Sopenharmony_ci if (regnum & MII_ADDR_C45) { 6958c2ecf20Sopenharmony_ci hwaddr |= regnum & GENMASK(21, 0); 6968c2ecf20Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND; 6978c2ecf20Sopenharmony_ci } else { 6988c2ecf20Sopenharmony_ci hwaddr |= (regnum & GENMASK(5, 0)) << IXGBE_MSCA_DEV_TYPE_SHIFT; 6998c2ecf20Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_OLD_PROTOCOL | 7008c2ecf20Sopenharmony_ci IXGBE_MSCA_READ_AUTOINC | IXGBE_MSCA_MDI_COMMAND; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci data = ixgbe_msca_cmd(hw, cmd); 7048c2ecf20Sopenharmony_ci if (data < 0) 7058c2ecf20Sopenharmony_ci goto mii_bus_read_done; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* For a clause 45 access the address cycle just completed, we still 7088c2ecf20Sopenharmony_ci * need to do the read command, otherwise just get the data 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_ci if (!(regnum & MII_ADDR_C45)) 7118c2ecf20Sopenharmony_ci goto do_mii_bus_read; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND; 7148c2ecf20Sopenharmony_ci data = ixgbe_msca_cmd(hw, cmd); 7158c2ecf20Sopenharmony_ci if (data < 0) 7168c2ecf20Sopenharmony_ci goto mii_bus_read_done; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cido_mii_bus_read: 7198c2ecf20Sopenharmony_ci data = IXGBE_READ_REG(hw, IXGBE_MSRWD); 7208c2ecf20Sopenharmony_ci data = (data >> IXGBE_MSRWD_READ_DATA_SHIFT) & GENMASK(16, 0); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cimii_bus_read_done: 7238c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 7248c2ecf20Sopenharmony_ci return data; 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci/** 7288c2ecf20Sopenharmony_ci * ixgbe_mii_bus_write_generic - Write a clause 22/45 register with gssr flags 7298c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 7308c2ecf20Sopenharmony_ci * @addr: address 7318c2ecf20Sopenharmony_ci * @regnum: register number 7328c2ecf20Sopenharmony_ci * @val: value to write 7338c2ecf20Sopenharmony_ci * @gssr: semaphore flags to acquire 7348c2ecf20Sopenharmony_ci **/ 7358c2ecf20Sopenharmony_cistatic s32 ixgbe_mii_bus_write_generic(struct ixgbe_hw *hw, int addr, 7368c2ecf20Sopenharmony_ci int regnum, u16 val, u32 gssr) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci u32 hwaddr, cmd; 7398c2ecf20Sopenharmony_ci s32 err; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) 7428c2ecf20Sopenharmony_ci return -EBUSY; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)val); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci hwaddr = addr << IXGBE_MSCA_PHY_ADDR_SHIFT; 7478c2ecf20Sopenharmony_ci if (regnum & MII_ADDR_C45) { 7488c2ecf20Sopenharmony_ci hwaddr |= regnum & GENMASK(21, 0); 7498c2ecf20Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND; 7508c2ecf20Sopenharmony_ci } else { 7518c2ecf20Sopenharmony_ci hwaddr |= (regnum & GENMASK(5, 0)) << IXGBE_MSCA_DEV_TYPE_SHIFT; 7528c2ecf20Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_WRITE | 7538c2ecf20Sopenharmony_ci IXGBE_MSCA_MDI_COMMAND; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* For clause 45 this is an address cycle, for clause 22 this is the 7578c2ecf20Sopenharmony_ci * entire transaction 7588c2ecf20Sopenharmony_ci */ 7598c2ecf20Sopenharmony_ci err = ixgbe_msca_cmd(hw, cmd); 7608c2ecf20Sopenharmony_ci if (err < 0 || !(regnum & MII_ADDR_C45)) 7618c2ecf20Sopenharmony_ci goto mii_bus_write_done; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci cmd = hwaddr | IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND; 7648c2ecf20Sopenharmony_ci err = ixgbe_msca_cmd(hw, cmd); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cimii_bus_write_done: 7678c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, gssr); 7688c2ecf20Sopenharmony_ci return err; 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci/** 7728c2ecf20Sopenharmony_ci * ixgbe_mii_bus_read - Read a clause 22/45 register 7738c2ecf20Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 7748c2ecf20Sopenharmony_ci * @addr: address 7758c2ecf20Sopenharmony_ci * @regnum: register number 7768c2ecf20Sopenharmony_ci **/ 7778c2ecf20Sopenharmony_cistatic s32 ixgbe_mii_bus_read(struct mii_bus *bus, int addr, int regnum) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 7808c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 7818c2ecf20Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci return ixgbe_mii_bus_read_generic(hw, addr, regnum, gssr); 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci/** 7878c2ecf20Sopenharmony_ci * ixgbe_mii_bus_write - Write a clause 22/45 register 7888c2ecf20Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 7898c2ecf20Sopenharmony_ci * @addr: address 7908c2ecf20Sopenharmony_ci * @regnum: register number 7918c2ecf20Sopenharmony_ci * @val: value to write 7928c2ecf20Sopenharmony_ci **/ 7938c2ecf20Sopenharmony_cistatic s32 ixgbe_mii_bus_write(struct mii_bus *bus, int addr, int regnum, 7948c2ecf20Sopenharmony_ci u16 val) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 7978c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 7988c2ecf20Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return ixgbe_mii_bus_write_generic(hw, addr, regnum, val, gssr); 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci/** 8048c2ecf20Sopenharmony_ci * ixgbe_x550em_a_mii_bus_read - Read a clause 22/45 register on x550em_a 8058c2ecf20Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 8068c2ecf20Sopenharmony_ci * @addr: address 8078c2ecf20Sopenharmony_ci * @regnum: register number 8088c2ecf20Sopenharmony_ci **/ 8098c2ecf20Sopenharmony_cistatic s32 ixgbe_x550em_a_mii_bus_read(struct mii_bus *bus, int addr, 8108c2ecf20Sopenharmony_ci int regnum) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 8138c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 8148c2ecf20Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci gssr |= IXGBE_GSSR_TOKEN_SM | IXGBE_GSSR_PHY0_SM; 8178c2ecf20Sopenharmony_ci return ixgbe_mii_bus_read_generic(hw, addr, regnum, gssr); 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci/** 8218c2ecf20Sopenharmony_ci * ixgbe_x550em_a_mii_bus_write - Write a clause 22/45 register on x550em_a 8228c2ecf20Sopenharmony_ci * @bus: pointer to mii_bus structure which points to our driver private 8238c2ecf20Sopenharmony_ci * @addr: address 8248c2ecf20Sopenharmony_ci * @regnum: register number 8258c2ecf20Sopenharmony_ci * @val: value to write 8268c2ecf20Sopenharmony_ci **/ 8278c2ecf20Sopenharmony_cistatic s32 ixgbe_x550em_a_mii_bus_write(struct mii_bus *bus, int addr, 8288c2ecf20Sopenharmony_ci int regnum, u16 val) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = bus->priv; 8318c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 8328c2ecf20Sopenharmony_ci u32 gssr = hw->phy.phy_semaphore_mask; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci gssr |= IXGBE_GSSR_TOKEN_SM | IXGBE_GSSR_PHY0_SM; 8358c2ecf20Sopenharmony_ci return ixgbe_mii_bus_write_generic(hw, addr, regnum, val, gssr); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci/** 8398c2ecf20Sopenharmony_ci * ixgbe_get_first_secondary_devfn - get first device downstream of root port 8408c2ecf20Sopenharmony_ci * @devfn: PCI_DEVFN of root port on domain 0, bus 0 8418c2ecf20Sopenharmony_ci * 8428c2ecf20Sopenharmony_ci * Returns pci_dev pointer to PCI_DEVFN(0, 0) on subordinate side of root 8438c2ecf20Sopenharmony_ci * on domain 0, bus 0, devfn = 'devfn' 8448c2ecf20Sopenharmony_ci **/ 8458c2ecf20Sopenharmony_cistatic struct pci_dev *ixgbe_get_first_secondary_devfn(unsigned int devfn) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct pci_dev *rp_pdev; 8488c2ecf20Sopenharmony_ci int bus; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci rp_pdev = pci_get_domain_bus_and_slot(0, 0, devfn); 8518c2ecf20Sopenharmony_ci if (rp_pdev && rp_pdev->subordinate) { 8528c2ecf20Sopenharmony_ci bus = rp_pdev->subordinate->number; 8538c2ecf20Sopenharmony_ci pci_dev_put(rp_pdev); 8548c2ecf20Sopenharmony_ci return pci_get_domain_bus_and_slot(0, bus, 0); 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci pci_dev_put(rp_pdev); 8588c2ecf20Sopenharmony_ci return NULL; 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci/** 8628c2ecf20Sopenharmony_ci * ixgbe_x550em_a_has_mii - is this the first ixgbe x550em_a PCI function? 8638c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 8648c2ecf20Sopenharmony_ci * 8658c2ecf20Sopenharmony_ci * Returns true if hw points to lowest numbered PCI B:D.F x550_em_a device in 8668c2ecf20Sopenharmony_ci * the SoC. There are up to 4 MACs sharing a single MDIO bus on the x550em_a, 8678c2ecf20Sopenharmony_ci * but we only want to register one MDIO bus. 8688c2ecf20Sopenharmony_ci **/ 8698c2ecf20Sopenharmony_cistatic bool ixgbe_x550em_a_has_mii(struct ixgbe_hw *hw) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = hw->back; 8728c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 8738c2ecf20Sopenharmony_ci struct pci_dev *func0_pdev; 8748c2ecf20Sopenharmony_ci bool has_mii = false; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* For the C3000 family of SoCs (x550em_a) the internal ixgbe devices 8778c2ecf20Sopenharmony_ci * are always downstream of root ports @ 0000:00:16.0 & 0000:00:17.0 8788c2ecf20Sopenharmony_ci * It's not valid for function 0 to be disabled and function 1 is up, 8798c2ecf20Sopenharmony_ci * so the lowest numbered ixgbe dev will be device 0 function 0 on one 8808c2ecf20Sopenharmony_ci * of those two root ports 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x16, 0)); 8838c2ecf20Sopenharmony_ci if (func0_pdev) { 8848c2ecf20Sopenharmony_ci if (func0_pdev == pdev) 8858c2ecf20Sopenharmony_ci has_mii = true; 8868c2ecf20Sopenharmony_ci goto out; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x17, 0)); 8898c2ecf20Sopenharmony_ci if (func0_pdev == pdev) 8908c2ecf20Sopenharmony_ci has_mii = true; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ciout: 8938c2ecf20Sopenharmony_ci pci_dev_put(func0_pdev); 8948c2ecf20Sopenharmony_ci return has_mii; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci/** 8988c2ecf20Sopenharmony_ci * ixgbe_mii_bus_init - mii_bus structure setup 8998c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 9008c2ecf20Sopenharmony_ci * 9018c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 9028c2ecf20Sopenharmony_ci * 9038c2ecf20Sopenharmony_ci * ixgbe_mii_bus_init initializes a mii_bus structure in adapter 9048c2ecf20Sopenharmony_ci **/ 9058c2ecf20Sopenharmony_cis32 ixgbe_mii_bus_init(struct ixgbe_hw *hw) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci s32 (*write)(struct mii_bus *bus, int addr, int regnum, u16 val); 9088c2ecf20Sopenharmony_ci s32 (*read)(struct mii_bus *bus, int addr, int regnum); 9098c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = hw->back; 9108c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 9118c2ecf20Sopenharmony_ci struct device *dev = &adapter->netdev->dev; 9128c2ecf20Sopenharmony_ci struct mii_bus *bus; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci switch (hw->device_id) { 9158c2ecf20Sopenharmony_ci /* C3000 SoCs */ 9168c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_KR: 9178c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_KR_L: 9188c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SFP_N: 9198c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SGMII: 9208c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SGMII_L: 9218c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_10G_T: 9228c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_SFP: 9238c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_1G_T: 9248c2ecf20Sopenharmony_ci case IXGBE_DEV_ID_X550EM_A_1G_T_L: 9258c2ecf20Sopenharmony_ci if (!ixgbe_x550em_a_has_mii(hw)) 9268c2ecf20Sopenharmony_ci return 0; 9278c2ecf20Sopenharmony_ci read = &ixgbe_x550em_a_mii_bus_read; 9288c2ecf20Sopenharmony_ci write = &ixgbe_x550em_a_mii_bus_write; 9298c2ecf20Sopenharmony_ci break; 9308c2ecf20Sopenharmony_ci default: 9318c2ecf20Sopenharmony_ci read = &ixgbe_mii_bus_read; 9328c2ecf20Sopenharmony_ci write = &ixgbe_mii_bus_write; 9338c2ecf20Sopenharmony_ci break; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci bus = devm_mdiobus_alloc(dev); 9378c2ecf20Sopenharmony_ci if (!bus) 9388c2ecf20Sopenharmony_ci return -ENOMEM; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci bus->read = read; 9418c2ecf20Sopenharmony_ci bus->write = write; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* Use the position of the device in the PCI hierarchy as the id */ 9448c2ecf20Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mdio-%s", ixgbe_driver_name, 9458c2ecf20Sopenharmony_ci pci_name(pdev)); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci bus->name = "ixgbe-mdio"; 9488c2ecf20Sopenharmony_ci bus->priv = adapter; 9498c2ecf20Sopenharmony_ci bus->parent = dev; 9508c2ecf20Sopenharmony_ci bus->phy_mask = GENMASK(31, 0); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* Support clause 22/45 natively. ixgbe_probe() sets MDIO_EMULATE_C22 9538c2ecf20Sopenharmony_ci * unfortunately that causes some clause 22 frames to be sent with 9548c2ecf20Sopenharmony_ci * clause 45 addressing. We don't want that. 9558c2ecf20Sopenharmony_ci */ 9568c2ecf20Sopenharmony_ci hw->phy.mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci adapter->mii_bus = bus; 9598c2ecf20Sopenharmony_ci return mdiobus_register(bus); 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci/** 9638c2ecf20Sopenharmony_ci * ixgbe_setup_phy_link_generic - Set and restart autoneg 9648c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 9658c2ecf20Sopenharmony_ci * 9668c2ecf20Sopenharmony_ci * Restart autonegotiation and PHY and waits for completion. 9678c2ecf20Sopenharmony_ci **/ 9688c2ecf20Sopenharmony_cis32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci s32 status = 0; 9718c2ecf20Sopenharmony_ci u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; 9728c2ecf20Sopenharmony_ci bool autoneg = false; 9738c2ecf20Sopenharmony_ci ixgbe_link_speed speed; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* Set or unset auto-negotiation 10G advertisement */ 9788c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_10GBT_CTRL, MDIO_MMD_AN, &autoneg_reg); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci autoneg_reg &= ~MDIO_AN_10GBT_CTRL_ADV10G; 9818c2ecf20Sopenharmony_ci if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) && 9828c2ecf20Sopenharmony_ci (speed & IXGBE_LINK_SPEED_10GB_FULL)) 9838c2ecf20Sopenharmony_ci autoneg_reg |= MDIO_AN_10GBT_CTRL_ADV10G; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_AN_10GBT_CTRL, MDIO_MMD_AN, autoneg_reg); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, 9888c2ecf20Sopenharmony_ci MDIO_MMD_AN, &autoneg_reg); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_X550) { 9918c2ecf20Sopenharmony_ci /* Set or unset auto-negotiation 5G advertisement */ 9928c2ecf20Sopenharmony_ci autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE; 9938c2ecf20Sopenharmony_ci if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) && 9948c2ecf20Sopenharmony_ci (speed & IXGBE_LINK_SPEED_5GB_FULL)) 9958c2ecf20Sopenharmony_ci autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* Set or unset auto-negotiation 2.5G advertisement */ 9988c2ecf20Sopenharmony_ci autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE; 9998c2ecf20Sopenharmony_ci if ((hw->phy.autoneg_advertised & 10008c2ecf20Sopenharmony_ci IXGBE_LINK_SPEED_2_5GB_FULL) && 10018c2ecf20Sopenharmony_ci (speed & IXGBE_LINK_SPEED_2_5GB_FULL)) 10028c2ecf20Sopenharmony_ci autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* Set or unset auto-negotiation 1G advertisement */ 10068c2ecf20Sopenharmony_ci autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE; 10078c2ecf20Sopenharmony_ci if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) && 10088c2ecf20Sopenharmony_ci (speed & IXGBE_LINK_SPEED_1GB_FULL)) 10098c2ecf20Sopenharmony_ci autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, 10128c2ecf20Sopenharmony_ci MDIO_MMD_AN, autoneg_reg); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci /* Set or unset auto-negotiation 100M advertisement */ 10158c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, &autoneg_reg); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci autoneg_reg &= ~(ADVERTISE_100FULL | ADVERTISE_100HALF); 10188c2ecf20Sopenharmony_ci if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) && 10198c2ecf20Sopenharmony_ci (speed & IXGBE_LINK_SPEED_100_FULL)) 10208c2ecf20Sopenharmony_ci autoneg_reg |= ADVERTISE_100FULL; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, autoneg_reg); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* Blocked by MNG FW so don't reset PHY */ 10258c2ecf20Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 10268c2ecf20Sopenharmony_ci return 0; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* Restart PHY autonegotiation and wait for completion */ 10298c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_CTRL1, 10308c2ecf20Sopenharmony_ci MDIO_MMD_AN, &autoneg_reg); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci autoneg_reg |= MDIO_AN_CTRL1_RESTART; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_CTRL1, 10358c2ecf20Sopenharmony_ci MDIO_MMD_AN, autoneg_reg); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci return status; 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci/** 10418c2ecf20Sopenharmony_ci * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities 10428c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 10438c2ecf20Sopenharmony_ci * @speed: new link speed 10448c2ecf20Sopenharmony_ci * @autoneg_wait_to_complete: unused 10458c2ecf20Sopenharmony_ci **/ 10468c2ecf20Sopenharmony_cis32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, 10478c2ecf20Sopenharmony_ci ixgbe_link_speed speed, 10488c2ecf20Sopenharmony_ci bool autoneg_wait_to_complete) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci /* Clear autoneg_advertised and set new values based on input link 10518c2ecf20Sopenharmony_ci * speed. 10528c2ecf20Sopenharmony_ci */ 10538c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised = 0; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10GB_FULL) 10568c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_5GB_FULL) 10598c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_5GB_FULL; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_2_5GB_FULL) 10628c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_2_5GB_FULL; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_1GB_FULL) 10658c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_100_FULL) 10688c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10_FULL) 10718c2ecf20Sopenharmony_ci hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10_FULL; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Setup link based on the new speed settings */ 10748c2ecf20Sopenharmony_ci if (hw->phy.ops.setup_link) 10758c2ecf20Sopenharmony_ci hw->phy.ops.setup_link(hw); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return 0; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci/** 10818c2ecf20Sopenharmony_ci * ixgbe_get_copper_speeds_supported - Get copper link speed from phy 10828c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 10838c2ecf20Sopenharmony_ci * 10848c2ecf20Sopenharmony_ci * Determines the supported link capabilities by reading the PHY auto 10858c2ecf20Sopenharmony_ci * negotiation register. 10868c2ecf20Sopenharmony_ci */ 10878c2ecf20Sopenharmony_cistatic s32 ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci u16 speed_ability; 10908c2ecf20Sopenharmony_ci s32 status; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD, 10938c2ecf20Sopenharmony_ci &speed_ability); 10948c2ecf20Sopenharmony_ci if (status) 10958c2ecf20Sopenharmony_ci return status; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (speed_ability & MDIO_SPEED_10G) 10988c2ecf20Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL; 10998c2ecf20Sopenharmony_ci if (speed_ability & MDIO_PMA_SPEED_1000) 11008c2ecf20Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL; 11018c2ecf20Sopenharmony_ci if (speed_ability & MDIO_PMA_SPEED_100) 11028c2ecf20Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci switch (hw->mac.type) { 11058c2ecf20Sopenharmony_ci case ixgbe_mac_X550: 11068c2ecf20Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL; 11078c2ecf20Sopenharmony_ci hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL; 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 11108c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 11118c2ecf20Sopenharmony_ci hw->phy.speeds_supported &= ~IXGBE_LINK_SPEED_100_FULL; 11128c2ecf20Sopenharmony_ci break; 11138c2ecf20Sopenharmony_ci default: 11148c2ecf20Sopenharmony_ci break; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci return 0; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci/** 11218c2ecf20Sopenharmony_ci * ixgbe_get_copper_link_capabilities_generic - Determines link capabilities 11228c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 11238c2ecf20Sopenharmony_ci * @speed: pointer to link speed 11248c2ecf20Sopenharmony_ci * @autoneg: boolean auto-negotiation value 11258c2ecf20Sopenharmony_ci */ 11268c2ecf20Sopenharmony_cis32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, 11278c2ecf20Sopenharmony_ci ixgbe_link_speed *speed, 11288c2ecf20Sopenharmony_ci bool *autoneg) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci s32 status = 0; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci *autoneg = true; 11338c2ecf20Sopenharmony_ci if (!hw->phy.speeds_supported) 11348c2ecf20Sopenharmony_ci status = ixgbe_get_copper_speeds_supported(hw); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci *speed = hw->phy.speeds_supported; 11378c2ecf20Sopenharmony_ci return status; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci/** 11418c2ecf20Sopenharmony_ci * ixgbe_check_phy_link_tnx - Determine link and speed status 11428c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 11438c2ecf20Sopenharmony_ci * @speed: link speed 11448c2ecf20Sopenharmony_ci * @link_up: status of link 11458c2ecf20Sopenharmony_ci * 11468c2ecf20Sopenharmony_ci * Reads the VS1 register to determine if link is up and the current speed for 11478c2ecf20Sopenharmony_ci * the PHY. 11488c2ecf20Sopenharmony_ci **/ 11498c2ecf20Sopenharmony_cis32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, 11508c2ecf20Sopenharmony_ci bool *link_up) 11518c2ecf20Sopenharmony_ci{ 11528c2ecf20Sopenharmony_ci s32 status; 11538c2ecf20Sopenharmony_ci u32 time_out; 11548c2ecf20Sopenharmony_ci u32 max_time_out = 10; 11558c2ecf20Sopenharmony_ci u16 phy_link = 0; 11568c2ecf20Sopenharmony_ci u16 phy_speed = 0; 11578c2ecf20Sopenharmony_ci u16 phy_data = 0; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* Initialize speed and link to default case */ 11608c2ecf20Sopenharmony_ci *link_up = false; 11618c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_10GB_FULL; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci /* 11648c2ecf20Sopenharmony_ci * Check current speed and link status of the PHY register. 11658c2ecf20Sopenharmony_ci * This is a vendor specific register and may have to 11668c2ecf20Sopenharmony_ci * be changed for other copper PHYs. 11678c2ecf20Sopenharmony_ci */ 11688c2ecf20Sopenharmony_ci for (time_out = 0; time_out < max_time_out; time_out++) { 11698c2ecf20Sopenharmony_ci udelay(10); 11708c2ecf20Sopenharmony_ci status = hw->phy.ops.read_reg(hw, 11718c2ecf20Sopenharmony_ci MDIO_STAT1, 11728c2ecf20Sopenharmony_ci MDIO_MMD_VEND1, 11738c2ecf20Sopenharmony_ci &phy_data); 11748c2ecf20Sopenharmony_ci phy_link = phy_data & 11758c2ecf20Sopenharmony_ci IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; 11768c2ecf20Sopenharmony_ci phy_speed = phy_data & 11778c2ecf20Sopenharmony_ci IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; 11788c2ecf20Sopenharmony_ci if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { 11798c2ecf20Sopenharmony_ci *link_up = true; 11808c2ecf20Sopenharmony_ci if (phy_speed == 11818c2ecf20Sopenharmony_ci IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) 11828c2ecf20Sopenharmony_ci *speed = IXGBE_LINK_SPEED_1GB_FULL; 11838c2ecf20Sopenharmony_ci break; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci return status; 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci/** 11918c2ecf20Sopenharmony_ci * ixgbe_setup_phy_link_tnx - Set and restart autoneg 11928c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 11938c2ecf20Sopenharmony_ci * 11948c2ecf20Sopenharmony_ci * Restart autonegotiation and PHY and waits for completion. 11958c2ecf20Sopenharmony_ci * This function always returns success, this is nessary since 11968c2ecf20Sopenharmony_ci * it is called via a function pointer that could call other 11978c2ecf20Sopenharmony_ci * functions that could return an error. 11988c2ecf20Sopenharmony_ci **/ 11998c2ecf20Sopenharmony_cis32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; 12028c2ecf20Sopenharmony_ci bool autoneg = false; 12038c2ecf20Sopenharmony_ci ixgbe_link_speed speed; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_10GB_FULL) { 12088c2ecf20Sopenharmony_ci /* Set or unset auto-negotiation 10G advertisement */ 12098c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_10GBT_CTRL, 12108c2ecf20Sopenharmony_ci MDIO_MMD_AN, 12118c2ecf20Sopenharmony_ci &autoneg_reg); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci autoneg_reg &= ~MDIO_AN_10GBT_CTRL_ADV10G; 12148c2ecf20Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) 12158c2ecf20Sopenharmony_ci autoneg_reg |= MDIO_AN_10GBT_CTRL_ADV10G; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_AN_10GBT_CTRL, 12188c2ecf20Sopenharmony_ci MDIO_MMD_AN, 12198c2ecf20Sopenharmony_ci autoneg_reg); 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_1GB_FULL) { 12238c2ecf20Sopenharmony_ci /* Set or unset auto-negotiation 1G advertisement */ 12248c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG, 12258c2ecf20Sopenharmony_ci MDIO_MMD_AN, 12268c2ecf20Sopenharmony_ci &autoneg_reg); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX; 12298c2ecf20Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) 12308c2ecf20Sopenharmony_ci autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG, 12338c2ecf20Sopenharmony_ci MDIO_MMD_AN, 12348c2ecf20Sopenharmony_ci autoneg_reg); 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (speed & IXGBE_LINK_SPEED_100_FULL) { 12388c2ecf20Sopenharmony_ci /* Set or unset auto-negotiation 100M advertisement */ 12398c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, 12408c2ecf20Sopenharmony_ci MDIO_MMD_AN, 12418c2ecf20Sopenharmony_ci &autoneg_reg); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci autoneg_reg &= ~(ADVERTISE_100FULL | 12448c2ecf20Sopenharmony_ci ADVERTISE_100HALF); 12458c2ecf20Sopenharmony_ci if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) 12468c2ecf20Sopenharmony_ci autoneg_reg |= ADVERTISE_100FULL; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, 12498c2ecf20Sopenharmony_ci MDIO_MMD_AN, 12508c2ecf20Sopenharmony_ci autoneg_reg); 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci /* Blocked by MNG FW so don't reset PHY */ 12548c2ecf20Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 12558c2ecf20Sopenharmony_ci return 0; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* Restart PHY autonegotiation and wait for completion */ 12588c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_CTRL1, 12598c2ecf20Sopenharmony_ci MDIO_MMD_AN, &autoneg_reg); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci autoneg_reg |= MDIO_AN_CTRL1_RESTART; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_CTRL1, 12648c2ecf20Sopenharmony_ci MDIO_MMD_AN, autoneg_reg); 12658c2ecf20Sopenharmony_ci return 0; 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci/** 12698c2ecf20Sopenharmony_ci * ixgbe_reset_phy_nl - Performs a PHY reset 12708c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 12718c2ecf20Sopenharmony_ci **/ 12728c2ecf20Sopenharmony_cis32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci u16 phy_offset, control, eword, edata, block_crc; 12758c2ecf20Sopenharmony_ci bool end_data = false; 12768c2ecf20Sopenharmony_ci u16 list_offset, data_offset; 12778c2ecf20Sopenharmony_ci u16 phy_data = 0; 12788c2ecf20Sopenharmony_ci s32 ret_val; 12798c2ecf20Sopenharmony_ci u32 i; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* Blocked by MNG FW so bail */ 12828c2ecf20Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 12838c2ecf20Sopenharmony_ci return 0; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, &phy_data); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci /* reset the PHY and poll for completion */ 12888c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, 12898c2ecf20Sopenharmony_ci (phy_data | MDIO_CTRL1_RESET)); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 12928c2ecf20Sopenharmony_ci hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, 12938c2ecf20Sopenharmony_ci &phy_data); 12948c2ecf20Sopenharmony_ci if ((phy_data & MDIO_CTRL1_RESET) == 0) 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci usleep_range(10000, 20000); 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci if ((phy_data & MDIO_CTRL1_RESET) != 0) { 13008c2ecf20Sopenharmony_ci hw_dbg(hw, "PHY reset did not complete.\n"); 13018c2ecf20Sopenharmony_ci return -EIO; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* Get init offsets */ 13058c2ecf20Sopenharmony_ci ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, 13068c2ecf20Sopenharmony_ci &data_offset); 13078c2ecf20Sopenharmony_ci if (ret_val) 13088c2ecf20Sopenharmony_ci return ret_val; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc); 13118c2ecf20Sopenharmony_ci data_offset++; 13128c2ecf20Sopenharmony_ci while (!end_data) { 13138c2ecf20Sopenharmony_ci /* 13148c2ecf20Sopenharmony_ci * Read control word from PHY init contents offset 13158c2ecf20Sopenharmony_ci */ 13168c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, data_offset, &eword); 13178c2ecf20Sopenharmony_ci if (ret_val) 13188c2ecf20Sopenharmony_ci goto err_eeprom; 13198c2ecf20Sopenharmony_ci control = (eword & IXGBE_CONTROL_MASK_NL) >> 13208c2ecf20Sopenharmony_ci IXGBE_CONTROL_SHIFT_NL; 13218c2ecf20Sopenharmony_ci edata = eword & IXGBE_DATA_MASK_NL; 13228c2ecf20Sopenharmony_ci switch (control) { 13238c2ecf20Sopenharmony_ci case IXGBE_DELAY_NL: 13248c2ecf20Sopenharmony_ci data_offset++; 13258c2ecf20Sopenharmony_ci hw_dbg(hw, "DELAY: %d MS\n", edata); 13268c2ecf20Sopenharmony_ci usleep_range(edata * 1000, edata * 2000); 13278c2ecf20Sopenharmony_ci break; 13288c2ecf20Sopenharmony_ci case IXGBE_DATA_NL: 13298c2ecf20Sopenharmony_ci hw_dbg(hw, "DATA:\n"); 13308c2ecf20Sopenharmony_ci data_offset++; 13318c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, data_offset++, 13328c2ecf20Sopenharmony_ci &phy_offset); 13338c2ecf20Sopenharmony_ci if (ret_val) 13348c2ecf20Sopenharmony_ci goto err_eeprom; 13358c2ecf20Sopenharmony_ci for (i = 0; i < edata; i++) { 13368c2ecf20Sopenharmony_ci ret_val = hw->eeprom.ops.read(hw, data_offset, 13378c2ecf20Sopenharmony_ci &eword); 13388c2ecf20Sopenharmony_ci if (ret_val) 13398c2ecf20Sopenharmony_ci goto err_eeprom; 13408c2ecf20Sopenharmony_ci hw->phy.ops.write_reg(hw, phy_offset, 13418c2ecf20Sopenharmony_ci MDIO_MMD_PMAPMD, eword); 13428c2ecf20Sopenharmony_ci hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword, 13438c2ecf20Sopenharmony_ci phy_offset); 13448c2ecf20Sopenharmony_ci data_offset++; 13458c2ecf20Sopenharmony_ci phy_offset++; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci break; 13488c2ecf20Sopenharmony_ci case IXGBE_CONTROL_NL: 13498c2ecf20Sopenharmony_ci data_offset++; 13508c2ecf20Sopenharmony_ci hw_dbg(hw, "CONTROL:\n"); 13518c2ecf20Sopenharmony_ci if (edata == IXGBE_CONTROL_EOL_NL) { 13528c2ecf20Sopenharmony_ci hw_dbg(hw, "EOL\n"); 13538c2ecf20Sopenharmony_ci end_data = true; 13548c2ecf20Sopenharmony_ci } else if (edata == IXGBE_CONTROL_SOL_NL) { 13558c2ecf20Sopenharmony_ci hw_dbg(hw, "SOL\n"); 13568c2ecf20Sopenharmony_ci } else { 13578c2ecf20Sopenharmony_ci hw_dbg(hw, "Bad control value\n"); 13588c2ecf20Sopenharmony_ci return -EIO; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci break; 13618c2ecf20Sopenharmony_ci default: 13628c2ecf20Sopenharmony_ci hw_dbg(hw, "Bad control type\n"); 13638c2ecf20Sopenharmony_ci return -EIO; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci return ret_val; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cierr_eeprom: 13708c2ecf20Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", data_offset); 13718c2ecf20Sopenharmony_ci return -EIO; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci/** 13758c2ecf20Sopenharmony_ci * ixgbe_identify_module_generic - Identifies module type 13768c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 13778c2ecf20Sopenharmony_ci * 13788c2ecf20Sopenharmony_ci * Determines HW type and calls appropriate function. 13798c2ecf20Sopenharmony_ci **/ 13808c2ecf20Sopenharmony_cis32 ixgbe_identify_module_generic(struct ixgbe_hw *hw) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci switch (hw->mac.ops.get_media_type(hw)) { 13838c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber: 13848c2ecf20Sopenharmony_ci return ixgbe_identify_sfp_module_generic(hw); 13858c2ecf20Sopenharmony_ci case ixgbe_media_type_fiber_qsfp: 13868c2ecf20Sopenharmony_ci return ixgbe_identify_qsfp_module_generic(hw); 13878c2ecf20Sopenharmony_ci default: 13888c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 13898c2ecf20Sopenharmony_ci return -ENOENT; 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci return -ENOENT; 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci/** 13968c2ecf20Sopenharmony_ci * ixgbe_identify_sfp_module_generic - Identifies SFP modules 13978c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 13988c2ecf20Sopenharmony_ci * 13998c2ecf20Sopenharmony_ci * Searches for and identifies the SFP module and assigns appropriate PHY type. 14008c2ecf20Sopenharmony_ci **/ 14018c2ecf20Sopenharmony_cis32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = hw->back; 14048c2ecf20Sopenharmony_ci s32 status; 14058c2ecf20Sopenharmony_ci u32 vendor_oui = 0; 14068c2ecf20Sopenharmony_ci enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; 14078c2ecf20Sopenharmony_ci u8 identifier = 0; 14088c2ecf20Sopenharmony_ci u8 comp_codes_1g = 0; 14098c2ecf20Sopenharmony_ci u8 comp_codes_10g = 0; 14108c2ecf20Sopenharmony_ci u8 oui_bytes[3] = {0, 0, 0}; 14118c2ecf20Sopenharmony_ci u8 cable_tech = 0; 14128c2ecf20Sopenharmony_ci u8 cable_spec = 0; 14138c2ecf20Sopenharmony_ci u16 enforce_sfp = 0; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) { 14168c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 14178c2ecf20Sopenharmony_ci return -ENOENT; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* LAN ID is needed for sfp_type determination */ 14218c2ecf20Sopenharmony_ci hw->mac.ops.set_lan_id(hw); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 14248c2ecf20Sopenharmony_ci IXGBE_SFF_IDENTIFIER, 14258c2ecf20Sopenharmony_ci &identifier); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (status) 14288c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci if (identifier != IXGBE_SFF_IDENTIFIER_SFP) { 14318c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 14328c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 14358c2ecf20Sopenharmony_ci IXGBE_SFF_1GBE_COMP_CODES, 14368c2ecf20Sopenharmony_ci &comp_codes_1g); 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci if (status) 14398c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 14428c2ecf20Sopenharmony_ci IXGBE_SFF_10GBE_COMP_CODES, 14438c2ecf20Sopenharmony_ci &comp_codes_10g); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci if (status) 14468c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 14478c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 14488c2ecf20Sopenharmony_ci IXGBE_SFF_CABLE_TECHNOLOGY, 14498c2ecf20Sopenharmony_ci &cable_tech); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (status) 14528c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci /* ID Module 14558c2ecf20Sopenharmony_ci * ========= 14568c2ecf20Sopenharmony_ci * 0 SFP_DA_CU 14578c2ecf20Sopenharmony_ci * 1 SFP_SR 14588c2ecf20Sopenharmony_ci * 2 SFP_LR 14598c2ecf20Sopenharmony_ci * 3 SFP_DA_CORE0 - 82599-specific 14608c2ecf20Sopenharmony_ci * 4 SFP_DA_CORE1 - 82599-specific 14618c2ecf20Sopenharmony_ci * 5 SFP_SR/LR_CORE0 - 82599-specific 14628c2ecf20Sopenharmony_ci * 6 SFP_SR/LR_CORE1 - 82599-specific 14638c2ecf20Sopenharmony_ci * 7 SFP_act_lmt_DA_CORE0 - 82599-specific 14648c2ecf20Sopenharmony_ci * 8 SFP_act_lmt_DA_CORE1 - 82599-specific 14658c2ecf20Sopenharmony_ci * 9 SFP_1g_cu_CORE0 - 82599-specific 14668c2ecf20Sopenharmony_ci * 10 SFP_1g_cu_CORE1 - 82599-specific 14678c2ecf20Sopenharmony_ci * 11 SFP_1g_sx_CORE0 - 82599-specific 14688c2ecf20Sopenharmony_ci * 12 SFP_1g_sx_CORE1 - 82599-specific 14698c2ecf20Sopenharmony_ci */ 14708c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) { 14718c2ecf20Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) 14728c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_da_cu; 14738c2ecf20Sopenharmony_ci else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) 14748c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_sr; 14758c2ecf20Sopenharmony_ci else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) 14768c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_lr; 14778c2ecf20Sopenharmony_ci else 14788c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_unknown; 14798c2ecf20Sopenharmony_ci } else { 14808c2ecf20Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { 14818c2ecf20Sopenharmony_ci if (hw->bus.lan_id == 0) 14828c2ecf20Sopenharmony_ci hw->phy.sfp_type = 14838c2ecf20Sopenharmony_ci ixgbe_sfp_type_da_cu_core0; 14848c2ecf20Sopenharmony_ci else 14858c2ecf20Sopenharmony_ci hw->phy.sfp_type = 14868c2ecf20Sopenharmony_ci ixgbe_sfp_type_da_cu_core1; 14878c2ecf20Sopenharmony_ci } else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) { 14888c2ecf20Sopenharmony_ci hw->phy.ops.read_i2c_eeprom( 14898c2ecf20Sopenharmony_ci hw, IXGBE_SFF_CABLE_SPEC_COMP, 14908c2ecf20Sopenharmony_ci &cable_spec); 14918c2ecf20Sopenharmony_ci if (cable_spec & 14928c2ecf20Sopenharmony_ci IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) { 14938c2ecf20Sopenharmony_ci if (hw->bus.lan_id == 0) 14948c2ecf20Sopenharmony_ci hw->phy.sfp_type = 14958c2ecf20Sopenharmony_ci ixgbe_sfp_type_da_act_lmt_core0; 14968c2ecf20Sopenharmony_ci else 14978c2ecf20Sopenharmony_ci hw->phy.sfp_type = 14988c2ecf20Sopenharmony_ci ixgbe_sfp_type_da_act_lmt_core1; 14998c2ecf20Sopenharmony_ci } else { 15008c2ecf20Sopenharmony_ci hw->phy.sfp_type = 15018c2ecf20Sopenharmony_ci ixgbe_sfp_type_unknown; 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci } else if (comp_codes_10g & 15048c2ecf20Sopenharmony_ci (IXGBE_SFF_10GBASESR_CAPABLE | 15058c2ecf20Sopenharmony_ci IXGBE_SFF_10GBASELR_CAPABLE)) { 15068c2ecf20Sopenharmony_ci if (hw->bus.lan_id == 0) 15078c2ecf20Sopenharmony_ci hw->phy.sfp_type = 15088c2ecf20Sopenharmony_ci ixgbe_sfp_type_srlr_core0; 15098c2ecf20Sopenharmony_ci else 15108c2ecf20Sopenharmony_ci hw->phy.sfp_type = 15118c2ecf20Sopenharmony_ci ixgbe_sfp_type_srlr_core1; 15128c2ecf20Sopenharmony_ci } else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) { 15138c2ecf20Sopenharmony_ci if (hw->bus.lan_id == 0) 15148c2ecf20Sopenharmony_ci hw->phy.sfp_type = 15158c2ecf20Sopenharmony_ci ixgbe_sfp_type_1g_cu_core0; 15168c2ecf20Sopenharmony_ci else 15178c2ecf20Sopenharmony_ci hw->phy.sfp_type = 15188c2ecf20Sopenharmony_ci ixgbe_sfp_type_1g_cu_core1; 15198c2ecf20Sopenharmony_ci } else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) { 15208c2ecf20Sopenharmony_ci if (hw->bus.lan_id == 0) 15218c2ecf20Sopenharmony_ci hw->phy.sfp_type = 15228c2ecf20Sopenharmony_ci ixgbe_sfp_type_1g_sx_core0; 15238c2ecf20Sopenharmony_ci else 15248c2ecf20Sopenharmony_ci hw->phy.sfp_type = 15258c2ecf20Sopenharmony_ci ixgbe_sfp_type_1g_sx_core1; 15268c2ecf20Sopenharmony_ci } else if (comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) { 15278c2ecf20Sopenharmony_ci if (hw->bus.lan_id == 0) 15288c2ecf20Sopenharmony_ci hw->phy.sfp_type = 15298c2ecf20Sopenharmony_ci ixgbe_sfp_type_1g_lx_core0; 15308c2ecf20Sopenharmony_ci else 15318c2ecf20Sopenharmony_ci hw->phy.sfp_type = 15328c2ecf20Sopenharmony_ci ixgbe_sfp_type_1g_lx_core1; 15338c2ecf20Sopenharmony_ci } else { 15348c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_unknown; 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (hw->phy.sfp_type != stored_sfp_type) 15398c2ecf20Sopenharmony_ci hw->phy.sfp_setup_needed = true; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci /* Determine if the SFP+ PHY is dual speed or not. */ 15428c2ecf20Sopenharmony_ci hw->phy.multispeed_fiber = false; 15438c2ecf20Sopenharmony_ci if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && 15448c2ecf20Sopenharmony_ci (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || 15458c2ecf20Sopenharmony_ci ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && 15468c2ecf20Sopenharmony_ci (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) 15478c2ecf20Sopenharmony_ci hw->phy.multispeed_fiber = true; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci /* Determine PHY vendor */ 15508c2ecf20Sopenharmony_ci if (hw->phy.type != ixgbe_phy_nl) { 15518c2ecf20Sopenharmony_ci hw->phy.id = identifier; 15528c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 15538c2ecf20Sopenharmony_ci IXGBE_SFF_VENDOR_OUI_BYTE0, 15548c2ecf20Sopenharmony_ci &oui_bytes[0]); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (status != 0) 15578c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 15608c2ecf20Sopenharmony_ci IXGBE_SFF_VENDOR_OUI_BYTE1, 15618c2ecf20Sopenharmony_ci &oui_bytes[1]); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci if (status != 0) 15648c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 15678c2ecf20Sopenharmony_ci IXGBE_SFF_VENDOR_OUI_BYTE2, 15688c2ecf20Sopenharmony_ci &oui_bytes[2]); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (status != 0) 15718c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci vendor_oui = 15748c2ecf20Sopenharmony_ci ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | 15758c2ecf20Sopenharmony_ci (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | 15768c2ecf20Sopenharmony_ci (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci switch (vendor_oui) { 15798c2ecf20Sopenharmony_ci case IXGBE_SFF_VENDOR_OUI_TYCO: 15808c2ecf20Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) 15818c2ecf20Sopenharmony_ci hw->phy.type = 15828c2ecf20Sopenharmony_ci ixgbe_phy_sfp_passive_tyco; 15838c2ecf20Sopenharmony_ci break; 15848c2ecf20Sopenharmony_ci case IXGBE_SFF_VENDOR_OUI_FTL: 15858c2ecf20Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) 15868c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_ftl_active; 15878c2ecf20Sopenharmony_ci else 15888c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_ftl; 15898c2ecf20Sopenharmony_ci break; 15908c2ecf20Sopenharmony_ci case IXGBE_SFF_VENDOR_OUI_AVAGO: 15918c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_avago; 15928c2ecf20Sopenharmony_ci break; 15938c2ecf20Sopenharmony_ci case IXGBE_SFF_VENDOR_OUI_INTEL: 15948c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_intel; 15958c2ecf20Sopenharmony_ci break; 15968c2ecf20Sopenharmony_ci default: 15978c2ecf20Sopenharmony_ci if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) 15988c2ecf20Sopenharmony_ci hw->phy.type = 15998c2ecf20Sopenharmony_ci ixgbe_phy_sfp_passive_unknown; 16008c2ecf20Sopenharmony_ci else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) 16018c2ecf20Sopenharmony_ci hw->phy.type = 16028c2ecf20Sopenharmony_ci ixgbe_phy_sfp_active_unknown; 16038c2ecf20Sopenharmony_ci else 16048c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unknown; 16058c2ecf20Sopenharmony_ci break; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci /* Allow any DA cable vendor */ 16108c2ecf20Sopenharmony_ci if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE | 16118c2ecf20Sopenharmony_ci IXGBE_SFF_DA_ACTIVE_CABLE)) 16128c2ecf20Sopenharmony_ci return 0; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* Verify supported 1G SFP modules */ 16158c2ecf20Sopenharmony_ci if (comp_codes_10g == 0 && 16168c2ecf20Sopenharmony_ci !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || 16178c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || 16188c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || 16198c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || 16208c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || 16218c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { 16228c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 16238c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci /* Anything else 82598-based is supported */ 16278c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) 16288c2ecf20Sopenharmony_ci return 0; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci hw->mac.ops.get_device_caps(hw, &enforce_sfp); 16318c2ecf20Sopenharmony_ci if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) && 16328c2ecf20Sopenharmony_ci !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || 16338c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || 16348c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || 16358c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || 16368c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || 16378c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { 16388c2ecf20Sopenharmony_ci /* Make sure we're a supported PHY type */ 16398c2ecf20Sopenharmony_ci if (hw->phy.type == ixgbe_phy_sfp_intel) 16408c2ecf20Sopenharmony_ci return 0; 16418c2ecf20Sopenharmony_ci if (hw->allow_unsupported_sfp) { 16428c2ecf20Sopenharmony_ci e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); 16438c2ecf20Sopenharmony_ci return 0; 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci hw_dbg(hw, "SFP+ module not supported\n"); 16468c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 16478c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci return 0; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_cierr_read_i2c_eeprom: 16528c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 16538c2ecf20Sopenharmony_ci if (hw->phy.type != ixgbe_phy_nl) { 16548c2ecf20Sopenharmony_ci hw->phy.id = 0; 16558c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_unknown; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci return -ENOENT; 16588c2ecf20Sopenharmony_ci} 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci/** 16618c2ecf20Sopenharmony_ci * ixgbe_identify_qsfp_module_generic - Identifies QSFP modules 16628c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 16638c2ecf20Sopenharmony_ci * 16648c2ecf20Sopenharmony_ci * Searches for and identifies the QSFP module and assigns appropriate PHY type 16658c2ecf20Sopenharmony_ci **/ 16668c2ecf20Sopenharmony_cistatic s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = hw->back; 16698c2ecf20Sopenharmony_ci s32 status; 16708c2ecf20Sopenharmony_ci u32 vendor_oui = 0; 16718c2ecf20Sopenharmony_ci enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; 16728c2ecf20Sopenharmony_ci u8 identifier = 0; 16738c2ecf20Sopenharmony_ci u8 comp_codes_1g = 0; 16748c2ecf20Sopenharmony_ci u8 comp_codes_10g = 0; 16758c2ecf20Sopenharmony_ci u8 oui_bytes[3] = {0, 0, 0}; 16768c2ecf20Sopenharmony_ci u16 enforce_sfp = 0; 16778c2ecf20Sopenharmony_ci u8 connector = 0; 16788c2ecf20Sopenharmony_ci u8 cable_length = 0; 16798c2ecf20Sopenharmony_ci u8 device_tech = 0; 16808c2ecf20Sopenharmony_ci bool active_cable = false; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) { 16838c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 16848c2ecf20Sopenharmony_ci return -ENOENT; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci /* LAN ID is needed for sfp_type determination */ 16888c2ecf20Sopenharmony_ci hw->mac.ops.set_lan_id(hw); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, 16918c2ecf20Sopenharmony_ci &identifier); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci if (status != 0) 16948c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) { 16978c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 16988c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci hw->phy.id = identifier; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP, 17048c2ecf20Sopenharmony_ci &comp_codes_10g); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci if (status != 0) 17078c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_1GBE_COMP, 17108c2ecf20Sopenharmony_ci &comp_codes_1g); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (status != 0) 17138c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (comp_codes_10g & IXGBE_SFF_QSFP_DA_PASSIVE_CABLE) { 17168c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_qsfp_passive_unknown; 17178c2ecf20Sopenharmony_ci if (hw->bus.lan_id == 0) 17188c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0; 17198c2ecf20Sopenharmony_ci else 17208c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core1; 17218c2ecf20Sopenharmony_ci } else if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE | 17228c2ecf20Sopenharmony_ci IXGBE_SFF_10GBASELR_CAPABLE)) { 17238c2ecf20Sopenharmony_ci if (hw->bus.lan_id == 0) 17248c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_srlr_core0; 17258c2ecf20Sopenharmony_ci else 17268c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_srlr_core1; 17278c2ecf20Sopenharmony_ci } else { 17288c2ecf20Sopenharmony_ci if (comp_codes_10g & IXGBE_SFF_QSFP_DA_ACTIVE_CABLE) 17298c2ecf20Sopenharmony_ci active_cable = true; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci if (!active_cable) { 17328c2ecf20Sopenharmony_ci /* check for active DA cables that pre-date 17338c2ecf20Sopenharmony_ci * SFF-8436 v3.6 17348c2ecf20Sopenharmony_ci */ 17358c2ecf20Sopenharmony_ci hw->phy.ops.read_i2c_eeprom(hw, 17368c2ecf20Sopenharmony_ci IXGBE_SFF_QSFP_CONNECTOR, 17378c2ecf20Sopenharmony_ci &connector); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci hw->phy.ops.read_i2c_eeprom(hw, 17408c2ecf20Sopenharmony_ci IXGBE_SFF_QSFP_CABLE_LENGTH, 17418c2ecf20Sopenharmony_ci &cable_length); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci hw->phy.ops.read_i2c_eeprom(hw, 17448c2ecf20Sopenharmony_ci IXGBE_SFF_QSFP_DEVICE_TECH, 17458c2ecf20Sopenharmony_ci &device_tech); 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci if ((connector == 17488c2ecf20Sopenharmony_ci IXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE) && 17498c2ecf20Sopenharmony_ci (cable_length > 0) && 17508c2ecf20Sopenharmony_ci ((device_tech >> 4) == 17518c2ecf20Sopenharmony_ci IXGBE_SFF_QSFP_TRANSMITER_850NM_VCSEL)) 17528c2ecf20Sopenharmony_ci active_cable = true; 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci if (active_cable) { 17568c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_qsfp_active_unknown; 17578c2ecf20Sopenharmony_ci if (hw->bus.lan_id == 0) 17588c2ecf20Sopenharmony_ci hw->phy.sfp_type = 17598c2ecf20Sopenharmony_ci ixgbe_sfp_type_da_act_lmt_core0; 17608c2ecf20Sopenharmony_ci else 17618c2ecf20Sopenharmony_ci hw->phy.sfp_type = 17628c2ecf20Sopenharmony_ci ixgbe_sfp_type_da_act_lmt_core1; 17638c2ecf20Sopenharmony_ci } else { 17648c2ecf20Sopenharmony_ci /* unsupported module type */ 17658c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 17668c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci if (hw->phy.sfp_type != stored_sfp_type) 17718c2ecf20Sopenharmony_ci hw->phy.sfp_setup_needed = true; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci /* Determine if the QSFP+ PHY is dual speed or not. */ 17748c2ecf20Sopenharmony_ci hw->phy.multispeed_fiber = false; 17758c2ecf20Sopenharmony_ci if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && 17768c2ecf20Sopenharmony_ci (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || 17778c2ecf20Sopenharmony_ci ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && 17788c2ecf20Sopenharmony_ci (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) 17798c2ecf20Sopenharmony_ci hw->phy.multispeed_fiber = true; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci /* Determine PHY vendor for optical modules */ 17828c2ecf20Sopenharmony_ci if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE | 17838c2ecf20Sopenharmony_ci IXGBE_SFF_10GBASELR_CAPABLE)) { 17848c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 17858c2ecf20Sopenharmony_ci IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0, 17868c2ecf20Sopenharmony_ci &oui_bytes[0]); 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (status != 0) 17898c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 17928c2ecf20Sopenharmony_ci IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1, 17938c2ecf20Sopenharmony_ci &oui_bytes[1]); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci if (status != 0) 17968c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci status = hw->phy.ops.read_i2c_eeprom(hw, 17998c2ecf20Sopenharmony_ci IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2, 18008c2ecf20Sopenharmony_ci &oui_bytes[2]); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci if (status != 0) 18038c2ecf20Sopenharmony_ci goto err_read_i2c_eeprom; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci vendor_oui = 18068c2ecf20Sopenharmony_ci ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | 18078c2ecf20Sopenharmony_ci (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | 18088c2ecf20Sopenharmony_ci (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci if (vendor_oui == IXGBE_SFF_VENDOR_OUI_INTEL) 18118c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_qsfp_intel; 18128c2ecf20Sopenharmony_ci else 18138c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_qsfp_unknown; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci hw->mac.ops.get_device_caps(hw, &enforce_sfp); 18168c2ecf20Sopenharmony_ci if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { 18178c2ecf20Sopenharmony_ci /* Make sure we're a supported PHY type */ 18188c2ecf20Sopenharmony_ci if (hw->phy.type == ixgbe_phy_qsfp_intel) 18198c2ecf20Sopenharmony_ci return 0; 18208c2ecf20Sopenharmony_ci if (hw->allow_unsupported_sfp) { 18218c2ecf20Sopenharmony_ci e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); 18228c2ecf20Sopenharmony_ci return 0; 18238c2ecf20Sopenharmony_ci } 18248c2ecf20Sopenharmony_ci hw_dbg(hw, "QSFP module not supported\n"); 18258c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_sfp_unsupported; 18268c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci return 0; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci return 0; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_cierr_read_i2c_eeprom: 18338c2ecf20Sopenharmony_ci hw->phy.sfp_type = ixgbe_sfp_type_not_present; 18348c2ecf20Sopenharmony_ci hw->phy.id = 0; 18358c2ecf20Sopenharmony_ci hw->phy.type = ixgbe_phy_unknown; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci return -ENOENT; 18388c2ecf20Sopenharmony_ci} 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci/** 18418c2ecf20Sopenharmony_ci * ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence 18428c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 18438c2ecf20Sopenharmony_ci * @list_offset: offset to the SFP ID list 18448c2ecf20Sopenharmony_ci * @data_offset: offset to the SFP data block 18458c2ecf20Sopenharmony_ci * 18468c2ecf20Sopenharmony_ci * Checks the MAC's EEPROM to see if it supports a given SFP+ module type, if 18478c2ecf20Sopenharmony_ci * so it returns the offsets to the phy init sequence block. 18488c2ecf20Sopenharmony_ci **/ 18498c2ecf20Sopenharmony_cis32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, 18508c2ecf20Sopenharmony_ci u16 *list_offset, 18518c2ecf20Sopenharmony_ci u16 *data_offset) 18528c2ecf20Sopenharmony_ci{ 18538c2ecf20Sopenharmony_ci u16 sfp_id; 18548c2ecf20Sopenharmony_ci u16 sfp_type = hw->phy.sfp_type; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) 18578c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) 18608c2ecf20Sopenharmony_ci return -ENOENT; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) && 18638c2ecf20Sopenharmony_ci (hw->phy.sfp_type == ixgbe_sfp_type_da_cu)) 18648c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci /* 18678c2ecf20Sopenharmony_ci * Limiting active cables and 1G Phys must be initialized as 18688c2ecf20Sopenharmony_ci * SR modules 18698c2ecf20Sopenharmony_ci */ 18708c2ecf20Sopenharmony_ci if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 || 18718c2ecf20Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_lx_core0 || 18728c2ecf20Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_cu_core0 || 18738c2ecf20Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_sx_core0) 18748c2ecf20Sopenharmony_ci sfp_type = ixgbe_sfp_type_srlr_core0; 18758c2ecf20Sopenharmony_ci else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 || 18768c2ecf20Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_lx_core1 || 18778c2ecf20Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_cu_core1 || 18788c2ecf20Sopenharmony_ci sfp_type == ixgbe_sfp_type_1g_sx_core1) 18798c2ecf20Sopenharmony_ci sfp_type = ixgbe_sfp_type_srlr_core1; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci /* Read offset to PHY init contents */ 18828c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset)) { 18838c2ecf20Sopenharmony_ci hw_err(hw, "eeprom read at %d failed\n", 18848c2ecf20Sopenharmony_ci IXGBE_PHY_INIT_OFFSET_NL); 18858c2ecf20Sopenharmony_ci return -EIO; 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if ((!*list_offset) || (*list_offset == 0xFFFF)) 18898c2ecf20Sopenharmony_ci return -EIO; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci /* Shift offset to first ID word */ 18928c2ecf20Sopenharmony_ci (*list_offset)++; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci /* 18958c2ecf20Sopenharmony_ci * Find the matching SFP ID in the EEPROM 18968c2ecf20Sopenharmony_ci * and program the init sequence 18978c2ecf20Sopenharmony_ci */ 18988c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) 18998c2ecf20Sopenharmony_ci goto err_phy; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci while (sfp_id != IXGBE_PHY_INIT_END_NL) { 19028c2ecf20Sopenharmony_ci if (sfp_id == sfp_type) { 19038c2ecf20Sopenharmony_ci (*list_offset)++; 19048c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, *list_offset, data_offset)) 19058c2ecf20Sopenharmony_ci goto err_phy; 19068c2ecf20Sopenharmony_ci if ((!*data_offset) || (*data_offset == 0xFFFF)) { 19078c2ecf20Sopenharmony_ci hw_dbg(hw, "SFP+ module not supported\n"); 19088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 19098c2ecf20Sopenharmony_ci } else { 19108c2ecf20Sopenharmony_ci break; 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci } else { 19138c2ecf20Sopenharmony_ci (*list_offset) += 2; 19148c2ecf20Sopenharmony_ci if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) 19158c2ecf20Sopenharmony_ci goto err_phy; 19168c2ecf20Sopenharmony_ci } 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci if (sfp_id == IXGBE_PHY_INIT_END_NL) { 19208c2ecf20Sopenharmony_ci hw_dbg(hw, "No matching SFP+ module found\n"); 19218c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci return 0; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_cierr_phy: 19278c2ecf20Sopenharmony_ci hw_err(hw, "eeprom read at offset %d failed\n", *list_offset); 19288c2ecf20Sopenharmony_ci return -EIO; 19298c2ecf20Sopenharmony_ci} 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci/** 19328c2ecf20Sopenharmony_ci * ixgbe_read_i2c_eeprom_generic - Reads 8 bit EEPROM word over I2C interface 19338c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 19348c2ecf20Sopenharmony_ci * @byte_offset: EEPROM byte offset to read 19358c2ecf20Sopenharmony_ci * @eeprom_data: value read 19368c2ecf20Sopenharmony_ci * 19378c2ecf20Sopenharmony_ci * Performs byte read operation to SFP module's EEPROM over I2C interface. 19388c2ecf20Sopenharmony_ci **/ 19398c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, 19408c2ecf20Sopenharmony_ci u8 *eeprom_data) 19418c2ecf20Sopenharmony_ci{ 19428c2ecf20Sopenharmony_ci return hw->phy.ops.read_i2c_byte(hw, byte_offset, 19438c2ecf20Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR, 19448c2ecf20Sopenharmony_ci eeprom_data); 19458c2ecf20Sopenharmony_ci} 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci/** 19488c2ecf20Sopenharmony_ci * ixgbe_read_i2c_sff8472_generic - Reads 8 bit word over I2C interface 19498c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 19508c2ecf20Sopenharmony_ci * @byte_offset: byte offset at address 0xA2 19518c2ecf20Sopenharmony_ci * @sff8472_data: value read 19528c2ecf20Sopenharmony_ci * 19538c2ecf20Sopenharmony_ci * Performs byte read operation to SFP module's SFF-8472 data over I2C 19548c2ecf20Sopenharmony_ci **/ 19558c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, 19568c2ecf20Sopenharmony_ci u8 *sff8472_data) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci return hw->phy.ops.read_i2c_byte(hw, byte_offset, 19598c2ecf20Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR2, 19608c2ecf20Sopenharmony_ci sff8472_data); 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci/** 19648c2ecf20Sopenharmony_ci * ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface 19658c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 19668c2ecf20Sopenharmony_ci * @byte_offset: EEPROM byte offset to write 19678c2ecf20Sopenharmony_ci * @eeprom_data: value to write 19688c2ecf20Sopenharmony_ci * 19698c2ecf20Sopenharmony_ci * Performs byte write operation to SFP module's EEPROM over I2C interface. 19708c2ecf20Sopenharmony_ci **/ 19718c2ecf20Sopenharmony_cis32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, 19728c2ecf20Sopenharmony_ci u8 eeprom_data) 19738c2ecf20Sopenharmony_ci{ 19748c2ecf20Sopenharmony_ci return hw->phy.ops.write_i2c_byte(hw, byte_offset, 19758c2ecf20Sopenharmony_ci IXGBE_I2C_EEPROM_DEV_ADDR, 19768c2ecf20Sopenharmony_ci eeprom_data); 19778c2ecf20Sopenharmony_ci} 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci/** 19808c2ecf20Sopenharmony_ci * ixgbe_is_sfp_probe - Returns true if SFP is being detected 19818c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 19828c2ecf20Sopenharmony_ci * @offset: eeprom offset to be read 19838c2ecf20Sopenharmony_ci * @addr: I2C address to be read 19848c2ecf20Sopenharmony_ci */ 19858c2ecf20Sopenharmony_cistatic bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr) 19868c2ecf20Sopenharmony_ci{ 19878c2ecf20Sopenharmony_ci if (addr == IXGBE_I2C_EEPROM_DEV_ADDR && 19888c2ecf20Sopenharmony_ci offset == IXGBE_SFF_IDENTIFIER && 19898c2ecf20Sopenharmony_ci hw->phy.sfp_type == ixgbe_sfp_type_not_present) 19908c2ecf20Sopenharmony_ci return true; 19918c2ecf20Sopenharmony_ci return false; 19928c2ecf20Sopenharmony_ci} 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci/** 19958c2ecf20Sopenharmony_ci * ixgbe_read_i2c_byte_generic_int - Reads 8 bit word over I2C 19968c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 19978c2ecf20Sopenharmony_ci * @byte_offset: byte offset to read 19988c2ecf20Sopenharmony_ci * @dev_addr: device address 19998c2ecf20Sopenharmony_ci * @data: value read 20008c2ecf20Sopenharmony_ci * @lock: true if to take and release semaphore 20018c2ecf20Sopenharmony_ci * 20028c2ecf20Sopenharmony_ci * Performs byte read operation to SFP module's EEPROM over I2C interface at 20038c2ecf20Sopenharmony_ci * a specified device address. 20048c2ecf20Sopenharmony_ci */ 20058c2ecf20Sopenharmony_cistatic s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, 20068c2ecf20Sopenharmony_ci u8 dev_addr, u8 *data, bool lock) 20078c2ecf20Sopenharmony_ci{ 20088c2ecf20Sopenharmony_ci s32 status; 20098c2ecf20Sopenharmony_ci u32 max_retry = 10; 20108c2ecf20Sopenharmony_ci u32 retry = 0; 20118c2ecf20Sopenharmony_ci u32 swfw_mask = hw->phy.phy_semaphore_mask; 20128c2ecf20Sopenharmony_ci bool nack = true; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci if (hw->mac.type >= ixgbe_mac_X550) 20158c2ecf20Sopenharmony_ci max_retry = 3; 20168c2ecf20Sopenharmony_ci if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr)) 20178c2ecf20Sopenharmony_ci max_retry = IXGBE_SFP_DETECT_RETRIES; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci *data = 0; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci do { 20228c2ecf20Sopenharmony_ci if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 20238c2ecf20Sopenharmony_ci return -EBUSY; 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci ixgbe_i2c_start(hw); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci /* Device Address and write indication */ 20288c2ecf20Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, dev_addr); 20298c2ecf20Sopenharmony_ci if (status != 0) 20308c2ecf20Sopenharmony_ci goto fail; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 20338c2ecf20Sopenharmony_ci if (status != 0) 20348c2ecf20Sopenharmony_ci goto fail; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, byte_offset); 20378c2ecf20Sopenharmony_ci if (status != 0) 20388c2ecf20Sopenharmony_ci goto fail; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 20418c2ecf20Sopenharmony_ci if (status != 0) 20428c2ecf20Sopenharmony_ci goto fail; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci ixgbe_i2c_start(hw); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci /* Device Address and read indication */ 20478c2ecf20Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, (dev_addr | 0x1)); 20488c2ecf20Sopenharmony_ci if (status != 0) 20498c2ecf20Sopenharmony_ci goto fail; 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 20528c2ecf20Sopenharmony_ci if (status != 0) 20538c2ecf20Sopenharmony_ci goto fail; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci status = ixgbe_clock_in_i2c_byte(hw, data); 20568c2ecf20Sopenharmony_ci if (status != 0) 20578c2ecf20Sopenharmony_ci goto fail; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci status = ixgbe_clock_out_i2c_bit(hw, nack); 20608c2ecf20Sopenharmony_ci if (status != 0) 20618c2ecf20Sopenharmony_ci goto fail; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci ixgbe_i2c_stop(hw); 20648c2ecf20Sopenharmony_ci if (lock) 20658c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 20668c2ecf20Sopenharmony_ci return 0; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_cifail: 20698c2ecf20Sopenharmony_ci ixgbe_i2c_bus_clear(hw); 20708c2ecf20Sopenharmony_ci if (lock) { 20718c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 20728c2ecf20Sopenharmony_ci msleep(100); 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci retry++; 20758c2ecf20Sopenharmony_ci if (retry < max_retry) 20768c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C byte read error - Retrying.\n"); 20778c2ecf20Sopenharmony_ci else 20788c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C byte read error.\n"); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci } while (retry < max_retry); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci return status; 20838c2ecf20Sopenharmony_ci} 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci/** 20868c2ecf20Sopenharmony_ci * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C 20878c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 20888c2ecf20Sopenharmony_ci * @byte_offset: byte offset to read 20898c2ecf20Sopenharmony_ci * @dev_addr: device address 20908c2ecf20Sopenharmony_ci * @data: value read 20918c2ecf20Sopenharmony_ci * 20928c2ecf20Sopenharmony_ci * Performs byte read operation to SFP module's EEPROM over I2C interface at 20938c2ecf20Sopenharmony_ci * a specified device address. 20948c2ecf20Sopenharmony_ci */ 20958c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, 20968c2ecf20Sopenharmony_ci u8 dev_addr, u8 *data) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr, 20998c2ecf20Sopenharmony_ci data, true); 21008c2ecf20Sopenharmony_ci} 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci/** 21038c2ecf20Sopenharmony_ci * ixgbe_read_i2c_byte_generic_unlocked - Reads 8 bit word over I2C 21048c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 21058c2ecf20Sopenharmony_ci * @byte_offset: byte offset to read 21068c2ecf20Sopenharmony_ci * @dev_addr: device address 21078c2ecf20Sopenharmony_ci * @data: value read 21088c2ecf20Sopenharmony_ci * 21098c2ecf20Sopenharmony_ci * Performs byte read operation to SFP module's EEPROM over I2C interface at 21108c2ecf20Sopenharmony_ci * a specified device address. 21118c2ecf20Sopenharmony_ci */ 21128c2ecf20Sopenharmony_cis32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, 21138c2ecf20Sopenharmony_ci u8 dev_addr, u8 *data) 21148c2ecf20Sopenharmony_ci{ 21158c2ecf20Sopenharmony_ci return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr, 21168c2ecf20Sopenharmony_ci data, false); 21178c2ecf20Sopenharmony_ci} 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci/** 21208c2ecf20Sopenharmony_ci * ixgbe_write_i2c_byte_generic_int - Writes 8 bit word over I2C 21218c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 21228c2ecf20Sopenharmony_ci * @byte_offset: byte offset to write 21238c2ecf20Sopenharmony_ci * @dev_addr: device address 21248c2ecf20Sopenharmony_ci * @data: value to write 21258c2ecf20Sopenharmony_ci * @lock: true if to take and release semaphore 21268c2ecf20Sopenharmony_ci * 21278c2ecf20Sopenharmony_ci * Performs byte write operation to SFP module's EEPROM over I2C interface at 21288c2ecf20Sopenharmony_ci * a specified device address. 21298c2ecf20Sopenharmony_ci */ 21308c2ecf20Sopenharmony_cistatic s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, 21318c2ecf20Sopenharmony_ci u8 dev_addr, u8 data, bool lock) 21328c2ecf20Sopenharmony_ci{ 21338c2ecf20Sopenharmony_ci s32 status; 21348c2ecf20Sopenharmony_ci u32 max_retry = 1; 21358c2ecf20Sopenharmony_ci u32 retry = 0; 21368c2ecf20Sopenharmony_ci u32 swfw_mask = hw->phy.phy_semaphore_mask; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 21398c2ecf20Sopenharmony_ci return -EBUSY; 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci do { 21428c2ecf20Sopenharmony_ci ixgbe_i2c_start(hw); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, dev_addr); 21458c2ecf20Sopenharmony_ci if (status != 0) 21468c2ecf20Sopenharmony_ci goto fail; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 21498c2ecf20Sopenharmony_ci if (status != 0) 21508c2ecf20Sopenharmony_ci goto fail; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, byte_offset); 21538c2ecf20Sopenharmony_ci if (status != 0) 21548c2ecf20Sopenharmony_ci goto fail; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 21578c2ecf20Sopenharmony_ci if (status != 0) 21588c2ecf20Sopenharmony_ci goto fail; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci status = ixgbe_clock_out_i2c_byte(hw, data); 21618c2ecf20Sopenharmony_ci if (status != 0) 21628c2ecf20Sopenharmony_ci goto fail; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci status = ixgbe_get_i2c_ack(hw); 21658c2ecf20Sopenharmony_ci if (status != 0) 21668c2ecf20Sopenharmony_ci goto fail; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci ixgbe_i2c_stop(hw); 21698c2ecf20Sopenharmony_ci if (lock) 21708c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 21718c2ecf20Sopenharmony_ci return 0; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_cifail: 21748c2ecf20Sopenharmony_ci ixgbe_i2c_bus_clear(hw); 21758c2ecf20Sopenharmony_ci retry++; 21768c2ecf20Sopenharmony_ci if (retry < max_retry) 21778c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C byte write error - Retrying.\n"); 21788c2ecf20Sopenharmony_ci else 21798c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C byte write error.\n"); 21808c2ecf20Sopenharmony_ci } while (retry < max_retry); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci if (lock) 21838c2ecf20Sopenharmony_ci hw->mac.ops.release_swfw_sync(hw, swfw_mask); 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci return status; 21868c2ecf20Sopenharmony_ci} 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci/** 21898c2ecf20Sopenharmony_ci * ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C 21908c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 21918c2ecf20Sopenharmony_ci * @byte_offset: byte offset to write 21928c2ecf20Sopenharmony_ci * @dev_addr: device address 21938c2ecf20Sopenharmony_ci * @data: value to write 21948c2ecf20Sopenharmony_ci * 21958c2ecf20Sopenharmony_ci * Performs byte write operation to SFP module's EEPROM over I2C interface at 21968c2ecf20Sopenharmony_ci * a specified device address. 21978c2ecf20Sopenharmony_ci */ 21988c2ecf20Sopenharmony_cis32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, 21998c2ecf20Sopenharmony_ci u8 dev_addr, u8 data) 22008c2ecf20Sopenharmony_ci{ 22018c2ecf20Sopenharmony_ci return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr, 22028c2ecf20Sopenharmony_ci data, true); 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci/** 22068c2ecf20Sopenharmony_ci * ixgbe_write_i2c_byte_generic_unlocked - Writes 8 bit word over I2C 22078c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 22088c2ecf20Sopenharmony_ci * @byte_offset: byte offset to write 22098c2ecf20Sopenharmony_ci * @dev_addr: device address 22108c2ecf20Sopenharmony_ci * @data: value to write 22118c2ecf20Sopenharmony_ci * 22128c2ecf20Sopenharmony_ci * Performs byte write operation to SFP module's EEPROM over I2C interface at 22138c2ecf20Sopenharmony_ci * a specified device address. 22148c2ecf20Sopenharmony_ci */ 22158c2ecf20Sopenharmony_cis32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, 22168c2ecf20Sopenharmony_ci u8 dev_addr, u8 data) 22178c2ecf20Sopenharmony_ci{ 22188c2ecf20Sopenharmony_ci return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr, 22198c2ecf20Sopenharmony_ci data, false); 22208c2ecf20Sopenharmony_ci} 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci/** 22238c2ecf20Sopenharmony_ci * ixgbe_i2c_start - Sets I2C start condition 22248c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 22258c2ecf20Sopenharmony_ci * 22268c2ecf20Sopenharmony_ci * Sets I2C start condition (High -> Low on SDA while SCL is High) 22278c2ecf20Sopenharmony_ci * Set bit-bang mode on X550 hardware. 22288c2ecf20Sopenharmony_ci **/ 22298c2ecf20Sopenharmony_cistatic void ixgbe_i2c_start(struct ixgbe_hw *hw) 22308c2ecf20Sopenharmony_ci{ 22318c2ecf20Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci i2cctl |= IXGBE_I2C_BB_EN(hw); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci /* Start condition must begin with data and clock high */ 22368c2ecf20Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 1); 22378c2ecf20Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci /* Setup time for start condition (4.7us) */ 22408c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_SU_STA); 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 0); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci /* Hold time for start condition (4us) */ 22458c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_HD_STA); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci /* Minimum low period of clock is 4.7 us */ 22508c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci} 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci/** 22558c2ecf20Sopenharmony_ci * ixgbe_i2c_stop - Sets I2C stop condition 22568c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 22578c2ecf20Sopenharmony_ci * 22588c2ecf20Sopenharmony_ci * Sets I2C stop condition (Low -> High on SDA while SCL is High) 22598c2ecf20Sopenharmony_ci * Disables bit-bang mode and negates data output enable on X550 22608c2ecf20Sopenharmony_ci * hardware. 22618c2ecf20Sopenharmony_ci **/ 22628c2ecf20Sopenharmony_cistatic void ixgbe_i2c_stop(struct ixgbe_hw *hw) 22638c2ecf20Sopenharmony_ci{ 22648c2ecf20Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 22658c2ecf20Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 22668c2ecf20Sopenharmony_ci u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN(hw); 22678c2ecf20Sopenharmony_ci u32 bb_en_bit = IXGBE_I2C_BB_EN(hw); 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci /* Stop condition must begin with data low and clock high */ 22708c2ecf20Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 0); 22718c2ecf20Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci /* Setup time for stop condition (4us) */ 22748c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_SU_STO); 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 1); 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci /* bus free time between stop and start (4.7us)*/ 22798c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_BUF); 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci if (bb_en_bit || data_oe_bit || clk_oe_bit) { 22828c2ecf20Sopenharmony_ci i2cctl &= ~bb_en_bit; 22838c2ecf20Sopenharmony_ci i2cctl |= data_oe_bit | clk_oe_bit; 22848c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl); 22858c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci} 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci/** 22908c2ecf20Sopenharmony_ci * ixgbe_clock_in_i2c_byte - Clocks in one byte via I2C 22918c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 22928c2ecf20Sopenharmony_ci * @data: data byte to clock in 22938c2ecf20Sopenharmony_ci * 22948c2ecf20Sopenharmony_ci * Clocks in one byte data via I2C data/clock 22958c2ecf20Sopenharmony_ci **/ 22968c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data) 22978c2ecf20Sopenharmony_ci{ 22988c2ecf20Sopenharmony_ci s32 i; 22998c2ecf20Sopenharmony_ci bool bit = false; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci *data = 0; 23028c2ecf20Sopenharmony_ci for (i = 7; i >= 0; i--) { 23038c2ecf20Sopenharmony_ci ixgbe_clock_in_i2c_bit(hw, &bit); 23048c2ecf20Sopenharmony_ci *data |= bit << i; 23058c2ecf20Sopenharmony_ci } 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci return 0; 23088c2ecf20Sopenharmony_ci} 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci/** 23118c2ecf20Sopenharmony_ci * ixgbe_clock_out_i2c_byte - Clocks out one byte via I2C 23128c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 23138c2ecf20Sopenharmony_ci * @data: data byte clocked out 23148c2ecf20Sopenharmony_ci * 23158c2ecf20Sopenharmony_ci * Clocks out one byte data via I2C data/clock 23168c2ecf20Sopenharmony_ci **/ 23178c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) 23188c2ecf20Sopenharmony_ci{ 23198c2ecf20Sopenharmony_ci s32 status; 23208c2ecf20Sopenharmony_ci s32 i; 23218c2ecf20Sopenharmony_ci u32 i2cctl; 23228c2ecf20Sopenharmony_ci bool bit = false; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci for (i = 7; i >= 0; i--) { 23258c2ecf20Sopenharmony_ci bit = (data >> i) & 0x1; 23268c2ecf20Sopenharmony_ci status = ixgbe_clock_out_i2c_bit(hw, bit); 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci if (status != 0) 23298c2ecf20Sopenharmony_ci break; 23308c2ecf20Sopenharmony_ci } 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci /* Release SDA line (set high) */ 23338c2ecf20Sopenharmony_ci i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 23348c2ecf20Sopenharmony_ci i2cctl |= IXGBE_I2C_DATA_OUT(hw); 23358c2ecf20Sopenharmony_ci i2cctl |= IXGBE_I2C_DATA_OE_N_EN(hw); 23368c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl); 23378c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci return status; 23408c2ecf20Sopenharmony_ci} 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci/** 23438c2ecf20Sopenharmony_ci * ixgbe_get_i2c_ack - Polls for I2C ACK 23448c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 23458c2ecf20Sopenharmony_ci * 23468c2ecf20Sopenharmony_ci * Clocks in/out one bit via I2C data/clock 23478c2ecf20Sopenharmony_ci **/ 23488c2ecf20Sopenharmony_cistatic s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) 23498c2ecf20Sopenharmony_ci{ 23508c2ecf20Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 23518c2ecf20Sopenharmony_ci s32 status = 0; 23528c2ecf20Sopenharmony_ci u32 i = 0; 23538c2ecf20Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 23548c2ecf20Sopenharmony_ci u32 timeout = 10; 23558c2ecf20Sopenharmony_ci bool ack = true; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci if (data_oe_bit) { 23588c2ecf20Sopenharmony_ci i2cctl |= IXGBE_I2C_DATA_OUT(hw); 23598c2ecf20Sopenharmony_ci i2cctl |= data_oe_bit; 23608c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl); 23618c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 23628c2ecf20Sopenharmony_ci } 23638c2ecf20Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci /* Minimum high period of clock is 4us */ 23668c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_HIGH); 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci /* Poll for ACK. Note that ACK in I2C spec is 23698c2ecf20Sopenharmony_ci * transition from 1 to 0 */ 23708c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 23718c2ecf20Sopenharmony_ci i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 23728c2ecf20Sopenharmony_ci ack = ixgbe_get_i2c_data(hw, &i2cctl); 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci udelay(1); 23758c2ecf20Sopenharmony_ci if (ack == 0) 23768c2ecf20Sopenharmony_ci break; 23778c2ecf20Sopenharmony_ci } 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci if (ack == 1) { 23808c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C ack was not received.\n"); 23818c2ecf20Sopenharmony_ci status = -EIO; 23828c2ecf20Sopenharmony_ci } 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci /* Minimum low period of clock is 4.7 us */ 23878c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci return status; 23908c2ecf20Sopenharmony_ci} 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci/** 23938c2ecf20Sopenharmony_ci * ixgbe_clock_in_i2c_bit - Clocks in one bit via I2C data/clock 23948c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 23958c2ecf20Sopenharmony_ci * @data: read data value 23968c2ecf20Sopenharmony_ci * 23978c2ecf20Sopenharmony_ci * Clocks in one bit via I2C data/clock 23988c2ecf20Sopenharmony_ci **/ 23998c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) 24008c2ecf20Sopenharmony_ci{ 24018c2ecf20Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 24028c2ecf20Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci if (data_oe_bit) { 24058c2ecf20Sopenharmony_ci i2cctl |= IXGBE_I2C_DATA_OUT(hw); 24068c2ecf20Sopenharmony_ci i2cctl |= data_oe_bit; 24078c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl); 24088c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci /* Minimum high period of clock is 4us */ 24138c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_HIGH); 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 24168c2ecf20Sopenharmony_ci *data = ixgbe_get_i2c_data(hw, &i2cctl); 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci /* Minimum low period of clock is 4.7 us */ 24218c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci return 0; 24248c2ecf20Sopenharmony_ci} 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci/** 24278c2ecf20Sopenharmony_ci * ixgbe_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock 24288c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 24298c2ecf20Sopenharmony_ci * @data: data value to write 24308c2ecf20Sopenharmony_ci * 24318c2ecf20Sopenharmony_ci * Clocks out one bit via I2C data/clock 24328c2ecf20Sopenharmony_ci **/ 24338c2ecf20Sopenharmony_cistatic s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) 24348c2ecf20Sopenharmony_ci{ 24358c2ecf20Sopenharmony_ci s32 status; 24368c2ecf20Sopenharmony_ci u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci status = ixgbe_set_i2c_data(hw, &i2cctl, data); 24398c2ecf20Sopenharmony_ci if (status == 0) { 24408c2ecf20Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci /* Minimum high period of clock is 4us */ 24438c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_HIGH); 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci /* Minimum low period of clock is 4.7 us. 24488c2ecf20Sopenharmony_ci * This also takes care of the data hold time. 24498c2ecf20Sopenharmony_ci */ 24508c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 24518c2ecf20Sopenharmony_ci } else { 24528c2ecf20Sopenharmony_ci hw_dbg(hw, "I2C data was not set to %X\n", data); 24538c2ecf20Sopenharmony_ci return -EIO; 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci return 0; 24578c2ecf20Sopenharmony_ci} 24588c2ecf20Sopenharmony_ci/** 24598c2ecf20Sopenharmony_ci * ixgbe_raise_i2c_clk - Raises the I2C SCL clock 24608c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 24618c2ecf20Sopenharmony_ci * @i2cctl: Current value of I2CCTL register 24628c2ecf20Sopenharmony_ci * 24638c2ecf20Sopenharmony_ci * Raises the I2C clock line '0'->'1' 24648c2ecf20Sopenharmony_ci * Negates the I2C clock output enable on X550 hardware. 24658c2ecf20Sopenharmony_ci **/ 24668c2ecf20Sopenharmony_cistatic void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) 24678c2ecf20Sopenharmony_ci{ 24688c2ecf20Sopenharmony_ci u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN(hw); 24698c2ecf20Sopenharmony_ci u32 i = 0; 24708c2ecf20Sopenharmony_ci u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT; 24718c2ecf20Sopenharmony_ci u32 i2cctl_r = 0; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci if (clk_oe_bit) { 24748c2ecf20Sopenharmony_ci *i2cctl |= clk_oe_bit; 24758c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 24768c2ecf20Sopenharmony_ci } 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 24798c2ecf20Sopenharmony_ci *i2cctl |= IXGBE_I2C_CLK_OUT(hw); 24808c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 24818c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 24828c2ecf20Sopenharmony_ci /* SCL rise time (1000ns) */ 24838c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_RISE); 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 24868c2ecf20Sopenharmony_ci if (i2cctl_r & IXGBE_I2C_CLK_IN(hw)) 24878c2ecf20Sopenharmony_ci break; 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci} 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci/** 24928c2ecf20Sopenharmony_ci * ixgbe_lower_i2c_clk - Lowers the I2C SCL clock 24938c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 24948c2ecf20Sopenharmony_ci * @i2cctl: Current value of I2CCTL register 24958c2ecf20Sopenharmony_ci * 24968c2ecf20Sopenharmony_ci * Lowers the I2C clock line '1'->'0' 24978c2ecf20Sopenharmony_ci * Asserts the I2C clock output enable on X550 hardware. 24988c2ecf20Sopenharmony_ci **/ 24998c2ecf20Sopenharmony_cistatic void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) 25008c2ecf20Sopenharmony_ci{ 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci *i2cctl &= ~IXGBE_I2C_CLK_OUT(hw); 25038c2ecf20Sopenharmony_ci *i2cctl &= ~IXGBE_I2C_CLK_OE_N_EN(hw); 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 25068c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci /* SCL fall time (300ns) */ 25098c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_FALL); 25108c2ecf20Sopenharmony_ci} 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci/** 25138c2ecf20Sopenharmony_ci * ixgbe_set_i2c_data - Sets the I2C data bit 25148c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 25158c2ecf20Sopenharmony_ci * @i2cctl: Current value of I2CCTL register 25168c2ecf20Sopenharmony_ci * @data: I2C data value (0 or 1) to set 25178c2ecf20Sopenharmony_ci * 25188c2ecf20Sopenharmony_ci * Sets the I2C data bit 25198c2ecf20Sopenharmony_ci * Asserts the I2C data output enable on X550 hardware. 25208c2ecf20Sopenharmony_ci **/ 25218c2ecf20Sopenharmony_cistatic s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) 25228c2ecf20Sopenharmony_ci{ 25238c2ecf20Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci if (data) 25268c2ecf20Sopenharmony_ci *i2cctl |= IXGBE_I2C_DATA_OUT(hw); 25278c2ecf20Sopenharmony_ci else 25288c2ecf20Sopenharmony_ci *i2cctl &= ~IXGBE_I2C_DATA_OUT(hw); 25298c2ecf20Sopenharmony_ci *i2cctl &= ~data_oe_bit; 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 25328c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */ 25358c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA); 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci if (!data) /* Can't verify data in this case */ 25388c2ecf20Sopenharmony_ci return 0; 25398c2ecf20Sopenharmony_ci if (data_oe_bit) { 25408c2ecf20Sopenharmony_ci *i2cctl |= data_oe_bit; 25418c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 25428c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 25438c2ecf20Sopenharmony_ci } 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci /* Verify data was set correctly */ 25468c2ecf20Sopenharmony_ci *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 25478c2ecf20Sopenharmony_ci if (data != ixgbe_get_i2c_data(hw, i2cctl)) { 25488c2ecf20Sopenharmony_ci hw_dbg(hw, "Error - I2C data was not set to %X.\n", data); 25498c2ecf20Sopenharmony_ci return -EIO; 25508c2ecf20Sopenharmony_ci } 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci return 0; 25538c2ecf20Sopenharmony_ci} 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci/** 25568c2ecf20Sopenharmony_ci * ixgbe_get_i2c_data - Reads the I2C SDA data bit 25578c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 25588c2ecf20Sopenharmony_ci * @i2cctl: Current value of I2CCTL register 25598c2ecf20Sopenharmony_ci * 25608c2ecf20Sopenharmony_ci * Returns the I2C data bit value 25618c2ecf20Sopenharmony_ci * Negates the I2C data output enable on X550 hardware. 25628c2ecf20Sopenharmony_ci **/ 25638c2ecf20Sopenharmony_cistatic bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl) 25648c2ecf20Sopenharmony_ci{ 25658c2ecf20Sopenharmony_ci u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci if (data_oe_bit) { 25688c2ecf20Sopenharmony_ci *i2cctl |= data_oe_bit; 25698c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); 25708c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 25718c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_FALL); 25728c2ecf20Sopenharmony_ci } 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci if (*i2cctl & IXGBE_I2C_DATA_IN(hw)) 25758c2ecf20Sopenharmony_ci return true; 25768c2ecf20Sopenharmony_ci return false; 25778c2ecf20Sopenharmony_ci} 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci/** 25808c2ecf20Sopenharmony_ci * ixgbe_i2c_bus_clear - Clears the I2C bus 25818c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 25828c2ecf20Sopenharmony_ci * 25838c2ecf20Sopenharmony_ci * Clears the I2C bus by sending nine clock pulses. 25848c2ecf20Sopenharmony_ci * Used when data line is stuck low. 25858c2ecf20Sopenharmony_ci **/ 25868c2ecf20Sopenharmony_cistatic void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw) 25878c2ecf20Sopenharmony_ci{ 25888c2ecf20Sopenharmony_ci u32 i2cctl; 25898c2ecf20Sopenharmony_ci u32 i; 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci ixgbe_i2c_start(hw); 25928c2ecf20Sopenharmony_ci i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci ixgbe_set_i2c_data(hw, &i2cctl, 1); 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci for (i = 0; i < 9; i++) { 25978c2ecf20Sopenharmony_ci ixgbe_raise_i2c_clk(hw, &i2cctl); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci /* Min high period of clock is 4us */ 26008c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_HIGH); 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci ixgbe_lower_i2c_clk(hw, &i2cctl); 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci /* Min low period of clock is 4.7us*/ 26058c2ecf20Sopenharmony_ci udelay(IXGBE_I2C_T_LOW); 26068c2ecf20Sopenharmony_ci } 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci ixgbe_i2c_start(hw); 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci /* Put the i2c bus back to default state */ 26118c2ecf20Sopenharmony_ci ixgbe_i2c_stop(hw); 26128c2ecf20Sopenharmony_ci} 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci/** 26158c2ecf20Sopenharmony_ci * ixgbe_tn_check_overtemp - Checks if an overtemp occurred. 26168c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 26178c2ecf20Sopenharmony_ci * 26188c2ecf20Sopenharmony_ci * Checks if the LASI temp alarm status was triggered due to overtemp 26198c2ecf20Sopenharmony_ci * 26208c2ecf20Sopenharmony_ci * Return true when an overtemp event detected, otherwise false. 26218c2ecf20Sopenharmony_ci **/ 26228c2ecf20Sopenharmony_cibool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw) 26238c2ecf20Sopenharmony_ci{ 26248c2ecf20Sopenharmony_ci u16 phy_data = 0; 26258c2ecf20Sopenharmony_ci u32 status; 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM) 26288c2ecf20Sopenharmony_ci return false; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci /* Check that the LASI temp alarm status was triggered */ 26318c2ecf20Sopenharmony_ci status = hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG, 26328c2ecf20Sopenharmony_ci MDIO_MMD_PMAPMD, &phy_data); 26338c2ecf20Sopenharmony_ci if (status) 26348c2ecf20Sopenharmony_ci return false; 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci return !!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM); 26378c2ecf20Sopenharmony_ci} 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci/** ixgbe_set_copper_phy_power - Control power for copper phy 26408c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 26418c2ecf20Sopenharmony_ci * @on: true for on, false for off 26428c2ecf20Sopenharmony_ci **/ 26438c2ecf20Sopenharmony_cis32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on) 26448c2ecf20Sopenharmony_ci{ 26458c2ecf20Sopenharmony_ci u32 status; 26468c2ecf20Sopenharmony_ci u16 reg; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci /* Bail if we don't have copper phy */ 26498c2ecf20Sopenharmony_ci if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper) 26508c2ecf20Sopenharmony_ci return 0; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci if (!on && ixgbe_mng_present(hw)) 26538c2ecf20Sopenharmony_ci return 0; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci status = hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_VEND1, ®); 26568c2ecf20Sopenharmony_ci if (status) 26578c2ecf20Sopenharmony_ci return status; 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci if (on) { 26608c2ecf20Sopenharmony_ci reg &= ~IXGBE_MDIO_PHY_SET_LOW_POWER_MODE; 26618c2ecf20Sopenharmony_ci } else { 26628c2ecf20Sopenharmony_ci if (ixgbe_check_reset_blocked(hw)) 26638c2ecf20Sopenharmony_ci return 0; 26648c2ecf20Sopenharmony_ci reg |= IXGBE_MDIO_PHY_SET_LOW_POWER_MODE; 26658c2ecf20Sopenharmony_ci } 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci status = hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_VEND1, reg); 26688c2ecf20Sopenharmony_ci return status; 26698c2ecf20Sopenharmony_ci} 2670