19ca4041bSJack F Vogel /****************************************************************************** 27282444bSPedro F. Giffuni SPDX-License-Identifier: BSD-3-Clause 313705f88SJack F Vogel 48455e365SKevin Bowling Copyright (c) 2001-2020, Intel Corporation 513705f88SJack F Vogel All rights reserved. 613705f88SJack F Vogel 713705f88SJack F Vogel Redistribution and use in source and binary forms, with or without 813705f88SJack F Vogel modification, are permitted provided that the following conditions are met: 913705f88SJack F Vogel 1013705f88SJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 1113705f88SJack F Vogel this list of conditions and the following disclaimer. 1213705f88SJack F Vogel 1313705f88SJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 1413705f88SJack F Vogel notice, this list of conditions and the following disclaimer in the 1513705f88SJack F Vogel documentation and/or other materials provided with the distribution. 1613705f88SJack F Vogel 1713705f88SJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 1813705f88SJack F Vogel contributors may be used to endorse or promote products derived from 1913705f88SJack F Vogel this software without specific prior written permission. 2013705f88SJack F Vogel 2113705f88SJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2213705f88SJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2313705f88SJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2413705f88SJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2513705f88SJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2613705f88SJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2713705f88SJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2813705f88SJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2913705f88SJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3013705f88SJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3113705f88SJack F Vogel POSSIBILITY OF SUCH DAMAGE. 3213705f88SJack F Vogel 339ca4041bSJack F Vogel ******************************************************************************/ 3413705f88SJack F Vogel 3513705f88SJack F Vogel #include "ixgbe_api.h" 3613705f88SJack F Vogel #include "ixgbe_common.h" 3713705f88SJack F Vogel #include "ixgbe_phy.h" 3813705f88SJack F Vogel 390ac6dfecSJack F Vogel static void ixgbe_i2c_start(struct ixgbe_hw *hw); 400ac6dfecSJack F Vogel static void ixgbe_i2c_stop(struct ixgbe_hw *hw); 413a890053SGuinan Sun static void ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data); 420ac6dfecSJack F Vogel static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data); 430ac6dfecSJack F Vogel static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw); 443a890053SGuinan Sun static void ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data); 450ac6dfecSJack F Vogel static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data); 4685d0a26eSJack F Vogel static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); 470ac6dfecSJack F Vogel static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); 480ac6dfecSJack F Vogel static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); 49758cc3dcSJack F Vogel static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl); 500ecc2ff0SJack F Vogel static s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, 510ecc2ff0SJack F Vogel u8 *sff8472_data); 520ac6dfecSJack F Vogel 5313705f88SJack F Vogel /** 54758cc3dcSJack F Vogel * ixgbe_out_i2c_byte_ack - Send I2C byte with ack 55758cc3dcSJack F Vogel * @hw: pointer to the hardware structure 56758cc3dcSJack F Vogel * @byte: byte to send 57758cc3dcSJack F Vogel * 58758cc3dcSJack F Vogel * Returns an error code on error. 59758cc3dcSJack F Vogel */ 60758cc3dcSJack F Vogel static s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte) 61758cc3dcSJack F Vogel { 62758cc3dcSJack F Vogel s32 status; 63758cc3dcSJack F Vogel 64758cc3dcSJack F Vogel status = ixgbe_clock_out_i2c_byte(hw, byte); 65758cc3dcSJack F Vogel if (status) 66758cc3dcSJack F Vogel return status; 67758cc3dcSJack F Vogel return ixgbe_get_i2c_ack(hw); 68758cc3dcSJack F Vogel } 69758cc3dcSJack F Vogel 70758cc3dcSJack F Vogel /** 71758cc3dcSJack F Vogel * ixgbe_in_i2c_byte_ack - Receive an I2C byte and send ack 72758cc3dcSJack F Vogel * @hw: pointer to the hardware structure 73758cc3dcSJack F Vogel * @byte: pointer to a u8 to receive the byte 74758cc3dcSJack F Vogel * 75758cc3dcSJack F Vogel * Returns an error code on error. 76758cc3dcSJack F Vogel */ 77758cc3dcSJack F Vogel static s32 ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte) 78758cc3dcSJack F Vogel { 793a890053SGuinan Sun ixgbe_clock_in_i2c_byte(hw, byte); 80758cc3dcSJack F Vogel /* ACK */ 8179b36ec9SKevin Bowling return ixgbe_clock_out_i2c_bit(hw, false); 82758cc3dcSJack F Vogel } 83758cc3dcSJack F Vogel 84758cc3dcSJack F Vogel /** 85758cc3dcSJack F Vogel * ixgbe_ones_comp_byte_add - Perform one's complement addition 867d48aa4cSEric Joyner * @add1: addend 1 877d48aa4cSEric Joyner * @add2: addend 2 88758cc3dcSJack F Vogel * 89758cc3dcSJack F Vogel * Returns one's complement 8-bit sum. 90758cc3dcSJack F Vogel */ 91758cc3dcSJack F Vogel static u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2) 92758cc3dcSJack F Vogel { 93758cc3dcSJack F Vogel u16 sum = add1 + add2; 94758cc3dcSJack F Vogel 95758cc3dcSJack F Vogel sum = (sum & 0xFF) + (sum >> 8); 96758cc3dcSJack F Vogel return sum & 0xFF; 97758cc3dcSJack F Vogel } 98758cc3dcSJack F Vogel 99758cc3dcSJack F Vogel /** 1006f37f232SEric Joyner * ixgbe_read_i2c_combined_generic_int - Perform I2C read combined operation 101758cc3dcSJack F Vogel * @hw: pointer to the hardware structure 102758cc3dcSJack F Vogel * @addr: I2C bus address to read from 103758cc3dcSJack F Vogel * @reg: I2C device register to read from 104758cc3dcSJack F Vogel * @val: pointer to location to receive read value 10579b36ec9SKevin Bowling * @lock: true if to take and release semaphore 106758cc3dcSJack F Vogel * 107758cc3dcSJack F Vogel * Returns an error code on error. 108758cc3dcSJack F Vogel */ 1098eb6488eSEric Joyner s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg, 1108eb6488eSEric Joyner u16 *val, bool lock) 111758cc3dcSJack F Vogel { 112758cc3dcSJack F Vogel u32 swfw_mask = hw->phy.phy_semaphore_mask; 1138eb6488eSEric Joyner int max_retry = 3; 114758cc3dcSJack F Vogel int retry = 0; 115758cc3dcSJack F Vogel u8 csum_byte; 116758cc3dcSJack F Vogel u8 high_bits; 117758cc3dcSJack F Vogel u8 low_bits; 118758cc3dcSJack F Vogel u8 reg_high; 119758cc3dcSJack F Vogel u8 csum; 120758cc3dcSJack F Vogel 121758cc3dcSJack F Vogel reg_high = ((reg >> 7) & 0xFE) | 1; /* Indicate read combined */ 122758cc3dcSJack F Vogel csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); 123758cc3dcSJack F Vogel csum = ~csum; 124758cc3dcSJack F Vogel do { 1256f37f232SEric Joyner if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 126758cc3dcSJack F Vogel return IXGBE_ERR_SWFW_SYNC; 127758cc3dcSJack F Vogel ixgbe_i2c_start(hw); 128758cc3dcSJack F Vogel /* Device Address and write indication */ 129758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, addr)) 130758cc3dcSJack F Vogel goto fail; 131758cc3dcSJack F Vogel /* Write bits 14:8 */ 132758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, reg_high)) 133758cc3dcSJack F Vogel goto fail; 134758cc3dcSJack F Vogel /* Write bits 7:0 */ 135758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF)) 136758cc3dcSJack F Vogel goto fail; 137758cc3dcSJack F Vogel /* Write csum */ 138758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, csum)) 139758cc3dcSJack F Vogel goto fail; 140758cc3dcSJack F Vogel /* Re-start condition */ 141758cc3dcSJack F Vogel ixgbe_i2c_start(hw); 142758cc3dcSJack F Vogel /* Device Address and read indication */ 143758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, addr | 1)) 144758cc3dcSJack F Vogel goto fail; 145758cc3dcSJack F Vogel /* Get upper bits */ 146758cc3dcSJack F Vogel if (ixgbe_in_i2c_byte_ack(hw, &high_bits)) 147758cc3dcSJack F Vogel goto fail; 148758cc3dcSJack F Vogel /* Get low bits */ 149758cc3dcSJack F Vogel if (ixgbe_in_i2c_byte_ack(hw, &low_bits)) 150758cc3dcSJack F Vogel goto fail; 151758cc3dcSJack F Vogel /* Get csum */ 1523a890053SGuinan Sun ixgbe_clock_in_i2c_byte(hw, &csum_byte); 153758cc3dcSJack F Vogel /* NACK */ 15479b36ec9SKevin Bowling if (ixgbe_clock_out_i2c_bit(hw, false)) 155758cc3dcSJack F Vogel goto fail; 156758cc3dcSJack F Vogel ixgbe_i2c_stop(hw); 1576f37f232SEric Joyner if (lock) 158758cc3dcSJack F Vogel hw->mac.ops.release_swfw_sync(hw, swfw_mask); 159758cc3dcSJack F Vogel *val = (high_bits << 8) | low_bits; 160758cc3dcSJack F Vogel return 0; 161758cc3dcSJack F Vogel 162758cc3dcSJack F Vogel fail: 163758cc3dcSJack F Vogel ixgbe_i2c_bus_clear(hw); 1646f37f232SEric Joyner if (lock) 165758cc3dcSJack F Vogel hw->mac.ops.release_swfw_sync(hw, swfw_mask); 166758cc3dcSJack F Vogel if (retry < max_retry) 167758cc3dcSJack F Vogel DEBUGOUT("I2C byte read combined error - Retrying.\n"); 168758cc3dcSJack F Vogel else 169758cc3dcSJack F Vogel DEBUGOUT("I2C byte read combined error.\n"); 170dc11ba4eSGuinan Sun retry++; 171dc11ba4eSGuinan Sun } while (retry <= max_retry); 172758cc3dcSJack F Vogel 173758cc3dcSJack F Vogel return IXGBE_ERR_I2C; 174758cc3dcSJack F Vogel } 175758cc3dcSJack F Vogel 176758cc3dcSJack F Vogel /** 1776f37f232SEric Joyner * ixgbe_write_i2c_combined_generic_int - Perform I2C write combined operation 178758cc3dcSJack F Vogel * @hw: pointer to the hardware structure 179758cc3dcSJack F Vogel * @addr: I2C bus address to write to 180758cc3dcSJack F Vogel * @reg: I2C device register to write to 181758cc3dcSJack F Vogel * @val: value to write 18279b36ec9SKevin Bowling * @lock: true if to take and release semaphore 183758cc3dcSJack F Vogel * 184758cc3dcSJack F Vogel * Returns an error code on error. 185758cc3dcSJack F Vogel */ 1868eb6488eSEric Joyner s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg, 1878eb6488eSEric Joyner u16 val, bool lock) 188758cc3dcSJack F Vogel { 1896f37f232SEric Joyner u32 swfw_mask = hw->phy.phy_semaphore_mask; 190758cc3dcSJack F Vogel int max_retry = 1; 191758cc3dcSJack F Vogel int retry = 0; 192758cc3dcSJack F Vogel u8 reg_high; 193758cc3dcSJack F Vogel u8 csum; 194758cc3dcSJack F Vogel 195758cc3dcSJack F Vogel reg_high = (reg >> 7) & 0xFE; /* Indicate write combined */ 196758cc3dcSJack F Vogel csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); 197758cc3dcSJack F Vogel csum = ixgbe_ones_comp_byte_add(csum, val >> 8); 198758cc3dcSJack F Vogel csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF); 199758cc3dcSJack F Vogel csum = ~csum; 200758cc3dcSJack F Vogel do { 2016f37f232SEric Joyner if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 2026f37f232SEric Joyner return IXGBE_ERR_SWFW_SYNC; 203758cc3dcSJack F Vogel ixgbe_i2c_start(hw); 204758cc3dcSJack F Vogel /* Device Address and write indication */ 205758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, addr)) 206758cc3dcSJack F Vogel goto fail; 207758cc3dcSJack F Vogel /* Write bits 14:8 */ 208758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, reg_high)) 209758cc3dcSJack F Vogel goto fail; 210758cc3dcSJack F Vogel /* Write bits 7:0 */ 211758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF)) 212758cc3dcSJack F Vogel goto fail; 213758cc3dcSJack F Vogel /* Write data 15:8 */ 214758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, val >> 8)) 215758cc3dcSJack F Vogel goto fail; 216758cc3dcSJack F Vogel /* Write data 7:0 */ 217758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, val & 0xFF)) 218758cc3dcSJack F Vogel goto fail; 219758cc3dcSJack F Vogel /* Write csum */ 220758cc3dcSJack F Vogel if (ixgbe_out_i2c_byte_ack(hw, csum)) 221758cc3dcSJack F Vogel goto fail; 222758cc3dcSJack F Vogel ixgbe_i2c_stop(hw); 2236f37f232SEric Joyner if (lock) 2246f37f232SEric Joyner hw->mac.ops.release_swfw_sync(hw, swfw_mask); 225758cc3dcSJack F Vogel return 0; 226758cc3dcSJack F Vogel 227758cc3dcSJack F Vogel fail: 228758cc3dcSJack F Vogel ixgbe_i2c_bus_clear(hw); 2296f37f232SEric Joyner if (lock) 2306f37f232SEric Joyner hw->mac.ops.release_swfw_sync(hw, swfw_mask); 231758cc3dcSJack F Vogel if (retry < max_retry) 232758cc3dcSJack F Vogel DEBUGOUT("I2C byte write combined error - Retrying.\n"); 233758cc3dcSJack F Vogel else 234758cc3dcSJack F Vogel DEBUGOUT("I2C byte write combined error.\n"); 235dc11ba4eSGuinan Sun retry++; 236dc11ba4eSGuinan Sun } while (retry <= max_retry); 237758cc3dcSJack F Vogel 238758cc3dcSJack F Vogel return IXGBE_ERR_I2C; 239758cc3dcSJack F Vogel } 240758cc3dcSJack F Vogel 241758cc3dcSJack F Vogel /** 2429ca4041bSJack F Vogel * ixgbe_init_phy_ops_generic - Inits PHY function ptrs 2439ca4041bSJack F Vogel * @hw: pointer to the hardware structure 24413705f88SJack F Vogel * 2459ca4041bSJack F Vogel * Initialize the function pointers. 24613705f88SJack F Vogel **/ 2479ca4041bSJack F Vogel s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw) 24813705f88SJack F Vogel { 2499ca4041bSJack F Vogel struct ixgbe_phy_info *phy = &hw->phy; 2509ca4041bSJack F Vogel 2512969bf0eSJack F Vogel DEBUGFUNC("ixgbe_init_phy_ops_generic"); 2522969bf0eSJack F Vogel 2539ca4041bSJack F Vogel /* PHY */ 254758cc3dcSJack F Vogel phy->ops.identify = ixgbe_identify_phy_generic; 255758cc3dcSJack F Vogel phy->ops.reset = ixgbe_reset_phy_generic; 256758cc3dcSJack F Vogel phy->ops.read_reg = ixgbe_read_phy_reg_generic; 257758cc3dcSJack F Vogel phy->ops.write_reg = ixgbe_write_phy_reg_generic; 258758cc3dcSJack F Vogel phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi; 259758cc3dcSJack F Vogel phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi; 260758cc3dcSJack F Vogel phy->ops.setup_link = ixgbe_setup_phy_link_generic; 261758cc3dcSJack F Vogel phy->ops.setup_link_speed = ixgbe_setup_phy_link_speed_generic; 2629ca4041bSJack F Vogel phy->ops.check_link = NULL; 2632969bf0eSJack F Vogel phy->ops.get_firmware_version = ixgbe_get_phy_firmware_version_generic; 264758cc3dcSJack F Vogel phy->ops.read_i2c_byte = ixgbe_read_i2c_byte_generic; 265758cc3dcSJack F Vogel phy->ops.write_i2c_byte = ixgbe_write_i2c_byte_generic; 266758cc3dcSJack F Vogel phy->ops.read_i2c_sff8472 = ixgbe_read_i2c_sff8472_generic; 267758cc3dcSJack F Vogel phy->ops.read_i2c_eeprom = ixgbe_read_i2c_eeprom_generic; 268758cc3dcSJack F Vogel phy->ops.write_i2c_eeprom = ixgbe_write_i2c_eeprom_generic; 269758cc3dcSJack F Vogel phy->ops.i2c_bus_clear = ixgbe_i2c_bus_clear; 270758cc3dcSJack F Vogel phy->ops.identify_sfp = ixgbe_identify_module_generic; 2711b6e0dbaSJack F Vogel phy->sfp_type = ixgbe_sfp_type_unknown; 2726f37f232SEric Joyner phy->ops.read_i2c_byte_unlocked = ixgbe_read_i2c_byte_generic_unlocked; 2736f37f232SEric Joyner phy->ops.write_i2c_byte_unlocked = 2746f37f232SEric Joyner ixgbe_write_i2c_byte_generic_unlocked; 275758cc3dcSJack F Vogel phy->ops.check_overtemp = ixgbe_tn_check_overtemp; 27613705f88SJack F Vogel return IXGBE_SUCCESS; 27713705f88SJack F Vogel } 27813705f88SJack F Vogel 27913705f88SJack F Vogel /** 2808eb6488eSEric Joyner * ixgbe_probe_phy - Probe a single address for a PHY 2818eb6488eSEric Joyner * @hw: pointer to hardware structure 2828eb6488eSEric Joyner * @phy_addr: PHY address to probe 2838eb6488eSEric Joyner * 28479b36ec9SKevin Bowling * Returns true if PHY found 2858eb6488eSEric Joyner */ 2868eb6488eSEric Joyner static bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr) 2878eb6488eSEric Joyner { 2888eb6488eSEric Joyner u16 ext_ability = 0; 2898eb6488eSEric Joyner 2908eb6488eSEric Joyner if (!ixgbe_validate_phy_addr(hw, phy_addr)) { 2918eb6488eSEric Joyner DEBUGOUT1("Unable to validate PHY address 0x%04X\n", 2928eb6488eSEric Joyner phy_addr); 29379b36ec9SKevin Bowling return false; 2948eb6488eSEric Joyner } 2958eb6488eSEric Joyner 2968eb6488eSEric Joyner if (ixgbe_get_phy_id(hw)) 29779b36ec9SKevin Bowling return false; 2988eb6488eSEric Joyner 2998eb6488eSEric Joyner hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); 3008eb6488eSEric Joyner 3018eb6488eSEric Joyner if (hw->phy.type == ixgbe_phy_unknown) { 3028eb6488eSEric Joyner hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY, 3038eb6488eSEric Joyner IXGBE_MDIO_PMA_PMD_DEV_TYPE, &ext_ability); 3048eb6488eSEric Joyner if (ext_ability & 3058eb6488eSEric Joyner (IXGBE_MDIO_PHY_10GBASET_ABILITY | 3068eb6488eSEric Joyner IXGBE_MDIO_PHY_1000BASET_ABILITY)) 3078eb6488eSEric Joyner hw->phy.type = ixgbe_phy_cu_unknown; 3088eb6488eSEric Joyner else 3098eb6488eSEric Joyner hw->phy.type = ixgbe_phy_generic; 3108eb6488eSEric Joyner } 3118eb6488eSEric Joyner 31279b36ec9SKevin Bowling return true; 3138eb6488eSEric Joyner } 3148eb6488eSEric Joyner 3158eb6488eSEric Joyner /** 31613705f88SJack F Vogel * ixgbe_identify_phy_generic - Get physical layer module 31713705f88SJack F Vogel * @hw: pointer to hardware structure 31813705f88SJack F Vogel * 31913705f88SJack F Vogel * Determines the physical layer module found on the current adapter. 32013705f88SJack F Vogel **/ 32113705f88SJack F Vogel s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) 32213705f88SJack F Vogel { 32313705f88SJack F Vogel s32 status = IXGBE_ERR_PHY_ADDR_INVALID; 3248eb6488eSEric Joyner u16 phy_addr; 32513705f88SJack F Vogel 3262969bf0eSJack F Vogel DEBUGFUNC("ixgbe_identify_phy_generic"); 3272969bf0eSJack F Vogel 328758cc3dcSJack F Vogel if (!hw->phy.phy_semaphore_mask) { 329758cc3dcSJack F Vogel if (hw->bus.lan_id) 330758cc3dcSJack F Vogel hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM; 331758cc3dcSJack F Vogel else 332758cc3dcSJack F Vogel hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM; 333758cc3dcSJack F Vogel } 334758cc3dcSJack F Vogel 3358eb6488eSEric Joyner if (hw->phy.type != ixgbe_phy_unknown) 3368eb6488eSEric Joyner return IXGBE_SUCCESS; 3370ac6dfecSJack F Vogel 3388eb6488eSEric Joyner if (hw->phy.nw_mng_if_sel) { 3398eb6488eSEric Joyner phy_addr = (hw->phy.nw_mng_if_sel & 3408eb6488eSEric Joyner IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >> 3418eb6488eSEric Joyner IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT; 3428eb6488eSEric Joyner if (ixgbe_probe_phy(hw, phy_addr)) 3438eb6488eSEric Joyner return IXGBE_SUCCESS; 3440ac6dfecSJack F Vogel else 3458eb6488eSEric Joyner return IXGBE_ERR_PHY_ADDR_INVALID; 3460ac6dfecSJack F Vogel } 3470ac6dfecSJack F Vogel 3488eb6488eSEric Joyner for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { 3498eb6488eSEric Joyner if (ixgbe_probe_phy(hw, phy_addr)) { 35013705f88SJack F Vogel status = IXGBE_SUCCESS; 35113705f88SJack F Vogel break; 35213705f88SJack F Vogel } 35313705f88SJack F Vogel } 354758cc3dcSJack F Vogel 355758cc3dcSJack F Vogel /* Certain media types do not have a phy so an address will not 356758cc3dcSJack F Vogel * be found and the code will take this path. Caller has to 357758cc3dcSJack F Vogel * decide if it is an error or not. 358758cc3dcSJack F Vogel */ 3598eb6488eSEric Joyner if (status != IXGBE_SUCCESS) 3600ac6dfecSJack F Vogel hw->phy.addr = 0; 3619ca4041bSJack F Vogel 36213705f88SJack F Vogel return status; 36313705f88SJack F Vogel } 36413705f88SJack F Vogel 36513705f88SJack F Vogel /** 366758cc3dcSJack F Vogel * ixgbe_check_reset_blocked - check status of MNG FW veto bit 367758cc3dcSJack F Vogel * @hw: pointer to the hardware structure 368758cc3dcSJack F Vogel * 369758cc3dcSJack F Vogel * This function checks the MMNGC.MNG_VETO bit to see if there are 370758cc3dcSJack F Vogel * any constraints on link from manageability. For MAC's that don't 371758cc3dcSJack F Vogel * have this bit just return faluse since the link can not be blocked 372758cc3dcSJack F Vogel * via this method. 373758cc3dcSJack F Vogel **/ 374758cc3dcSJack F Vogel s32 ixgbe_check_reset_blocked(struct ixgbe_hw *hw) 375758cc3dcSJack F Vogel { 376758cc3dcSJack F Vogel u32 mmngc; 377758cc3dcSJack F Vogel 378758cc3dcSJack F Vogel DEBUGFUNC("ixgbe_check_reset_blocked"); 379758cc3dcSJack F Vogel 380758cc3dcSJack F Vogel /* If we don't have this bit, it can't be blocking */ 381758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) 38279b36ec9SKevin Bowling return false; 383758cc3dcSJack F Vogel 384758cc3dcSJack F Vogel mmngc = IXGBE_READ_REG(hw, IXGBE_MMNGC); 385758cc3dcSJack F Vogel if (mmngc & IXGBE_MMNGC_MNG_VETO) { 386758cc3dcSJack F Vogel ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, 387758cc3dcSJack F Vogel "MNG_VETO bit detected.\n"); 38879b36ec9SKevin Bowling return true; 389758cc3dcSJack F Vogel } 390758cc3dcSJack F Vogel 39179b36ec9SKevin Bowling return false; 392758cc3dcSJack F Vogel } 393758cc3dcSJack F Vogel 394758cc3dcSJack F Vogel /** 39513705f88SJack F Vogel * ixgbe_validate_phy_addr - Determines phy address is valid 39613705f88SJack F Vogel * @hw: pointer to hardware structure 3977d48aa4cSEric Joyner * @phy_addr: PHY address 39813705f88SJack F Vogel * 39913705f88SJack F Vogel **/ 40013705f88SJack F Vogel bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr) 40113705f88SJack F Vogel { 40213705f88SJack F Vogel u16 phy_id = 0; 40379b36ec9SKevin Bowling bool valid = false; 40413705f88SJack F Vogel 4052969bf0eSJack F Vogel DEBUGFUNC("ixgbe_validate_phy_addr"); 4062969bf0eSJack F Vogel 40713705f88SJack F Vogel hw->phy.addr = phy_addr; 4089ca4041bSJack F Vogel hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, 4099ca4041bSJack F Vogel IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id); 41013705f88SJack F Vogel 41113705f88SJack F Vogel if (phy_id != 0xFFFF && phy_id != 0x0) 41279b36ec9SKevin Bowling valid = true; 41313705f88SJack F Vogel 4148eb6488eSEric Joyner DEBUGOUT1("PHY ID HIGH is 0x%04X\n", phy_id); 4158eb6488eSEric Joyner 41613705f88SJack F Vogel return valid; 41713705f88SJack F Vogel } 41813705f88SJack F Vogel 41913705f88SJack F Vogel /** 42013705f88SJack F Vogel * ixgbe_get_phy_id - Get the phy type 42113705f88SJack F Vogel * @hw: pointer to hardware structure 42213705f88SJack F Vogel * 42313705f88SJack F Vogel **/ 42413705f88SJack F Vogel s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) 42513705f88SJack F Vogel { 42613705f88SJack F Vogel u32 status; 42713705f88SJack F Vogel u16 phy_id_high = 0; 42813705f88SJack F Vogel u16 phy_id_low = 0; 42913705f88SJack F Vogel 4302969bf0eSJack F Vogel DEBUGFUNC("ixgbe_get_phy_id"); 4312969bf0eSJack F Vogel 4329ca4041bSJack F Vogel status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, 43313705f88SJack F Vogel IXGBE_MDIO_PMA_PMD_DEV_TYPE, 43413705f88SJack F Vogel &phy_id_high); 43513705f88SJack F Vogel 43613705f88SJack F Vogel if (status == IXGBE_SUCCESS) { 43713705f88SJack F Vogel hw->phy.id = (u32)(phy_id_high << 16); 4389ca4041bSJack F Vogel status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW, 43913705f88SJack F Vogel IXGBE_MDIO_PMA_PMD_DEV_TYPE, 44013705f88SJack F Vogel &phy_id_low); 44113705f88SJack F Vogel hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); 44213705f88SJack F Vogel hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); 44313705f88SJack F Vogel } 4448eb6488eSEric Joyner DEBUGOUT2("PHY_ID_HIGH 0x%04X, PHY_ID_LOW 0x%04X\n", 4458eb6488eSEric Joyner phy_id_high, phy_id_low); 4468eb6488eSEric Joyner 44713705f88SJack F Vogel return status; 44813705f88SJack F Vogel } 44913705f88SJack F Vogel 45013705f88SJack F Vogel /** 45113705f88SJack F Vogel * ixgbe_get_phy_type_from_id - Get the phy type 4528eb6488eSEric Joyner * @phy_id: PHY ID information 45313705f88SJack F Vogel * 45413705f88SJack F Vogel **/ 45513705f88SJack F Vogel enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) 45613705f88SJack F Vogel { 45713705f88SJack F Vogel enum ixgbe_phy_type phy_type; 45813705f88SJack F Vogel 4592969bf0eSJack F Vogel DEBUGFUNC("ixgbe_get_phy_type_from_id"); 4602969bf0eSJack F Vogel 46113705f88SJack F Vogel switch (phy_id) { 4629ca4041bSJack F Vogel case TN1010_PHY_ID: 4639ca4041bSJack F Vogel phy_type = ixgbe_phy_tn; 4649ca4041bSJack F Vogel break; 4659b56dfd2SRadoslaw Tyl case X550_PHY_ID: 46685d0a26eSJack F Vogel case X540_PHY_ID: 4670ac6dfecSJack F Vogel phy_type = ixgbe_phy_aq; 4680ac6dfecSJack F Vogel break; 46913705f88SJack F Vogel case QT2022_PHY_ID: 47013705f88SJack F Vogel phy_type = ixgbe_phy_qt; 47113705f88SJack F Vogel break; 4721b6e0dbaSJack F Vogel case ATH_PHY_ID: 4731b6e0dbaSJack F Vogel phy_type = ixgbe_phy_nl; 4741b6e0dbaSJack F Vogel break; 475758cc3dcSJack F Vogel case X557_PHY_ID: 4768eb6488eSEric Joyner case X557_PHY_ID2: 477758cc3dcSJack F Vogel phy_type = ixgbe_phy_x550em_ext_t; 478758cc3dcSJack F Vogel break; 4798eb6488eSEric Joyner case IXGBE_M88E1500_E_PHY_ID: 4808eb6488eSEric Joyner case IXGBE_M88E1543_E_PHY_ID: 4818eb6488eSEric Joyner phy_type = ixgbe_phy_ext_1g_t; 4828eb6488eSEric Joyner break; 48313705f88SJack F Vogel default: 48413705f88SJack F Vogel phy_type = ixgbe_phy_unknown; 48513705f88SJack F Vogel break; 48613705f88SJack F Vogel } 48713705f88SJack F Vogel return phy_type; 48813705f88SJack F Vogel } 48913705f88SJack F Vogel 49013705f88SJack F Vogel /** 49113705f88SJack F Vogel * ixgbe_reset_phy_generic - Performs a PHY reset 49213705f88SJack F Vogel * @hw: pointer to hardware structure 49313705f88SJack F Vogel **/ 49413705f88SJack F Vogel s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) 49513705f88SJack F Vogel { 4960ac6dfecSJack F Vogel u32 i; 4970ac6dfecSJack F Vogel u16 ctrl = 0; 4980ac6dfecSJack F Vogel s32 status = IXGBE_SUCCESS; 4990ac6dfecSJack F Vogel 5002969bf0eSJack F Vogel DEBUGFUNC("ixgbe_reset_phy_generic"); 5012969bf0eSJack F Vogel 5020ac6dfecSJack F Vogel if (hw->phy.type == ixgbe_phy_unknown) 5030ac6dfecSJack F Vogel status = ixgbe_identify_phy_generic(hw); 5040ac6dfecSJack F Vogel 5050ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS || hw->phy.type == ixgbe_phy_none) 5060ac6dfecSJack F Vogel goto out; 5070ac6dfecSJack F Vogel 5081a4e3449SJack F Vogel /* Don't reset PHY if it's shut down due to overtemp. */ 5091a4e3449SJack F Vogel if (!hw->phy.reset_if_overtemp && 5101a4e3449SJack F Vogel (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw))) 5111a4e3449SJack F Vogel goto out; 5121a4e3449SJack F Vogel 513758cc3dcSJack F Vogel /* Blocked by MNG FW so bail */ 514758cc3dcSJack F Vogel if (ixgbe_check_reset_blocked(hw)) 515758cc3dcSJack F Vogel goto out; 516758cc3dcSJack F Vogel 51713705f88SJack F Vogel /* 51813705f88SJack F Vogel * Perform soft PHY reset to the PHY_XS. 51913705f88SJack F Vogel * This will cause a soft reset to the PHY 52013705f88SJack F Vogel */ 5210ac6dfecSJack F Vogel hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, 52213705f88SJack F Vogel IXGBE_MDIO_PHY_XS_DEV_TYPE, 52313705f88SJack F Vogel IXGBE_MDIO_PHY_XS_RESET); 5240ac6dfecSJack F Vogel 525c0014855SJack F Vogel /* 526c0014855SJack F Vogel * Poll for reset bit to self-clear indicating reset is complete. 527c0014855SJack F Vogel * Some PHYs could take up to 3 seconds to complete and need about 528c0014855SJack F Vogel * 1.7 usec delay after the reset is complete. 529c0014855SJack F Vogel */ 530c0014855SJack F Vogel for (i = 0; i < 30; i++) { 531c0014855SJack F Vogel msec_delay(100); 5328eb6488eSEric Joyner if (hw->phy.type == ixgbe_phy_x550em_ext_t) { 5338eb6488eSEric Joyner status = hw->phy.ops.read_reg(hw, 5348eb6488eSEric Joyner IXGBE_MDIO_TX_VENDOR_ALARMS_3, 5358eb6488eSEric Joyner IXGBE_MDIO_PMA_PMD_DEV_TYPE, 5368eb6488eSEric Joyner &ctrl); 5378eb6488eSEric Joyner if (status != IXGBE_SUCCESS) 5388eb6488eSEric Joyner return status; 5398eb6488eSEric Joyner 5408eb6488eSEric Joyner if (ctrl & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) { 5418eb6488eSEric Joyner usec_delay(2); 5428eb6488eSEric Joyner break; 5438eb6488eSEric Joyner } 5448eb6488eSEric Joyner } else { 5458eb6488eSEric Joyner status = hw->phy.ops.read_reg(hw, 5468eb6488eSEric Joyner IXGBE_MDIO_PHY_XS_CONTROL, 5478eb6488eSEric Joyner IXGBE_MDIO_PHY_XS_DEV_TYPE, 5488eb6488eSEric Joyner &ctrl); 5498eb6488eSEric Joyner if (status != IXGBE_SUCCESS) 5508eb6488eSEric Joyner return status; 5518eb6488eSEric Joyner 552c0014855SJack F Vogel if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) { 553c0014855SJack F Vogel usec_delay(2); 5540ac6dfecSJack F Vogel break; 5550ac6dfecSJack F Vogel } 556c0014855SJack F Vogel } 5578eb6488eSEric Joyner } 5580ac6dfecSJack F Vogel 5590ac6dfecSJack F Vogel if (ctrl & IXGBE_MDIO_PHY_XS_RESET) { 5600ac6dfecSJack F Vogel status = IXGBE_ERR_RESET_FAILED; 561fd75b91dSJack F Vogel ERROR_REPORT1(IXGBE_ERROR_POLLING, 562fd75b91dSJack F Vogel "PHY reset polling failed to complete.\n"); 5630ac6dfecSJack F Vogel } 5640ac6dfecSJack F Vogel 5650ac6dfecSJack F Vogel out: 5660ac6dfecSJack F Vogel return status; 56713705f88SJack F Vogel } 56813705f88SJack F Vogel 56913705f88SJack F Vogel /** 57080a39a2bSGuinan Sun * ixgbe_restart_auto_neg - Restart auto negotiation on the PHY 57180a39a2bSGuinan Sun * @hw: pointer to hardware structure 57280a39a2bSGuinan Sun **/ 57380a39a2bSGuinan Sun void ixgbe_restart_auto_neg(struct ixgbe_hw *hw) 57480a39a2bSGuinan Sun { 57580a39a2bSGuinan Sun u16 autoneg_reg; 57680a39a2bSGuinan Sun 57780a39a2bSGuinan Sun /* Check if PHY reset is blocked by MNG FW */ 57880a39a2bSGuinan Sun if (ixgbe_check_reset_blocked(hw)) 57980a39a2bSGuinan Sun return; 58080a39a2bSGuinan Sun 58180a39a2bSGuinan Sun /* Restart PHY auto-negotiation. */ 58280a39a2bSGuinan Sun hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, 58380a39a2bSGuinan Sun IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); 58480a39a2bSGuinan Sun autoneg_reg |= IXGBE_MII_RESTART; 58580a39a2bSGuinan Sun hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, 58680a39a2bSGuinan Sun IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); 58780a39a2bSGuinan Sun } 58880a39a2bSGuinan Sun 58980a39a2bSGuinan Sun /** 590edef2769SRadoslaw Tyl * ixgbe_read_phy_reg_mdi - Reads a value from a specified PHY register without 591fd75b91dSJack F Vogel * the SWFW lock 59213705f88SJack F Vogel * @hw: pointer to hardware structure 59313705f88SJack F Vogel * @reg_addr: 32 bit address of PHY register to read 5947d48aa4cSEric Joyner * @device_type: 5 bit device type 59513705f88SJack F Vogel * @phy_data: Pointer to read data from PHY register 59613705f88SJack F Vogel **/ 597fd75b91dSJack F Vogel s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, 598fd75b91dSJack F Vogel u16 *phy_data) 59913705f88SJack F Vogel { 600fd75b91dSJack F Vogel u32 i, data, command; 60113705f88SJack F Vogel 60213705f88SJack F Vogel /* Setup and write the address cycle command */ 60313705f88SJack F Vogel command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 60413705f88SJack F Vogel (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 60513705f88SJack F Vogel (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | 60613705f88SJack F Vogel (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); 60713705f88SJack F Vogel 60813705f88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 60913705f88SJack F Vogel 61013705f88SJack F Vogel /* 61113705f88SJack F Vogel * Check every 10 usec to see if the address cycle completed. 61213705f88SJack F Vogel * The MDI Command bit will clear when the operation is 61313705f88SJack F Vogel * complete 61413705f88SJack F Vogel */ 6153ec35e52SJack F Vogel for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 61613705f88SJack F Vogel usec_delay(10); 61713705f88SJack F Vogel 61813705f88SJack F Vogel command = IXGBE_READ_REG(hw, IXGBE_MSCA); 6191b6e0dbaSJack F Vogel if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 62013705f88SJack F Vogel break; 62113705f88SJack F Vogel } 62213705f88SJack F Vogel 623fd75b91dSJack F Vogel 62413705f88SJack F Vogel if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 625fd75b91dSJack F Vogel ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address command did not complete.\n"); 6268eb6488eSEric Joyner DEBUGOUT("PHY address command did not complete, returning IXGBE_ERR_PHY\n"); 627fd75b91dSJack F Vogel return IXGBE_ERR_PHY; 62813705f88SJack F Vogel } 62913705f88SJack F Vogel 63013705f88SJack F Vogel /* 63113705f88SJack F Vogel * Address cycle complete, setup and write the read 63213705f88SJack F Vogel * command 63313705f88SJack F Vogel */ 63413705f88SJack F Vogel command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 63513705f88SJack F Vogel (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 63613705f88SJack F Vogel (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | 63713705f88SJack F Vogel (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); 63813705f88SJack F Vogel 63913705f88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 64013705f88SJack F Vogel 64113705f88SJack F Vogel /* 64213705f88SJack F Vogel * Check every 10 usec to see if the address cycle 64313705f88SJack F Vogel * completed. The MDI Command bit will clear when the 64413705f88SJack F Vogel * operation is complete 64513705f88SJack F Vogel */ 6463ec35e52SJack F Vogel for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 64713705f88SJack F Vogel usec_delay(10); 64813705f88SJack F Vogel 64913705f88SJack F Vogel command = IXGBE_READ_REG(hw, IXGBE_MSCA); 65013705f88SJack F Vogel if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 65113705f88SJack F Vogel break; 65213705f88SJack F Vogel } 65313705f88SJack F Vogel 65413705f88SJack F Vogel if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 655fd75b91dSJack F Vogel ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY read command didn't complete\n"); 6568eb6488eSEric Joyner DEBUGOUT("PHY read command didn't complete, returning IXGBE_ERR_PHY\n"); 657fd75b91dSJack F Vogel return IXGBE_ERR_PHY; 658fd75b91dSJack F Vogel } 659fd75b91dSJack F Vogel 66013705f88SJack F Vogel /* 66113705f88SJack F Vogel * Read operation is complete. Get the data 66213705f88SJack F Vogel * from MSRWD 66313705f88SJack F Vogel */ 66413705f88SJack F Vogel data = IXGBE_READ_REG(hw, IXGBE_MSRWD); 66513705f88SJack F Vogel data >>= IXGBE_MSRWD_READ_DATA_SHIFT; 66613705f88SJack F Vogel *phy_data = (u16)(data); 66713705f88SJack F Vogel 668fd75b91dSJack F Vogel return IXGBE_SUCCESS; 66913705f88SJack F Vogel } 67013705f88SJack F Vogel 67113705f88SJack F Vogel /** 672fd75b91dSJack F Vogel * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register 673fd75b91dSJack F Vogel * using the SWFW lock - this function is needed in most cases 67413705f88SJack F Vogel * @hw: pointer to hardware structure 675fd75b91dSJack F Vogel * @reg_addr: 32 bit address of PHY register to read 6767d48aa4cSEric Joyner * @device_type: 5 bit device type 677fd75b91dSJack F Vogel * @phy_data: Pointer to read data from PHY register 67813705f88SJack F Vogel **/ 679fd75b91dSJack F Vogel s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, 680fd75b91dSJack F Vogel u32 device_type, u16 *phy_data) 68113705f88SJack F Vogel { 682fd75b91dSJack F Vogel s32 status; 683758cc3dcSJack F Vogel u32 gssr = hw->phy.phy_semaphore_mask; 68413705f88SJack F Vogel 685fd75b91dSJack F Vogel DEBUGFUNC("ixgbe_read_phy_reg_generic"); 6862969bf0eSJack F Vogel 6878eb6488eSEric Joyner if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) 6888eb6488eSEric Joyner return IXGBE_ERR_SWFW_SYNC; 6898eb6488eSEric Joyner 6908eb6488eSEric Joyner status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data); 6918eb6488eSEric Joyner 692fd75b91dSJack F Vogel hw->mac.ops.release_swfw_sync(hw, gssr); 69313705f88SJack F Vogel 694fd75b91dSJack F Vogel return status; 695fd75b91dSJack F Vogel } 696fd75b91dSJack F Vogel 697fd75b91dSJack F Vogel /** 698fd75b91dSJack F Vogel * ixgbe_write_phy_reg_mdi - Writes a value to specified PHY register 699fd75b91dSJack F Vogel * without SWFW lock 700fd75b91dSJack F Vogel * @hw: pointer to hardware structure 701fd75b91dSJack F Vogel * @reg_addr: 32 bit PHY register to write 702fd75b91dSJack F Vogel * @device_type: 5 bit device type 703fd75b91dSJack F Vogel * @phy_data: Data to write to the PHY register 704fd75b91dSJack F Vogel **/ 705fd75b91dSJack F Vogel s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, 706fd75b91dSJack F Vogel u32 device_type, u16 phy_data) 707fd75b91dSJack F Vogel { 708fd75b91dSJack F Vogel u32 i, command; 709fd75b91dSJack F Vogel 71013705f88SJack F Vogel /* Put the data in the MDI single read and write data register*/ 71113705f88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); 71213705f88SJack F Vogel 71313705f88SJack F Vogel /* Setup and write the address cycle command */ 71413705f88SJack F Vogel command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 71513705f88SJack F Vogel (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 71613705f88SJack F Vogel (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | 71713705f88SJack F Vogel (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); 71813705f88SJack F Vogel 71913705f88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 72013705f88SJack F Vogel 72113705f88SJack F Vogel /* 72213705f88SJack F Vogel * Check every 10 usec to see if the address cycle completed. 72313705f88SJack F Vogel * The MDI Command bit will clear when the operation is 72413705f88SJack F Vogel * complete 72513705f88SJack F Vogel */ 7263ec35e52SJack F Vogel for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 72713705f88SJack F Vogel usec_delay(10); 72813705f88SJack F Vogel 72913705f88SJack F Vogel command = IXGBE_READ_REG(hw, IXGBE_MSCA); 7309ca4041bSJack F Vogel if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 73113705f88SJack F Vogel break; 73213705f88SJack F Vogel } 73313705f88SJack F Vogel 7349ca4041bSJack F Vogel if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 735fd75b91dSJack F Vogel ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address cmd didn't complete\n"); 736fd75b91dSJack F Vogel return IXGBE_ERR_PHY; 7379ca4041bSJack F Vogel } 73813705f88SJack F Vogel 73913705f88SJack F Vogel /* 74013705f88SJack F Vogel * Address cycle complete, setup and write the write 74113705f88SJack F Vogel * command 74213705f88SJack F Vogel */ 74313705f88SJack F Vogel command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | 74413705f88SJack F Vogel (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | 74513705f88SJack F Vogel (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | 74613705f88SJack F Vogel (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); 74713705f88SJack F Vogel 74813705f88SJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); 74913705f88SJack F Vogel 75013705f88SJack F Vogel /* 75113705f88SJack F Vogel * Check every 10 usec to see if the address cycle 75213705f88SJack F Vogel * completed. The MDI Command bit will clear when the 75313705f88SJack F Vogel * operation is complete 75413705f88SJack F Vogel */ 7553ec35e52SJack F Vogel for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { 75613705f88SJack F Vogel usec_delay(10); 75713705f88SJack F Vogel 75813705f88SJack F Vogel command = IXGBE_READ_REG(hw, IXGBE_MSCA); 7599ca4041bSJack F Vogel if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) 76013705f88SJack F Vogel break; 76113705f88SJack F Vogel } 76213705f88SJack F Vogel 7639ca4041bSJack F Vogel if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { 764fd75b91dSJack F Vogel ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY write cmd didn't complete\n"); 765fd75b91dSJack F Vogel return IXGBE_ERR_PHY; 7669ca4041bSJack F Vogel } 76713705f88SJack F Vogel 768fd75b91dSJack F Vogel return IXGBE_SUCCESS; 769fd75b91dSJack F Vogel } 770fd75b91dSJack F Vogel 771fd75b91dSJack F Vogel /** 772fd75b91dSJack F Vogel * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register 773fd75b91dSJack F Vogel * using SWFW lock- this function is needed in most cases 774fd75b91dSJack F Vogel * @hw: pointer to hardware structure 775fd75b91dSJack F Vogel * @reg_addr: 32 bit PHY register to write 776fd75b91dSJack F Vogel * @device_type: 5 bit device type 777fd75b91dSJack F Vogel * @phy_data: Data to write to the PHY register 778fd75b91dSJack F Vogel **/ 779fd75b91dSJack F Vogel s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, 780fd75b91dSJack F Vogel u32 device_type, u16 phy_data) 781fd75b91dSJack F Vogel { 782fd75b91dSJack F Vogel s32 status; 783758cc3dcSJack F Vogel u32 gssr = hw->phy.phy_semaphore_mask; 784fd75b91dSJack F Vogel 785fd75b91dSJack F Vogel DEBUGFUNC("ixgbe_write_phy_reg_generic"); 786fd75b91dSJack F Vogel 787fd75b91dSJack F Vogel if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) { 7888eb6488eSEric Joyner status = hw->phy.ops.write_reg_mdi(hw, reg_addr, device_type, 789fd75b91dSJack F Vogel phy_data); 79085d0a26eSJack F Vogel hw->mac.ops.release_swfw_sync(hw, gssr); 791fd75b91dSJack F Vogel } else { 792fd75b91dSJack F Vogel status = IXGBE_ERR_SWFW_SYNC; 79313705f88SJack F Vogel } 79413705f88SJack F Vogel 79513705f88SJack F Vogel return status; 79613705f88SJack F Vogel } 79713705f88SJack F Vogel 79813705f88SJack F Vogel /** 799758cc3dcSJack F Vogel * ixgbe_setup_phy_link_generic - Set and restart auto-neg 80013705f88SJack F Vogel * @hw: pointer to hardware structure 80113705f88SJack F Vogel * 802758cc3dcSJack F Vogel * Restart auto-negotiation and PHY and waits for completion. 80313705f88SJack F Vogel **/ 8049ca4041bSJack F Vogel s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) 80513705f88SJack F Vogel { 806d8602bb9SJack F Vogel s32 status = IXGBE_SUCCESS; 8079ca4041bSJack F Vogel u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; 80879b36ec9SKevin Bowling bool autoneg = false; 8092969bf0eSJack F Vogel ixgbe_link_speed speed; 8109ca4041bSJack F Vogel 8112969bf0eSJack F Vogel DEBUGFUNC("ixgbe_setup_phy_link_generic"); 8129ca4041bSJack F Vogel 8132969bf0eSJack F Vogel ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg); 8149ca4041bSJack F Vogel 8152969bf0eSJack F Vogel /* Set or unset auto-negotiation 10G advertisement */ 8162969bf0eSJack F Vogel hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, 8172969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 8182969bf0eSJack F Vogel &autoneg_reg); 8192969bf0eSJack F Vogel 8202969bf0eSJack F Vogel autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE; 8218eb6488eSEric Joyner if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) && 8228eb6488eSEric Joyner (speed & IXGBE_LINK_SPEED_10GB_FULL)) 8232969bf0eSJack F Vogel autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE; 8242969bf0eSJack F Vogel 8252969bf0eSJack F Vogel hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, 8262969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 8272969bf0eSJack F Vogel autoneg_reg); 8288eb6488eSEric Joyner 8298eb6488eSEric Joyner hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, 8308eb6488eSEric Joyner IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 8318eb6488eSEric Joyner &autoneg_reg); 8322969bf0eSJack F Vogel 833758cc3dcSJack F Vogel if (hw->mac.type == ixgbe_mac_X550) { 834a9ca1c79SSean Bruno /* Set or unset auto-negotiation 5G advertisement */ 835758cc3dcSJack F Vogel autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE; 8368eb6488eSEric Joyner if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) && 8378eb6488eSEric Joyner (speed & IXGBE_LINK_SPEED_5GB_FULL)) 838758cc3dcSJack F Vogel autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE; 839758cc3dcSJack F Vogel 840a9ca1c79SSean Bruno /* Set or unset auto-negotiation 2.5G advertisement */ 841758cc3dcSJack F Vogel autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE; 8428eb6488eSEric Joyner if ((hw->phy.autoneg_advertised & 8438eb6488eSEric Joyner IXGBE_LINK_SPEED_2_5GB_FULL) && 8448eb6488eSEric Joyner (speed & IXGBE_LINK_SPEED_2_5GB_FULL)) 845758cc3dcSJack F Vogel autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE; 846758cc3dcSJack F Vogel } 847758cc3dcSJack F Vogel 8482969bf0eSJack F Vogel /* Set or unset auto-negotiation 1G advertisement */ 8492969bf0eSJack F Vogel autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE; 8508eb6488eSEric Joyner if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) && 8518eb6488eSEric Joyner (speed & IXGBE_LINK_SPEED_1GB_FULL)) 8522969bf0eSJack F Vogel autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE; 8532969bf0eSJack F Vogel 8548eb6488eSEric Joyner hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, 8552969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 8562969bf0eSJack F Vogel autoneg_reg); 8572969bf0eSJack F Vogel 8582969bf0eSJack F Vogel /* Set or unset auto-negotiation 100M advertisement */ 8592969bf0eSJack F Vogel hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG, 8602969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 8612969bf0eSJack F Vogel &autoneg_reg); 8622969bf0eSJack F Vogel 86385d0a26eSJack F Vogel autoneg_reg &= ~(IXGBE_MII_100BASE_T_ADVERTISE | 86485d0a26eSJack F Vogel IXGBE_MII_100BASE_T_ADVERTISE_HALF); 8658eb6488eSEric Joyner if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) && 8668eb6488eSEric Joyner (speed & IXGBE_LINK_SPEED_100_FULL)) 8672969bf0eSJack F Vogel autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE; 8682969bf0eSJack F Vogel 8692969bf0eSJack F Vogel hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG, 8702969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 8712969bf0eSJack F Vogel autoneg_reg); 8729ca4041bSJack F Vogel 87380a39a2bSGuinan Sun ixgbe_restart_auto_neg(hw); 8749ca4041bSJack F Vogel return status; 87513705f88SJack F Vogel } 87613705f88SJack F Vogel 87713705f88SJack F Vogel /** 8789ca4041bSJack F Vogel * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities 87913705f88SJack F Vogel * @hw: pointer to hardware structure 88013705f88SJack F Vogel * @speed: new link speed 8817d48aa4cSEric Joyner * @autoneg_wait_to_complete: unused 88213705f88SJack F Vogel **/ 8839ca4041bSJack F Vogel s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, 8849ca4041bSJack F Vogel ixgbe_link_speed speed, 88513705f88SJack F Vogel bool autoneg_wait_to_complete) 88613705f88SJack F Vogel { 8870ecc2ff0SJack F Vogel UNREFERENCED_1PARAMETER(autoneg_wait_to_complete); 8889ca4041bSJack F Vogel 8892969bf0eSJack F Vogel DEBUGFUNC("ixgbe_setup_phy_link_speed_generic"); 8902969bf0eSJack F Vogel 8919ca4041bSJack F Vogel /* 8929ca4041bSJack F Vogel * Clear autoneg_advertised and set new values based on input link 8939ca4041bSJack F Vogel * speed. 8949ca4041bSJack F Vogel */ 8959ca4041bSJack F Vogel hw->phy.autoneg_advertised = 0; 8969ca4041bSJack F Vogel 8971b6e0dbaSJack F Vogel if (speed & IXGBE_LINK_SPEED_10GB_FULL) 8989ca4041bSJack F Vogel hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; 8991b6e0dbaSJack F Vogel 900758cc3dcSJack F Vogel if (speed & IXGBE_LINK_SPEED_5GB_FULL) 901758cc3dcSJack F Vogel hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_5GB_FULL; 902758cc3dcSJack F Vogel 903758cc3dcSJack F Vogel if (speed & IXGBE_LINK_SPEED_2_5GB_FULL) 904758cc3dcSJack F Vogel hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_2_5GB_FULL; 905758cc3dcSJack F Vogel 9061b6e0dbaSJack F Vogel if (speed & IXGBE_LINK_SPEED_1GB_FULL) 9079ca4041bSJack F Vogel hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; 90813705f88SJack F Vogel 9090ac6dfecSJack F Vogel if (speed & IXGBE_LINK_SPEED_100_FULL) 9100ac6dfecSJack F Vogel hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL; 9110ac6dfecSJack F Vogel 9128eb6488eSEric Joyner if (speed & IXGBE_LINK_SPEED_10_FULL) 9138eb6488eSEric Joyner hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10_FULL; 9148eb6488eSEric Joyner 9159ca4041bSJack F Vogel /* Setup link based on the new speed settings */ 916a9ca1c79SSean Bruno ixgbe_setup_phy_link(hw); 9179ca4041bSJack F Vogel 9189ca4041bSJack F Vogel return IXGBE_SUCCESS; 9199ca4041bSJack F Vogel } 9209ca4041bSJack F Vogel 9219ca4041bSJack F Vogel /** 922a9ca1c79SSean Bruno * ixgbe_get_copper_speeds_supported - Get copper link speeds from phy 923a9ca1c79SSean Bruno * @hw: pointer to hardware structure 924a9ca1c79SSean Bruno * 925a9ca1c79SSean Bruno * Determines the supported link capabilities by reading the PHY auto 926a9ca1c79SSean Bruno * negotiation register. 927a9ca1c79SSean Bruno **/ 928a9ca1c79SSean Bruno static s32 ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw) 929a9ca1c79SSean Bruno { 930a9ca1c79SSean Bruno s32 status; 931a9ca1c79SSean Bruno u16 speed_ability; 932a9ca1c79SSean Bruno 933a9ca1c79SSean Bruno status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, 934a9ca1c79SSean Bruno IXGBE_MDIO_PMA_PMD_DEV_TYPE, 935a9ca1c79SSean Bruno &speed_ability); 936a9ca1c79SSean Bruno if (status) 937a9ca1c79SSean Bruno return status; 938a9ca1c79SSean Bruno 939a9ca1c79SSean Bruno if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) 940a9ca1c79SSean Bruno hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL; 941a9ca1c79SSean Bruno if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G) 942a9ca1c79SSean Bruno hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL; 943a9ca1c79SSean Bruno if (speed_ability & IXGBE_MDIO_PHY_SPEED_100M) 944a9ca1c79SSean Bruno hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL; 945a9ca1c79SSean Bruno 946a9ca1c79SSean Bruno switch (hw->mac.type) { 947a9ca1c79SSean Bruno case ixgbe_mac_X550: 948a9ca1c79SSean Bruno hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL; 949a9ca1c79SSean Bruno hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL; 950a9ca1c79SSean Bruno break; 951a9ca1c79SSean Bruno case ixgbe_mac_X550EM_x: 9528eb6488eSEric Joyner case ixgbe_mac_X550EM_a: 953a9ca1c79SSean Bruno hw->phy.speeds_supported &= ~IXGBE_LINK_SPEED_100_FULL; 954a9ca1c79SSean Bruno break; 955a9ca1c79SSean Bruno default: 956a9ca1c79SSean Bruno break; 957a9ca1c79SSean Bruno } 958a9ca1c79SSean Bruno 959a9ca1c79SSean Bruno return status; 960a9ca1c79SSean Bruno } 961a9ca1c79SSean Bruno 962a9ca1c79SSean Bruno /** 9630ac6dfecSJack F Vogel * ixgbe_get_copper_link_capabilities_generic - Determines link capabilities 9640ac6dfecSJack F Vogel * @hw: pointer to hardware structure 9650ac6dfecSJack F Vogel * @speed: pointer to link speed 9660ac6dfecSJack F Vogel * @autoneg: boolean auto-negotiation value 9670ac6dfecSJack F Vogel **/ 9680ac6dfecSJack F Vogel s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, 9690ac6dfecSJack F Vogel ixgbe_link_speed *speed, 9700ac6dfecSJack F Vogel bool *autoneg) 9710ac6dfecSJack F Vogel { 972a9ca1c79SSean Bruno s32 status = IXGBE_SUCCESS; 9730ac6dfecSJack F Vogel 9742969bf0eSJack F Vogel DEBUGFUNC("ixgbe_get_copper_link_capabilities_generic"); 9752969bf0eSJack F Vogel 97679b36ec9SKevin Bowling *autoneg = true; 977a9ca1c79SSean Bruno if (!hw->phy.speeds_supported) 978a9ca1c79SSean Bruno status = ixgbe_get_copper_speeds_supported(hw); 9790ac6dfecSJack F Vogel 980a9ca1c79SSean Bruno *speed = hw->phy.speeds_supported; 9810ac6dfecSJack F Vogel return status; 9820ac6dfecSJack F Vogel } 9830ac6dfecSJack F Vogel 9840ac6dfecSJack F Vogel /** 9859ca4041bSJack F Vogel * ixgbe_check_phy_link_tnx - Determine link and speed status 9869ca4041bSJack F Vogel * @hw: pointer to hardware structure 9877d48aa4cSEric Joyner * @speed: current link speed 98879b36ec9SKevin Bowling * @link_up: true is link is up, false otherwise 9899ca4041bSJack F Vogel * 9909ca4041bSJack F Vogel * Reads the VS1 register to determine if link is up and the current speed for 9919ca4041bSJack F Vogel * the PHY. 9929ca4041bSJack F Vogel **/ 9939ca4041bSJack F Vogel s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, 9949ca4041bSJack F Vogel bool *link_up) 9959ca4041bSJack F Vogel { 9969ca4041bSJack F Vogel s32 status = IXGBE_SUCCESS; 9979ca4041bSJack F Vogel u32 time_out; 9989ca4041bSJack F Vogel u32 max_time_out = 10; 9999ca4041bSJack F Vogel u16 phy_link = 0; 10009ca4041bSJack F Vogel u16 phy_speed = 0; 10019ca4041bSJack F Vogel u16 phy_data = 0; 10029ca4041bSJack F Vogel 10032969bf0eSJack F Vogel DEBUGFUNC("ixgbe_check_phy_link_tnx"); 10042969bf0eSJack F Vogel 10059ca4041bSJack F Vogel /* Initialize speed and link to default case */ 100679b36ec9SKevin Bowling *link_up = false; 10079ca4041bSJack F Vogel *speed = IXGBE_LINK_SPEED_10GB_FULL; 10089ca4041bSJack F Vogel 10099ca4041bSJack F Vogel /* 10109ca4041bSJack F Vogel * Check current speed and link status of the PHY register. 10119ca4041bSJack F Vogel * This is a vendor specific register and may have to 10129ca4041bSJack F Vogel * be changed for other copper PHYs. 10139ca4041bSJack F Vogel */ 10149ca4041bSJack F Vogel for (time_out = 0; time_out < max_time_out; time_out++) { 10159ca4041bSJack F Vogel usec_delay(10); 10169ca4041bSJack F Vogel status = hw->phy.ops.read_reg(hw, 10179ca4041bSJack F Vogel IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, 10189ca4041bSJack F Vogel IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 10199ca4041bSJack F Vogel &phy_data); 102085d0a26eSJack F Vogel phy_link = phy_data & IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; 10219ca4041bSJack F Vogel phy_speed = phy_data & 10229ca4041bSJack F Vogel IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; 10239ca4041bSJack F Vogel if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { 102479b36ec9SKevin Bowling *link_up = true; 10259ca4041bSJack F Vogel if (phy_speed == 10269ca4041bSJack F Vogel IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) 10279ca4041bSJack F Vogel *speed = IXGBE_LINK_SPEED_1GB_FULL; 10289ca4041bSJack F Vogel break; 10299ca4041bSJack F Vogel } 10309ca4041bSJack F Vogel } 10319ca4041bSJack F Vogel 10329ca4041bSJack F Vogel return status; 10339ca4041bSJack F Vogel } 10349ca4041bSJack F Vogel 10359ca4041bSJack F Vogel /** 1036758cc3dcSJack F Vogel * ixgbe_setup_phy_link_tnx - Set and restart auto-neg 10372969bf0eSJack F Vogel * @hw: pointer to hardware structure 10382969bf0eSJack F Vogel * 1039758cc3dcSJack F Vogel * Restart auto-negotiation and PHY and waits for completion. 10402969bf0eSJack F Vogel **/ 10412969bf0eSJack F Vogel s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) 10422969bf0eSJack F Vogel { 10432969bf0eSJack F Vogel s32 status = IXGBE_SUCCESS; 10442969bf0eSJack F Vogel u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; 104579b36ec9SKevin Bowling bool autoneg = false; 10462969bf0eSJack F Vogel ixgbe_link_speed speed; 10472969bf0eSJack F Vogel 10482969bf0eSJack F Vogel DEBUGFUNC("ixgbe_setup_phy_link_tnx"); 10492969bf0eSJack F Vogel 10502969bf0eSJack F Vogel ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg); 10512969bf0eSJack F Vogel 10522969bf0eSJack F Vogel if (speed & IXGBE_LINK_SPEED_10GB_FULL) { 10532969bf0eSJack F Vogel /* Set or unset auto-negotiation 10G advertisement */ 10542969bf0eSJack F Vogel hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, 10552969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 10562969bf0eSJack F Vogel &autoneg_reg); 10572969bf0eSJack F Vogel 10582969bf0eSJack F Vogel autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE; 10592969bf0eSJack F Vogel if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) 10602969bf0eSJack F Vogel autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE; 10612969bf0eSJack F Vogel 10622969bf0eSJack F Vogel hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, 10632969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 10642969bf0eSJack F Vogel autoneg_reg); 10652969bf0eSJack F Vogel } 10662969bf0eSJack F Vogel 10672969bf0eSJack F Vogel if (speed & IXGBE_LINK_SPEED_1GB_FULL) { 10682969bf0eSJack F Vogel /* Set or unset auto-negotiation 1G advertisement */ 10692969bf0eSJack F Vogel hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG, 10702969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 10712969bf0eSJack F Vogel &autoneg_reg); 10722969bf0eSJack F Vogel 10732969bf0eSJack F Vogel autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX; 10742969bf0eSJack F Vogel if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) 10752969bf0eSJack F Vogel autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX; 10762969bf0eSJack F Vogel 10772969bf0eSJack F Vogel hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG, 10782969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 10792969bf0eSJack F Vogel autoneg_reg); 10802969bf0eSJack F Vogel } 10812969bf0eSJack F Vogel 10822969bf0eSJack F Vogel if (speed & IXGBE_LINK_SPEED_100_FULL) { 10832969bf0eSJack F Vogel /* Set or unset auto-negotiation 100M advertisement */ 10842969bf0eSJack F Vogel hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG, 10852969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 10862969bf0eSJack F Vogel &autoneg_reg); 10872969bf0eSJack F Vogel 10882969bf0eSJack F Vogel autoneg_reg &= ~IXGBE_MII_100BASE_T_ADVERTISE; 10892969bf0eSJack F Vogel if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) 10902969bf0eSJack F Vogel autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE; 10912969bf0eSJack F Vogel 10922969bf0eSJack F Vogel hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG, 10932969bf0eSJack F Vogel IXGBE_MDIO_AUTO_NEG_DEV_TYPE, 10942969bf0eSJack F Vogel autoneg_reg); 10952969bf0eSJack F Vogel } 10962969bf0eSJack F Vogel 109780a39a2bSGuinan Sun ixgbe_restart_auto_neg(hw); 10982969bf0eSJack F Vogel return status; 10992969bf0eSJack F Vogel } 11002969bf0eSJack F Vogel 11012969bf0eSJack F Vogel /** 11029ca4041bSJack F Vogel * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version 11039ca4041bSJack F Vogel * @hw: pointer to hardware structure 11049ca4041bSJack F Vogel * @firmware_version: pointer to the PHY Firmware Version 11059ca4041bSJack F Vogel **/ 11069ca4041bSJack F Vogel s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, 11079ca4041bSJack F Vogel u16 *firmware_version) 11089ca4041bSJack F Vogel { 1109758cc3dcSJack F Vogel s32 status; 11109ca4041bSJack F Vogel 11112969bf0eSJack F Vogel DEBUGFUNC("ixgbe_get_phy_firmware_version_tnx"); 11122969bf0eSJack F Vogel 11139ca4041bSJack F Vogel status = hw->phy.ops.read_reg(hw, TNX_FW_REV, 11149ca4041bSJack F Vogel IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 11159ca4041bSJack F Vogel firmware_version); 11169ca4041bSJack F Vogel 11179ca4041bSJack F Vogel return status; 11189ca4041bSJack F Vogel } 11199ca4041bSJack F Vogel 11200ac6dfecSJack F Vogel /** 11212969bf0eSJack F Vogel * ixgbe_get_phy_firmware_version_generic - Gets the PHY Firmware Version 11220ac6dfecSJack F Vogel * @hw: pointer to hardware structure 11230ac6dfecSJack F Vogel * @firmware_version: pointer to the PHY Firmware Version 11240ac6dfecSJack F Vogel **/ 11252969bf0eSJack F Vogel s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw, 11260ac6dfecSJack F Vogel u16 *firmware_version) 11270ac6dfecSJack F Vogel { 1128758cc3dcSJack F Vogel s32 status; 11290ac6dfecSJack F Vogel 11302969bf0eSJack F Vogel DEBUGFUNC("ixgbe_get_phy_firmware_version_generic"); 11312969bf0eSJack F Vogel 11320ac6dfecSJack F Vogel status = hw->phy.ops.read_reg(hw, AQ_FW_REV, 11330ac6dfecSJack F Vogel IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 11340ac6dfecSJack F Vogel firmware_version); 11350ac6dfecSJack F Vogel 11360ac6dfecSJack F Vogel return status; 11370ac6dfecSJack F Vogel } 11380ac6dfecSJack F Vogel 11391b6e0dbaSJack F Vogel /** 11401b6e0dbaSJack F Vogel * ixgbe_reset_phy_nl - Performs a PHY reset 11411b6e0dbaSJack F Vogel * @hw: pointer to hardware structure 11421b6e0dbaSJack F Vogel **/ 11431b6e0dbaSJack F Vogel s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) 11441b6e0dbaSJack F Vogel { 11451b6e0dbaSJack F Vogel u16 phy_offset, control, eword, edata, block_crc; 114679b36ec9SKevin Bowling bool end_data = false; 11471b6e0dbaSJack F Vogel u16 list_offset, data_offset; 11481b6e0dbaSJack F Vogel u16 phy_data = 0; 11491b6e0dbaSJack F Vogel s32 ret_val = IXGBE_SUCCESS; 11501b6e0dbaSJack F Vogel u32 i; 11511b6e0dbaSJack F Vogel 11522969bf0eSJack F Vogel DEBUGFUNC("ixgbe_reset_phy_nl"); 11532969bf0eSJack F Vogel 1154758cc3dcSJack F Vogel /* Blocked by MNG FW so bail */ 1155758cc3dcSJack F Vogel if (ixgbe_check_reset_blocked(hw)) 1156758cc3dcSJack F Vogel goto out; 1157758cc3dcSJack F Vogel 11581b6e0dbaSJack F Vogel hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, 11591b6e0dbaSJack F Vogel IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); 11601b6e0dbaSJack F Vogel 11611b6e0dbaSJack F Vogel /* reset the PHY and poll for completion */ 11621b6e0dbaSJack F Vogel hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, 11631b6e0dbaSJack F Vogel IXGBE_MDIO_PHY_XS_DEV_TYPE, 11641b6e0dbaSJack F Vogel (phy_data | IXGBE_MDIO_PHY_XS_RESET)); 11651b6e0dbaSJack F Vogel 11661b6e0dbaSJack F Vogel for (i = 0; i < 100; i++) { 11671b6e0dbaSJack F Vogel hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, 11681b6e0dbaSJack F Vogel IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); 11691b6e0dbaSJack F Vogel if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0) 11701b6e0dbaSJack F Vogel break; 11711b6e0dbaSJack F Vogel msec_delay(10); 11721b6e0dbaSJack F Vogel } 11731b6e0dbaSJack F Vogel 11741b6e0dbaSJack F Vogel if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) { 11751b6e0dbaSJack F Vogel DEBUGOUT("PHY reset did not complete.\n"); 11761b6e0dbaSJack F Vogel ret_val = IXGBE_ERR_PHY; 11771b6e0dbaSJack F Vogel goto out; 11781b6e0dbaSJack F Vogel } 11791b6e0dbaSJack F Vogel 11801b6e0dbaSJack F Vogel /* Get init offsets */ 11811b6e0dbaSJack F Vogel ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, 11821b6e0dbaSJack F Vogel &data_offset); 11831b6e0dbaSJack F Vogel if (ret_val != IXGBE_SUCCESS) 11841b6e0dbaSJack F Vogel goto out; 11851b6e0dbaSJack F Vogel 11861b6e0dbaSJack F Vogel ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc); 11871b6e0dbaSJack F Vogel data_offset++; 11881b6e0dbaSJack F Vogel while (!end_data) { 11891b6e0dbaSJack F Vogel /* 11901b6e0dbaSJack F Vogel * Read control word from PHY init contents offset 11911b6e0dbaSJack F Vogel */ 11921b6e0dbaSJack F Vogel ret_val = hw->eeprom.ops.read(hw, data_offset, &eword); 1193fd75b91dSJack F Vogel if (ret_val) 1194fd75b91dSJack F Vogel goto err_eeprom; 11951b6e0dbaSJack F Vogel control = (eword & IXGBE_CONTROL_MASK_NL) >> 11961b6e0dbaSJack F Vogel IXGBE_CONTROL_SHIFT_NL; 11971b6e0dbaSJack F Vogel edata = eword & IXGBE_DATA_MASK_NL; 11981b6e0dbaSJack F Vogel switch (control) { 11991b6e0dbaSJack F Vogel case IXGBE_DELAY_NL: 12001b6e0dbaSJack F Vogel data_offset++; 12011b6e0dbaSJack F Vogel DEBUGOUT1("DELAY: %d MS\n", edata); 12021b6e0dbaSJack F Vogel msec_delay(edata); 12031b6e0dbaSJack F Vogel break; 12041b6e0dbaSJack F Vogel case IXGBE_DATA_NL: 12051b6e0dbaSJack F Vogel DEBUGOUT("DATA:\n"); 12061b6e0dbaSJack F Vogel data_offset++; 1207fd75b91dSJack F Vogel ret_val = hw->eeprom.ops.read(hw, data_offset, 12081b6e0dbaSJack F Vogel &phy_offset); 1209fd75b91dSJack F Vogel if (ret_val) 1210fd75b91dSJack F Vogel goto err_eeprom; 1211fd75b91dSJack F Vogel data_offset++; 12121b6e0dbaSJack F Vogel for (i = 0; i < edata; i++) { 1213fd75b91dSJack F Vogel ret_val = hw->eeprom.ops.read(hw, data_offset, 1214fd75b91dSJack F Vogel &eword); 1215fd75b91dSJack F Vogel if (ret_val) 1216fd75b91dSJack F Vogel goto err_eeprom; 12171b6e0dbaSJack F Vogel hw->phy.ops.write_reg(hw, phy_offset, 12181b6e0dbaSJack F Vogel IXGBE_TWINAX_DEV, eword); 12191b6e0dbaSJack F Vogel DEBUGOUT2("Wrote %4.4x to %4.4x\n", eword, 12201b6e0dbaSJack F Vogel phy_offset); 12211b6e0dbaSJack F Vogel data_offset++; 12221b6e0dbaSJack F Vogel phy_offset++; 12231b6e0dbaSJack F Vogel } 12241b6e0dbaSJack F Vogel break; 12251b6e0dbaSJack F Vogel case IXGBE_CONTROL_NL: 12261b6e0dbaSJack F Vogel data_offset++; 12271b6e0dbaSJack F Vogel DEBUGOUT("CONTROL:\n"); 12281b6e0dbaSJack F Vogel if (edata == IXGBE_CONTROL_EOL_NL) { 12291b6e0dbaSJack F Vogel DEBUGOUT("EOL\n"); 123079b36ec9SKevin Bowling end_data = true; 12311b6e0dbaSJack F Vogel } else if (edata == IXGBE_CONTROL_SOL_NL) { 12321b6e0dbaSJack F Vogel DEBUGOUT("SOL\n"); 12331b6e0dbaSJack F Vogel } else { 12341b6e0dbaSJack F Vogel DEBUGOUT("Bad control value\n"); 12351b6e0dbaSJack F Vogel ret_val = IXGBE_ERR_PHY; 12361b6e0dbaSJack F Vogel goto out; 12371b6e0dbaSJack F Vogel } 12381b6e0dbaSJack F Vogel break; 12391b6e0dbaSJack F Vogel default: 12401b6e0dbaSJack F Vogel DEBUGOUT("Bad control type\n"); 12411b6e0dbaSJack F Vogel ret_val = IXGBE_ERR_PHY; 12421b6e0dbaSJack F Vogel goto out; 12431b6e0dbaSJack F Vogel } 12441b6e0dbaSJack F Vogel } 12451b6e0dbaSJack F Vogel 12461b6e0dbaSJack F Vogel out: 12471b6e0dbaSJack F Vogel return ret_val; 1248fd75b91dSJack F Vogel 1249fd75b91dSJack F Vogel err_eeprom: 1250fd75b91dSJack F Vogel ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, 1251fd75b91dSJack F Vogel "eeprom read at offset %d failed", data_offset); 1252fd75b91dSJack F Vogel return IXGBE_ERR_PHY; 12531b6e0dbaSJack F Vogel } 12541b6e0dbaSJack F Vogel 12551b6e0dbaSJack F Vogel /** 125685d0a26eSJack F Vogel * ixgbe_identify_module_generic - Identifies module type 125785d0a26eSJack F Vogel * @hw: pointer to hardware structure 125885d0a26eSJack F Vogel * 125985d0a26eSJack F Vogel * Determines HW type and calls appropriate function. 126085d0a26eSJack F Vogel **/ 126185d0a26eSJack F Vogel s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw) 126285d0a26eSJack F Vogel { 126385d0a26eSJack F Vogel s32 status = IXGBE_ERR_SFP_NOT_PRESENT; 126485d0a26eSJack F Vogel 126585d0a26eSJack F Vogel DEBUGFUNC("ixgbe_identify_module_generic"); 126685d0a26eSJack F Vogel 126785d0a26eSJack F Vogel switch (hw->mac.ops.get_media_type(hw)) { 126885d0a26eSJack F Vogel case ixgbe_media_type_fiber: 126985d0a26eSJack F Vogel status = ixgbe_identify_sfp_module_generic(hw); 127085d0a26eSJack F Vogel break; 127185d0a26eSJack F Vogel 1272758cc3dcSJack F Vogel case ixgbe_media_type_fiber_qsfp: 1273758cc3dcSJack F Vogel status = ixgbe_identify_qsfp_module_generic(hw); 1274758cc3dcSJack F Vogel break; 127585d0a26eSJack F Vogel 127685d0a26eSJack F Vogel default: 127785d0a26eSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_not_present; 127885d0a26eSJack F Vogel status = IXGBE_ERR_SFP_NOT_PRESENT; 127985d0a26eSJack F Vogel break; 128085d0a26eSJack F Vogel } 128185d0a26eSJack F Vogel 128285d0a26eSJack F Vogel return status; 128385d0a26eSJack F Vogel } 128485d0a26eSJack F Vogel 128585d0a26eSJack F Vogel /** 12861b6e0dbaSJack F Vogel * ixgbe_identify_sfp_module_generic - Identifies SFP modules 12871b6e0dbaSJack F Vogel * @hw: pointer to hardware structure 12881b6e0dbaSJack F Vogel * 12891b6e0dbaSJack F Vogel * Searches for and identifies the SFP module and assigns appropriate PHY type. 12901b6e0dbaSJack F Vogel **/ 12911b6e0dbaSJack F Vogel s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) 12921b6e0dbaSJack F Vogel { 12931b6e0dbaSJack F Vogel s32 status = IXGBE_ERR_PHY_ADDR_INVALID; 12941b6e0dbaSJack F Vogel u32 vendor_oui = 0; 12950ac6dfecSJack F Vogel enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; 12961b6e0dbaSJack F Vogel u8 identifier = 0; 12971b6e0dbaSJack F Vogel u8 comp_codes_1g = 0; 12981b6e0dbaSJack F Vogel u8 comp_codes_10g = 0; 12990ac6dfecSJack F Vogel u8 oui_bytes[3] = {0, 0, 0}; 1300d8602bb9SJack F Vogel u8 cable_tech = 0; 1301c0014855SJack F Vogel u8 cable_spec = 0; 13020ac6dfecSJack F Vogel u16 enforce_sfp = 0; 1303a93409fcSKevin Bowling static bool warned_once = false; 13041b6e0dbaSJack F Vogel 13052969bf0eSJack F Vogel DEBUGFUNC("ixgbe_identify_sfp_module_generic"); 13062969bf0eSJack F Vogel 1307d8602bb9SJack F Vogel if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) { 1308d8602bb9SJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_not_present; 1309d8602bb9SJack F Vogel status = IXGBE_ERR_SFP_NOT_PRESENT; 1310d8602bb9SJack F Vogel goto out; 1311d8602bb9SJack F Vogel } 1312d8602bb9SJack F Vogel 1313758cc3dcSJack F Vogel /* LAN ID is needed for I2C access */ 1314758cc3dcSJack F Vogel hw->mac.ops.set_lan_id(hw); 1315758cc3dcSJack F Vogel 13161a4e3449SJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 13171a4e3449SJack F Vogel IXGBE_SFF_IDENTIFIER, 13181b6e0dbaSJack F Vogel &identifier); 13191b6e0dbaSJack F Vogel 13200ecc2ff0SJack F Vogel if (status != IXGBE_SUCCESS) 13211a4e3449SJack F Vogel goto err_read_i2c_eeprom; 13221b6e0dbaSJack F Vogel 1323d8602bb9SJack F Vogel if (identifier != IXGBE_SFF_IDENTIFIER_SFP) { 1324d8602bb9SJack F Vogel hw->phy.type = ixgbe_phy_sfp_unsupported; 1325d8602bb9SJack F Vogel status = IXGBE_ERR_SFP_NOT_SUPPORTED; 1326d8602bb9SJack F Vogel } else { 13271a4e3449SJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 13281a4e3449SJack F Vogel IXGBE_SFF_1GBE_COMP_CODES, 13291b6e0dbaSJack F Vogel &comp_codes_1g); 13301a4e3449SJack F Vogel 13310ecc2ff0SJack F Vogel if (status != IXGBE_SUCCESS) 13321a4e3449SJack F Vogel goto err_read_i2c_eeprom; 13331a4e3449SJack F Vogel 13341a4e3449SJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 13351a4e3449SJack F Vogel IXGBE_SFF_10GBE_COMP_CODES, 13361b6e0dbaSJack F Vogel &comp_codes_10g); 13371a4e3449SJack F Vogel 13380ecc2ff0SJack F Vogel if (status != IXGBE_SUCCESS) 13391a4e3449SJack F Vogel goto err_read_i2c_eeprom; 13401a4e3449SJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 13411a4e3449SJack F Vogel IXGBE_SFF_CABLE_TECHNOLOGY, 1342d8602bb9SJack F Vogel &cable_tech); 13431b6e0dbaSJack F Vogel 13440ecc2ff0SJack F Vogel if (status != IXGBE_SUCCESS) 13451a4e3449SJack F Vogel goto err_read_i2c_eeprom; 13461a4e3449SJack F Vogel 13471b6e0dbaSJack F Vogel /* ID Module 13481b6e0dbaSJack F Vogel * ========= 13491b6e0dbaSJack F Vogel * 0 SFP_DA_CU 13501b6e0dbaSJack F Vogel * 1 SFP_SR 13511b6e0dbaSJack F Vogel * 2 SFP_LR 13520ac6dfecSJack F Vogel * 3 SFP_DA_CORE0 - 82599-specific 13530ac6dfecSJack F Vogel * 4 SFP_DA_CORE1 - 82599-specific 13540ac6dfecSJack F Vogel * 5 SFP_SR/LR_CORE0 - 82599-specific 13550ac6dfecSJack F Vogel * 6 SFP_SR/LR_CORE1 - 82599-specific 1356c0014855SJack F Vogel * 7 SFP_act_lmt_DA_CORE0 - 82599-specific 1357c0014855SJack F Vogel * 8 SFP_act_lmt_DA_CORE1 - 82599-specific 13581a4e3449SJack F Vogel * 9 SFP_1g_cu_CORE0 - 82599-specific 13591a4e3449SJack F Vogel * 10 SFP_1g_cu_CORE1 - 82599-specific 1360a621e3c8SJack F Vogel * 11 SFP_1g_sx_CORE0 - 82599-specific 1361a621e3c8SJack F Vogel * 12 SFP_1g_sx_CORE1 - 82599-specific 13621b6e0dbaSJack F Vogel */ 13630ac6dfecSJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 1364d8602bb9SJack F Vogel if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) 13651b6e0dbaSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_da_cu; 13661b6e0dbaSJack F Vogel else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) 13671b6e0dbaSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_sr; 13681b6e0dbaSJack F Vogel else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) 13691b6e0dbaSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_lr; 13701b6e0dbaSJack F Vogel else 13711b6e0dbaSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_unknown; 1372758cc3dcSJack F Vogel } else { 1373c0014855SJack F Vogel if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { 13740ac6dfecSJack F Vogel if (hw->bus.lan_id == 0) 13750ac6dfecSJack F Vogel hw->phy.sfp_type = 13760ac6dfecSJack F Vogel ixgbe_sfp_type_da_cu_core0; 13770ac6dfecSJack F Vogel else 13780ac6dfecSJack F Vogel hw->phy.sfp_type = 13790ac6dfecSJack F Vogel ixgbe_sfp_type_da_cu_core1; 1380c0014855SJack F Vogel } else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) { 1381c0014855SJack F Vogel hw->phy.ops.read_i2c_eeprom( 1382c0014855SJack F Vogel hw, IXGBE_SFF_CABLE_SPEC_COMP, 1383c0014855SJack F Vogel &cable_spec); 1384c0014855SJack F Vogel if (cable_spec & 1385c0014855SJack F Vogel IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) { 1386c0014855SJack F Vogel if (hw->bus.lan_id == 0) 1387c0014855SJack F Vogel hw->phy.sfp_type = 1388c0014855SJack F Vogel ixgbe_sfp_type_da_act_lmt_core0; 1389c0014855SJack F Vogel else 1390c0014855SJack F Vogel hw->phy.sfp_type = 1391c0014855SJack F Vogel ixgbe_sfp_type_da_act_lmt_core1; 13921a4e3449SJack F Vogel } else { 1393c0014855SJack F Vogel hw->phy.sfp_type = 1394c0014855SJack F Vogel ixgbe_sfp_type_unknown; 13951a4e3449SJack F Vogel } 1396c0014855SJack F Vogel } else if (comp_codes_10g & 1397c0014855SJack F Vogel (IXGBE_SFF_10GBASESR_CAPABLE | 1398c0014855SJack F Vogel IXGBE_SFF_10GBASELR_CAPABLE)) { 13990ac6dfecSJack F Vogel if (hw->bus.lan_id == 0) 14000ac6dfecSJack F Vogel hw->phy.sfp_type = 14010ac6dfecSJack F Vogel ixgbe_sfp_type_srlr_core0; 14020ac6dfecSJack F Vogel else 14030ac6dfecSJack F Vogel hw->phy.sfp_type = 14040ac6dfecSJack F Vogel ixgbe_sfp_type_srlr_core1; 14051a4e3449SJack F Vogel } else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) { 14061a4e3449SJack F Vogel if (hw->bus.lan_id == 0) 14071a4e3449SJack F Vogel hw->phy.sfp_type = 14081a4e3449SJack F Vogel ixgbe_sfp_type_1g_cu_core0; 14091a4e3449SJack F Vogel else 14101a4e3449SJack F Vogel hw->phy.sfp_type = 14111a4e3449SJack F Vogel ixgbe_sfp_type_1g_cu_core1; 1412a621e3c8SJack F Vogel } else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) { 1413a621e3c8SJack F Vogel if (hw->bus.lan_id == 0) 1414a621e3c8SJack F Vogel hw->phy.sfp_type = 1415a621e3c8SJack F Vogel ixgbe_sfp_type_1g_sx_core0; 1416a621e3c8SJack F Vogel else 1417a621e3c8SJack F Vogel hw->phy.sfp_type = 1418a621e3c8SJack F Vogel ixgbe_sfp_type_1g_sx_core1; 14196f37f232SEric Joyner } else if (comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) { 14206f37f232SEric Joyner if (hw->bus.lan_id == 0) 14216f37f232SEric Joyner hw->phy.sfp_type = 14226f37f232SEric Joyner ixgbe_sfp_type_1g_lx_core0; 14236f37f232SEric Joyner else 14246f37f232SEric Joyner hw->phy.sfp_type = 14256f37f232SEric Joyner ixgbe_sfp_type_1g_lx_core1; 1426c0014855SJack F Vogel } else { 14270ac6dfecSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_unknown; 14280ac6dfecSJack F Vogel } 1429c0014855SJack F Vogel } 14300ac6dfecSJack F Vogel 14310ac6dfecSJack F Vogel if (hw->phy.sfp_type != stored_sfp_type) 143279b36ec9SKevin Bowling hw->phy.sfp_setup_needed = true; 14331b6e0dbaSJack F Vogel 14341b6e0dbaSJack F Vogel /* Determine if the SFP+ PHY is dual speed or not. */ 143579b36ec9SKevin Bowling hw->phy.multispeed_fiber = false; 14360ac6dfecSJack F Vogel if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && 14370ac6dfecSJack F Vogel (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || 14380ac6dfecSJack F Vogel ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && 143948ddd1b9SKevin Bowling (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)) || 1440*e38f9257SKevin Bowling (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) || 1441*e38f9257SKevin Bowling (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)) 144279b36ec9SKevin Bowling hw->phy.multispeed_fiber = true; 14432969bf0eSJack F Vogel 14441b6e0dbaSJack F Vogel /* Determine PHY vendor */ 14450ac6dfecSJack F Vogel if (hw->phy.type != ixgbe_phy_nl) { 14461b6e0dbaSJack F Vogel hw->phy.id = identifier; 14471a4e3449SJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 14481b6e0dbaSJack F Vogel IXGBE_SFF_VENDOR_OUI_BYTE0, 14491b6e0dbaSJack F Vogel &oui_bytes[0]); 14501a4e3449SJack F Vogel 14510ecc2ff0SJack F Vogel if (status != IXGBE_SUCCESS) 14521a4e3449SJack F Vogel goto err_read_i2c_eeprom; 14531a4e3449SJack F Vogel 14541a4e3449SJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 14551b6e0dbaSJack F Vogel IXGBE_SFF_VENDOR_OUI_BYTE1, 14561b6e0dbaSJack F Vogel &oui_bytes[1]); 14571a4e3449SJack F Vogel 14580ecc2ff0SJack F Vogel if (status != IXGBE_SUCCESS) 14591a4e3449SJack F Vogel goto err_read_i2c_eeprom; 14601a4e3449SJack F Vogel 14611a4e3449SJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 14621b6e0dbaSJack F Vogel IXGBE_SFF_VENDOR_OUI_BYTE2, 14631b6e0dbaSJack F Vogel &oui_bytes[2]); 14641b6e0dbaSJack F Vogel 14650ecc2ff0SJack F Vogel if (status != IXGBE_SUCCESS) 14661a4e3449SJack F Vogel goto err_read_i2c_eeprom; 14671a4e3449SJack F Vogel 14681b6e0dbaSJack F Vogel vendor_oui = 14691b6e0dbaSJack F Vogel ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | 14701b6e0dbaSJack F Vogel (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | 14711b6e0dbaSJack F Vogel (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); 14721b6e0dbaSJack F Vogel 14731b6e0dbaSJack F Vogel switch (vendor_oui) { 14741b6e0dbaSJack F Vogel case IXGBE_SFF_VENDOR_OUI_TYCO: 1475d8602bb9SJack F Vogel if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) 1476c0014855SJack F Vogel hw->phy.type = 1477c0014855SJack F Vogel ixgbe_phy_sfp_passive_tyco; 14781b6e0dbaSJack F Vogel break; 14791b6e0dbaSJack F Vogel case IXGBE_SFF_VENDOR_OUI_FTL: 1480c0014855SJack F Vogel if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) 1481c0014855SJack F Vogel hw->phy.type = ixgbe_phy_sfp_ftl_active; 1482c0014855SJack F Vogel else 14831b6e0dbaSJack F Vogel hw->phy.type = ixgbe_phy_sfp_ftl; 14841b6e0dbaSJack F Vogel break; 14851b6e0dbaSJack F Vogel case IXGBE_SFF_VENDOR_OUI_AVAGO: 14861b6e0dbaSJack F Vogel hw->phy.type = ixgbe_phy_sfp_avago; 14871b6e0dbaSJack F Vogel break; 14880ac6dfecSJack F Vogel case IXGBE_SFF_VENDOR_OUI_INTEL: 14890ac6dfecSJack F Vogel hw->phy.type = ixgbe_phy_sfp_intel; 14900ac6dfecSJack F Vogel break; 14911b6e0dbaSJack F Vogel default: 1492e06918b9SKevin Bowling if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) 1493e06918b9SKevin Bowling hw->phy.type = ixgbe_phy_sfp_passive_unknown; 1494e06918b9SKevin Bowling else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) 1495e06918b9SKevin Bowling hw->phy.type = ixgbe_phy_sfp_active_unknown; 1496e06918b9SKevin Bowling else 14971b6e0dbaSJack F Vogel hw->phy.type = ixgbe_phy_sfp_unknown; 14981b6e0dbaSJack F Vogel break; 14991b6e0dbaSJack F Vogel } 15001b6e0dbaSJack F Vogel } 15010ac6dfecSJack F Vogel 1502c0014855SJack F Vogel /* Allow any DA cable vendor */ 1503c0014855SJack F Vogel if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE | 1504c0014855SJack F Vogel IXGBE_SFF_DA_ACTIVE_CABLE)) { 1505d8602bb9SJack F Vogel status = IXGBE_SUCCESS; 1506d8602bb9SJack F Vogel goto out; 1507d8602bb9SJack F Vogel } 1508d8602bb9SJack F Vogel 15091a4e3449SJack F Vogel /* Verify supported 1G SFP modules */ 15101a4e3449SJack F Vogel if (comp_codes_10g == 0 && 15111a4e3449SJack F Vogel !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || 1512a621e3c8SJack F Vogel hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || 15136f37f232SEric Joyner hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || 15146f37f232SEric Joyner hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || 1515a621e3c8SJack F Vogel hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || 1516a621e3c8SJack F Vogel hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { 15170ac6dfecSJack F Vogel hw->phy.type = ixgbe_phy_sfp_unsupported; 15180ac6dfecSJack F Vogel status = IXGBE_ERR_SFP_NOT_SUPPORTED; 15190ac6dfecSJack F Vogel goto out; 15200ac6dfecSJack F Vogel } 1521d8602bb9SJack F Vogel 1522d8602bb9SJack F Vogel /* Anything else 82598-based is supported */ 1523d8602bb9SJack F Vogel if (hw->mac.type == ixgbe_mac_82598EB) { 15241b6e0dbaSJack F Vogel status = IXGBE_SUCCESS; 15250ac6dfecSJack F Vogel goto out; 15260ac6dfecSJack F Vogel } 15270ac6dfecSJack F Vogel 15280ac6dfecSJack F Vogel ixgbe_get_device_caps(hw, &enforce_sfp); 15291a4e3449SJack F Vogel if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) && 1530fd75b91dSJack F Vogel !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || 1531fd75b91dSJack F Vogel hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || 15326f37f232SEric Joyner hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || 15336f37f232SEric Joyner hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || 1534fd75b91dSJack F Vogel hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || 1535fd75b91dSJack F Vogel hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { 15360ac6dfecSJack F Vogel /* Make sure we're a supported PHY type */ 15370ac6dfecSJack F Vogel if (hw->phy.type == ixgbe_phy_sfp_intel) { 15380ac6dfecSJack F Vogel status = IXGBE_SUCCESS; 1539cdc12967SDag-Erling Smørgrav } else { 154079b36ec9SKevin Bowling if (hw->allow_unsupported_sfp == true) { 1541a93409fcSKevin Bowling if (!warned_once) 15423f66b96dSKevin Bowling EWARN(hw, 15433f66b96dSKevin Bowling "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. " 15443f66b96dSKevin Bowling "Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. " 15453f66b96dSKevin Bowling "Intel Corporation is not responsible for any harm caused by using untested modules.\n"); 1546a93409fcSKevin Bowling warned_once = true; 1547a621e3c8SJack F Vogel status = IXGBE_SUCCESS; 1548a621e3c8SJack F Vogel } else { 1549a93409fcSKevin Bowling DEBUGOUT 1550a93409fcSKevin Bowling ("SFP+ module not supported\n"); 1551a621e3c8SJack F Vogel hw->phy.type = 1552a621e3c8SJack F Vogel ixgbe_phy_sfp_unsupported; 15530ac6dfecSJack F Vogel status = IXGBE_ERR_SFP_NOT_SUPPORTED; 15540ac6dfecSJack F Vogel } 1555cdc12967SDag-Erling Smørgrav } 15560ac6dfecSJack F Vogel } else { 15570ac6dfecSJack F Vogel status = IXGBE_SUCCESS; 15580ac6dfecSJack F Vogel } 15591b6e0dbaSJack F Vogel } 15601b6e0dbaSJack F Vogel 15611b6e0dbaSJack F Vogel out: 15621b6e0dbaSJack F Vogel return status; 15631a4e3449SJack F Vogel 15641a4e3449SJack F Vogel err_read_i2c_eeprom: 15651a4e3449SJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_not_present; 15661a4e3449SJack F Vogel if (hw->phy.type != ixgbe_phy_nl) { 15671a4e3449SJack F Vogel hw->phy.id = 0; 15681a4e3449SJack F Vogel hw->phy.type = ixgbe_phy_unknown; 15691a4e3449SJack F Vogel } 15701a4e3449SJack F Vogel return IXGBE_ERR_SFP_NOT_PRESENT; 15711b6e0dbaSJack F Vogel } 15721b6e0dbaSJack F Vogel 1573758cc3dcSJack F Vogel /** 1574758cc3dcSJack F Vogel * ixgbe_get_supported_phy_sfp_layer_generic - Returns physical layer type 1575758cc3dcSJack F Vogel * @hw: pointer to hardware structure 1576758cc3dcSJack F Vogel * 1577758cc3dcSJack F Vogel * Determines physical layer capabilities of the current SFP. 1578758cc3dcSJack F Vogel */ 15798eb6488eSEric Joyner u64 ixgbe_get_supported_phy_sfp_layer_generic(struct ixgbe_hw *hw) 1580758cc3dcSJack F Vogel { 15818eb6488eSEric Joyner u64 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; 1582758cc3dcSJack F Vogel u8 comp_codes_10g = 0; 1583758cc3dcSJack F Vogel u8 comp_codes_1g = 0; 1584758cc3dcSJack F Vogel 1585758cc3dcSJack F Vogel DEBUGFUNC("ixgbe_get_supported_phy_sfp_layer_generic"); 1586758cc3dcSJack F Vogel 1587758cc3dcSJack F Vogel hw->phy.ops.identify_sfp(hw); 1588758cc3dcSJack F Vogel if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) 1589758cc3dcSJack F Vogel return physical_layer; 1590758cc3dcSJack F Vogel 1591758cc3dcSJack F Vogel switch (hw->phy.type) { 1592758cc3dcSJack F Vogel case ixgbe_phy_sfp_passive_tyco: 1593758cc3dcSJack F Vogel case ixgbe_phy_sfp_passive_unknown: 1594758cc3dcSJack F Vogel case ixgbe_phy_qsfp_passive_unknown: 1595758cc3dcSJack F Vogel physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; 1596758cc3dcSJack F Vogel break; 1597758cc3dcSJack F Vogel case ixgbe_phy_sfp_ftl_active: 1598758cc3dcSJack F Vogel case ixgbe_phy_sfp_active_unknown: 1599758cc3dcSJack F Vogel case ixgbe_phy_qsfp_active_unknown: 1600758cc3dcSJack F Vogel physical_layer = IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA; 1601758cc3dcSJack F Vogel break; 1602758cc3dcSJack F Vogel case ixgbe_phy_sfp_avago: 1603758cc3dcSJack F Vogel case ixgbe_phy_sfp_ftl: 1604758cc3dcSJack F Vogel case ixgbe_phy_sfp_intel: 1605758cc3dcSJack F Vogel case ixgbe_phy_sfp_unknown: 1606758cc3dcSJack F Vogel hw->phy.ops.read_i2c_eeprom(hw, 1607758cc3dcSJack F Vogel IXGBE_SFF_1GBE_COMP_CODES, &comp_codes_1g); 1608758cc3dcSJack F Vogel hw->phy.ops.read_i2c_eeprom(hw, 1609758cc3dcSJack F Vogel IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g); 1610758cc3dcSJack F Vogel if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) 1611758cc3dcSJack F Vogel physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; 1612758cc3dcSJack F Vogel else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) 1613758cc3dcSJack F Vogel physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; 1614758cc3dcSJack F Vogel else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) 1615758cc3dcSJack F Vogel physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T; 1616758cc3dcSJack F Vogel else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) 1617758cc3dcSJack F Vogel physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_SX; 1618758cc3dcSJack F Vogel break; 1619758cc3dcSJack F Vogel case ixgbe_phy_qsfp_intel: 1620758cc3dcSJack F Vogel case ixgbe_phy_qsfp_unknown: 1621758cc3dcSJack F Vogel hw->phy.ops.read_i2c_eeprom(hw, 1622758cc3dcSJack F Vogel IXGBE_SFF_QSFP_10GBE_COMP, &comp_codes_10g); 1623758cc3dcSJack F Vogel if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) 1624758cc3dcSJack F Vogel physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; 1625758cc3dcSJack F Vogel else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) 1626758cc3dcSJack F Vogel physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; 1627758cc3dcSJack F Vogel break; 1628758cc3dcSJack F Vogel default: 1629758cc3dcSJack F Vogel break; 1630758cc3dcSJack F Vogel } 1631758cc3dcSJack F Vogel 1632758cc3dcSJack F Vogel return physical_layer; 1633758cc3dcSJack F Vogel } 1634758cc3dcSJack F Vogel 1635758cc3dcSJack F Vogel /** 1636758cc3dcSJack F Vogel * ixgbe_identify_qsfp_module_generic - Identifies QSFP modules 1637758cc3dcSJack F Vogel * @hw: pointer to hardware structure 1638758cc3dcSJack F Vogel * 1639758cc3dcSJack F Vogel * Searches for and identifies the QSFP module and assigns appropriate PHY type 1640758cc3dcSJack F Vogel **/ 1641758cc3dcSJack F Vogel s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) 1642758cc3dcSJack F Vogel { 1643758cc3dcSJack F Vogel s32 status = IXGBE_ERR_PHY_ADDR_INVALID; 1644758cc3dcSJack F Vogel u32 vendor_oui = 0; 1645758cc3dcSJack F Vogel enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; 1646758cc3dcSJack F Vogel u8 identifier = 0; 1647758cc3dcSJack F Vogel u8 comp_codes_1g = 0; 1648758cc3dcSJack F Vogel u8 comp_codes_10g = 0; 1649758cc3dcSJack F Vogel u8 oui_bytes[3] = {0, 0, 0}; 1650758cc3dcSJack F Vogel u16 enforce_sfp = 0; 1651758cc3dcSJack F Vogel u8 connector = 0; 1652758cc3dcSJack F Vogel u8 cable_length = 0; 1653758cc3dcSJack F Vogel u8 device_tech = 0; 165479b36ec9SKevin Bowling bool active_cable = false; 1655a93409fcSKevin Bowling static bool warned_once = false; 1656758cc3dcSJack F Vogel 1657758cc3dcSJack F Vogel DEBUGFUNC("ixgbe_identify_qsfp_module_generic"); 1658758cc3dcSJack F Vogel 1659758cc3dcSJack F Vogel if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) { 1660758cc3dcSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_not_present; 1661758cc3dcSJack F Vogel status = IXGBE_ERR_SFP_NOT_PRESENT; 1662758cc3dcSJack F Vogel goto out; 1663758cc3dcSJack F Vogel } 1664758cc3dcSJack F Vogel 16656f37f232SEric Joyner /* LAN ID is needed for I2C access */ 16666f37f232SEric Joyner hw->mac.ops.set_lan_id(hw); 16676f37f232SEric Joyner 1668758cc3dcSJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, 1669758cc3dcSJack F Vogel &identifier); 1670758cc3dcSJack F Vogel 1671758cc3dcSJack F Vogel if (status != IXGBE_SUCCESS) 1672758cc3dcSJack F Vogel goto err_read_i2c_eeprom; 1673758cc3dcSJack F Vogel 1674758cc3dcSJack F Vogel if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) { 1675758cc3dcSJack F Vogel hw->phy.type = ixgbe_phy_sfp_unsupported; 1676758cc3dcSJack F Vogel status = IXGBE_ERR_SFP_NOT_SUPPORTED; 1677758cc3dcSJack F Vogel goto out; 1678758cc3dcSJack F Vogel } 1679758cc3dcSJack F Vogel 1680758cc3dcSJack F Vogel hw->phy.id = identifier; 1681758cc3dcSJack F Vogel 1682758cc3dcSJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP, 1683758cc3dcSJack F Vogel &comp_codes_10g); 1684758cc3dcSJack F Vogel 1685758cc3dcSJack F Vogel if (status != IXGBE_SUCCESS) 1686758cc3dcSJack F Vogel goto err_read_i2c_eeprom; 1687758cc3dcSJack F Vogel 1688758cc3dcSJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_1GBE_COMP, 1689758cc3dcSJack F Vogel &comp_codes_1g); 1690758cc3dcSJack F Vogel 1691758cc3dcSJack F Vogel if (status != IXGBE_SUCCESS) 1692758cc3dcSJack F Vogel goto err_read_i2c_eeprom; 1693758cc3dcSJack F Vogel 1694758cc3dcSJack F Vogel if (comp_codes_10g & IXGBE_SFF_QSFP_DA_PASSIVE_CABLE) { 1695758cc3dcSJack F Vogel hw->phy.type = ixgbe_phy_qsfp_passive_unknown; 1696758cc3dcSJack F Vogel if (hw->bus.lan_id == 0) 1697758cc3dcSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0; 1698758cc3dcSJack F Vogel else 1699758cc3dcSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core1; 1700758cc3dcSJack F Vogel } else if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE | 1701758cc3dcSJack F Vogel IXGBE_SFF_10GBASELR_CAPABLE)) { 1702758cc3dcSJack F Vogel if (hw->bus.lan_id == 0) 1703758cc3dcSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_srlr_core0; 1704758cc3dcSJack F Vogel else 1705758cc3dcSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_srlr_core1; 1706758cc3dcSJack F Vogel } else { 1707758cc3dcSJack F Vogel if (comp_codes_10g & IXGBE_SFF_QSFP_DA_ACTIVE_CABLE) 170879b36ec9SKevin Bowling active_cable = true; 1709758cc3dcSJack F Vogel 1710758cc3dcSJack F Vogel if (!active_cable) { 1711758cc3dcSJack F Vogel /* check for active DA cables that pre-date 1712758cc3dcSJack F Vogel * SFF-8436 v3.6 */ 1713758cc3dcSJack F Vogel hw->phy.ops.read_i2c_eeprom(hw, 1714758cc3dcSJack F Vogel IXGBE_SFF_QSFP_CONNECTOR, 1715758cc3dcSJack F Vogel &connector); 1716758cc3dcSJack F Vogel 1717758cc3dcSJack F Vogel hw->phy.ops.read_i2c_eeprom(hw, 1718758cc3dcSJack F Vogel IXGBE_SFF_QSFP_CABLE_LENGTH, 1719758cc3dcSJack F Vogel &cable_length); 1720758cc3dcSJack F Vogel 1721758cc3dcSJack F Vogel hw->phy.ops.read_i2c_eeprom(hw, 1722758cc3dcSJack F Vogel IXGBE_SFF_QSFP_DEVICE_TECH, 1723758cc3dcSJack F Vogel &device_tech); 1724758cc3dcSJack F Vogel 1725758cc3dcSJack F Vogel if ((connector == 1726758cc3dcSJack F Vogel IXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE) && 1727758cc3dcSJack F Vogel (cable_length > 0) && 1728758cc3dcSJack F Vogel ((device_tech >> 4) == 1729758cc3dcSJack F Vogel IXGBE_SFF_QSFP_TRANSMITER_850NM_VCSEL)) 173079b36ec9SKevin Bowling active_cable = true; 1731758cc3dcSJack F Vogel } 1732758cc3dcSJack F Vogel 1733758cc3dcSJack F Vogel if (active_cable) { 1734758cc3dcSJack F Vogel hw->phy.type = ixgbe_phy_qsfp_active_unknown; 1735758cc3dcSJack F Vogel if (hw->bus.lan_id == 0) 1736758cc3dcSJack F Vogel hw->phy.sfp_type = 1737758cc3dcSJack F Vogel ixgbe_sfp_type_da_act_lmt_core0; 1738758cc3dcSJack F Vogel else 1739758cc3dcSJack F Vogel hw->phy.sfp_type = 1740758cc3dcSJack F Vogel ixgbe_sfp_type_da_act_lmt_core1; 1741758cc3dcSJack F Vogel } else { 1742758cc3dcSJack F Vogel /* unsupported module type */ 1743758cc3dcSJack F Vogel hw->phy.type = ixgbe_phy_sfp_unsupported; 1744758cc3dcSJack F Vogel status = IXGBE_ERR_SFP_NOT_SUPPORTED; 1745758cc3dcSJack F Vogel goto out; 1746758cc3dcSJack F Vogel } 1747758cc3dcSJack F Vogel } 1748758cc3dcSJack F Vogel 1749758cc3dcSJack F Vogel if (hw->phy.sfp_type != stored_sfp_type) 175079b36ec9SKevin Bowling hw->phy.sfp_setup_needed = true; 1751758cc3dcSJack F Vogel 1752758cc3dcSJack F Vogel /* Determine if the QSFP+ PHY is dual speed or not. */ 175379b36ec9SKevin Bowling hw->phy.multispeed_fiber = false; 1754758cc3dcSJack F Vogel if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && 1755758cc3dcSJack F Vogel (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || 1756758cc3dcSJack F Vogel ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && 1757758cc3dcSJack F Vogel (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) 175879b36ec9SKevin Bowling hw->phy.multispeed_fiber = true; 1759758cc3dcSJack F Vogel 1760758cc3dcSJack F Vogel /* Determine PHY vendor for optical modules */ 1761758cc3dcSJack F Vogel if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE | 1762758cc3dcSJack F Vogel IXGBE_SFF_10GBASELR_CAPABLE)) { 1763758cc3dcSJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 1764758cc3dcSJack F Vogel IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0, 1765758cc3dcSJack F Vogel &oui_bytes[0]); 1766758cc3dcSJack F Vogel 1767758cc3dcSJack F Vogel if (status != IXGBE_SUCCESS) 1768758cc3dcSJack F Vogel goto err_read_i2c_eeprom; 1769758cc3dcSJack F Vogel 1770758cc3dcSJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 1771758cc3dcSJack F Vogel IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1, 1772758cc3dcSJack F Vogel &oui_bytes[1]); 1773758cc3dcSJack F Vogel 1774758cc3dcSJack F Vogel if (status != IXGBE_SUCCESS) 1775758cc3dcSJack F Vogel goto err_read_i2c_eeprom; 1776758cc3dcSJack F Vogel 1777758cc3dcSJack F Vogel status = hw->phy.ops.read_i2c_eeprom(hw, 1778758cc3dcSJack F Vogel IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2, 1779758cc3dcSJack F Vogel &oui_bytes[2]); 1780758cc3dcSJack F Vogel 1781758cc3dcSJack F Vogel if (status != IXGBE_SUCCESS) 1782758cc3dcSJack F Vogel goto err_read_i2c_eeprom; 1783758cc3dcSJack F Vogel 1784758cc3dcSJack F Vogel vendor_oui = 1785758cc3dcSJack F Vogel ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | 1786758cc3dcSJack F Vogel (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | 1787758cc3dcSJack F Vogel (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); 1788758cc3dcSJack F Vogel 1789758cc3dcSJack F Vogel if (vendor_oui == IXGBE_SFF_VENDOR_OUI_INTEL) 1790758cc3dcSJack F Vogel hw->phy.type = ixgbe_phy_qsfp_intel; 1791758cc3dcSJack F Vogel else 1792758cc3dcSJack F Vogel hw->phy.type = ixgbe_phy_qsfp_unknown; 1793758cc3dcSJack F Vogel 1794758cc3dcSJack F Vogel ixgbe_get_device_caps(hw, &enforce_sfp); 1795758cc3dcSJack F Vogel if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { 1796758cc3dcSJack F Vogel /* Make sure we're a supported PHY type */ 1797758cc3dcSJack F Vogel if (hw->phy.type == ixgbe_phy_qsfp_intel) { 1798758cc3dcSJack F Vogel status = IXGBE_SUCCESS; 1799758cc3dcSJack F Vogel } else { 180079b36ec9SKevin Bowling if (hw->allow_unsupported_sfp == true) { 1801a93409fcSKevin Bowling if (!warned_once) 18023f66b96dSKevin Bowling EWARN(hw, 18033f66b96dSKevin Bowling "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. " 18043f66b96dSKevin Bowling "Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. " 18053f66b96dSKevin Bowling "Intel Corporation is not responsible for any harm caused by using untested modules.\n"); 1806a93409fcSKevin Bowling warned_once = true; 1807758cc3dcSJack F Vogel status = IXGBE_SUCCESS; 1808758cc3dcSJack F Vogel } else { 1809758cc3dcSJack F Vogel DEBUGOUT("QSFP module not supported\n"); 1810758cc3dcSJack F Vogel hw->phy.type = 1811758cc3dcSJack F Vogel ixgbe_phy_sfp_unsupported; 1812758cc3dcSJack F Vogel status = IXGBE_ERR_SFP_NOT_SUPPORTED; 1813758cc3dcSJack F Vogel } 1814758cc3dcSJack F Vogel } 1815758cc3dcSJack F Vogel } else { 1816758cc3dcSJack F Vogel status = IXGBE_SUCCESS; 1817758cc3dcSJack F Vogel } 1818758cc3dcSJack F Vogel } 1819758cc3dcSJack F Vogel 1820758cc3dcSJack F Vogel out: 1821758cc3dcSJack F Vogel return status; 1822758cc3dcSJack F Vogel 1823758cc3dcSJack F Vogel err_read_i2c_eeprom: 1824758cc3dcSJack F Vogel hw->phy.sfp_type = ixgbe_sfp_type_not_present; 1825758cc3dcSJack F Vogel hw->phy.id = 0; 1826758cc3dcSJack F Vogel hw->phy.type = ixgbe_phy_unknown; 1827758cc3dcSJack F Vogel 1828758cc3dcSJack F Vogel return IXGBE_ERR_SFP_NOT_PRESENT; 1829758cc3dcSJack F Vogel } 183085d0a26eSJack F Vogel 18311b6e0dbaSJack F Vogel /** 18321b6e0dbaSJack F Vogel * ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence 18331b6e0dbaSJack F Vogel * @hw: pointer to hardware structure 18341b6e0dbaSJack F Vogel * @list_offset: offset to the SFP ID list 18351b6e0dbaSJack F Vogel * @data_offset: offset to the SFP data block 18361b6e0dbaSJack F Vogel * 18371b6e0dbaSJack F Vogel * Checks the MAC's EEPROM to see if it supports a given SFP+ module type, if 18381b6e0dbaSJack F Vogel * so it returns the offsets to the phy init sequence block. 18391b6e0dbaSJack F Vogel **/ 18401b6e0dbaSJack F Vogel s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, 18411b6e0dbaSJack F Vogel u16 *list_offset, 18421b6e0dbaSJack F Vogel u16 *data_offset) 18431b6e0dbaSJack F Vogel { 18441b6e0dbaSJack F Vogel u16 sfp_id; 1845c0014855SJack F Vogel u16 sfp_type = hw->phy.sfp_type; 18461b6e0dbaSJack F Vogel 18472969bf0eSJack F Vogel DEBUGFUNC("ixgbe_get_sfp_init_sequence_offsets"); 18482969bf0eSJack F Vogel 18491b6e0dbaSJack F Vogel if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) 18501b6e0dbaSJack F Vogel return IXGBE_ERR_SFP_NOT_SUPPORTED; 18511b6e0dbaSJack F Vogel 18521b6e0dbaSJack F Vogel if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) 18531b6e0dbaSJack F Vogel return IXGBE_ERR_SFP_NOT_PRESENT; 18541b6e0dbaSJack F Vogel 18551b6e0dbaSJack F Vogel if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) && 18561b6e0dbaSJack F Vogel (hw->phy.sfp_type == ixgbe_sfp_type_da_cu)) 18571b6e0dbaSJack F Vogel return IXGBE_ERR_SFP_NOT_SUPPORTED; 18581b6e0dbaSJack F Vogel 18591a4e3449SJack F Vogel /* 18601a4e3449SJack F Vogel * Limiting active cables and 1G Phys must be initialized as 18611a4e3449SJack F Vogel * SR modules 18621a4e3449SJack F Vogel */ 18631a4e3449SJack F Vogel if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 || 18646f37f232SEric Joyner sfp_type == ixgbe_sfp_type_1g_lx_core0 || 1865a621e3c8SJack F Vogel sfp_type == ixgbe_sfp_type_1g_cu_core0 || 1866a621e3c8SJack F Vogel sfp_type == ixgbe_sfp_type_1g_sx_core0) 1867c0014855SJack F Vogel sfp_type = ixgbe_sfp_type_srlr_core0; 18681a4e3449SJack F Vogel else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 || 18696f37f232SEric Joyner sfp_type == ixgbe_sfp_type_1g_lx_core1 || 1870a621e3c8SJack F Vogel sfp_type == ixgbe_sfp_type_1g_cu_core1 || 1871a621e3c8SJack F Vogel sfp_type == ixgbe_sfp_type_1g_sx_core1) 1872c0014855SJack F Vogel sfp_type = ixgbe_sfp_type_srlr_core1; 1873c0014855SJack F Vogel 18741b6e0dbaSJack F Vogel /* Read offset to PHY init contents */ 1875fd75b91dSJack F Vogel if (hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset)) { 1876fd75b91dSJack F Vogel ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, 1877fd75b91dSJack F Vogel "eeprom read at offset %d failed", 1878fd75b91dSJack F Vogel IXGBE_PHY_INIT_OFFSET_NL); 1879fd75b91dSJack F Vogel return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT; 1880fd75b91dSJack F Vogel } 18811b6e0dbaSJack F Vogel 18821b6e0dbaSJack F Vogel if ((!*list_offset) || (*list_offset == 0xFFFF)) 18830ac6dfecSJack F Vogel return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT; 18841b6e0dbaSJack F Vogel 18851b6e0dbaSJack F Vogel /* Shift offset to first ID word */ 18861b6e0dbaSJack F Vogel (*list_offset)++; 18871b6e0dbaSJack F Vogel 18881b6e0dbaSJack F Vogel /* 18891b6e0dbaSJack F Vogel * Find the matching SFP ID in the EEPROM 18901b6e0dbaSJack F Vogel * and program the init sequence 18911b6e0dbaSJack F Vogel */ 1892fd75b91dSJack F Vogel if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) 1893fd75b91dSJack F Vogel goto err_phy; 18941b6e0dbaSJack F Vogel 18951b6e0dbaSJack F Vogel while (sfp_id != IXGBE_PHY_INIT_END_NL) { 1896c0014855SJack F Vogel if (sfp_id == sfp_type) { 18971b6e0dbaSJack F Vogel (*list_offset)++; 1898fd75b91dSJack F Vogel if (hw->eeprom.ops.read(hw, *list_offset, data_offset)) 1899fd75b91dSJack F Vogel goto err_phy; 19001b6e0dbaSJack F Vogel if ((!*data_offset) || (*data_offset == 0xFFFF)) { 19011b6e0dbaSJack F Vogel DEBUGOUT("SFP+ module not supported\n"); 19021b6e0dbaSJack F Vogel return IXGBE_ERR_SFP_NOT_SUPPORTED; 19031b6e0dbaSJack F Vogel } else { 19041b6e0dbaSJack F Vogel break; 19051b6e0dbaSJack F Vogel } 19061b6e0dbaSJack F Vogel } else { 19071b6e0dbaSJack F Vogel (*list_offset) += 2; 19081b6e0dbaSJack F Vogel if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) 1909fd75b91dSJack F Vogel goto err_phy; 19101b6e0dbaSJack F Vogel } 19111b6e0dbaSJack F Vogel } 19121b6e0dbaSJack F Vogel 19131b6e0dbaSJack F Vogel if (sfp_id == IXGBE_PHY_INIT_END_NL) { 19141b6e0dbaSJack F Vogel DEBUGOUT("No matching SFP+ module found\n"); 19151b6e0dbaSJack F Vogel return IXGBE_ERR_SFP_NOT_SUPPORTED; 19161b6e0dbaSJack F Vogel } 19171b6e0dbaSJack F Vogel 19181b6e0dbaSJack F Vogel return IXGBE_SUCCESS; 1919fd75b91dSJack F Vogel 1920fd75b91dSJack F Vogel err_phy: 1921fd75b91dSJack F Vogel ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, 1922fd75b91dSJack F Vogel "eeprom read at offset %d failed", *list_offset); 1923fd75b91dSJack F Vogel return IXGBE_ERR_PHY; 19241b6e0dbaSJack F Vogel } 19251b6e0dbaSJack F Vogel 19260ac6dfecSJack F Vogel /** 19270ac6dfecSJack F Vogel * ixgbe_read_i2c_eeprom_generic - Reads 8 bit EEPROM word over I2C interface 19280ac6dfecSJack F Vogel * @hw: pointer to hardware structure 19290ac6dfecSJack F Vogel * @byte_offset: EEPROM byte offset to read 19300ac6dfecSJack F Vogel * @eeprom_data: value read 19310ac6dfecSJack F Vogel * 19320ac6dfecSJack F Vogel * Performs byte read operation to SFP module's EEPROM over I2C interface. 19330ac6dfecSJack F Vogel **/ 19340ac6dfecSJack F Vogel s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, 19350ac6dfecSJack F Vogel u8 *eeprom_data) 19360ac6dfecSJack F Vogel { 19370ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_read_i2c_eeprom_generic"); 19380ac6dfecSJack F Vogel 19390ac6dfecSJack F Vogel return hw->phy.ops.read_i2c_byte(hw, byte_offset, 19400ac6dfecSJack F Vogel IXGBE_I2C_EEPROM_DEV_ADDR, 19410ac6dfecSJack F Vogel eeprom_data); 19420ac6dfecSJack F Vogel } 19430ac6dfecSJack F Vogel 19440ac6dfecSJack F Vogel /** 19450ecc2ff0SJack F Vogel * ixgbe_read_i2c_sff8472_generic - Reads 8 bit word over I2C interface 19460ecc2ff0SJack F Vogel * @hw: pointer to hardware structure 19470ecc2ff0SJack F Vogel * @byte_offset: byte offset at address 0xA2 19487d48aa4cSEric Joyner * @sff8472_data: value read 19490ecc2ff0SJack F Vogel * 19500ecc2ff0SJack F Vogel * Performs byte read operation to SFP module's SFF-8472 data over I2C 19510ecc2ff0SJack F Vogel **/ 19520ecc2ff0SJack F Vogel static s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, 19530ecc2ff0SJack F Vogel u8 *sff8472_data) 19540ecc2ff0SJack F Vogel { 19550ecc2ff0SJack F Vogel return hw->phy.ops.read_i2c_byte(hw, byte_offset, 19560ecc2ff0SJack F Vogel IXGBE_I2C_EEPROM_DEV_ADDR2, 19570ecc2ff0SJack F Vogel sff8472_data); 19580ecc2ff0SJack F Vogel } 19590ecc2ff0SJack F Vogel 19600ecc2ff0SJack F Vogel /** 19610ac6dfecSJack F Vogel * ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface 19620ac6dfecSJack F Vogel * @hw: pointer to hardware structure 19630ac6dfecSJack F Vogel * @byte_offset: EEPROM byte offset to write 19640ac6dfecSJack F Vogel * @eeprom_data: value to write 19650ac6dfecSJack F Vogel * 19660ac6dfecSJack F Vogel * Performs byte write operation to SFP module's EEPROM over I2C interface. 19670ac6dfecSJack F Vogel **/ 19680ac6dfecSJack F Vogel s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, 19690ac6dfecSJack F Vogel u8 eeprom_data) 19700ac6dfecSJack F Vogel { 19710ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_write_i2c_eeprom_generic"); 19720ac6dfecSJack F Vogel 19730ac6dfecSJack F Vogel return hw->phy.ops.write_i2c_byte(hw, byte_offset, 19740ac6dfecSJack F Vogel IXGBE_I2C_EEPROM_DEV_ADDR, 19750ac6dfecSJack F Vogel eeprom_data); 19760ac6dfecSJack F Vogel } 19770ac6dfecSJack F Vogel 19780ac6dfecSJack F Vogel /** 197979b36ec9SKevin Bowling * ixgbe_is_sfp_probe - Returns true if SFP is being detected 1980758cc3dcSJack F Vogel * @hw: pointer to hardware structure 1981758cc3dcSJack F Vogel * @offset: eeprom offset to be read 1982758cc3dcSJack F Vogel * @addr: I2C address to be read 1983758cc3dcSJack F Vogel */ 1984758cc3dcSJack F Vogel static bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr) 1985758cc3dcSJack F Vogel { 1986758cc3dcSJack F Vogel if (addr == IXGBE_I2C_EEPROM_DEV_ADDR && 1987758cc3dcSJack F Vogel offset == IXGBE_SFF_IDENTIFIER && 1988758cc3dcSJack F Vogel hw->phy.sfp_type == ixgbe_sfp_type_not_present) 198979b36ec9SKevin Bowling return true; 199079b36ec9SKevin Bowling return false; 1991758cc3dcSJack F Vogel } 1992758cc3dcSJack F Vogel 1993758cc3dcSJack F Vogel /** 19946f37f232SEric Joyner * ixgbe_read_i2c_byte_generic_int - Reads 8 bit word over I2C 19950ac6dfecSJack F Vogel * @hw: pointer to hardware structure 19960ac6dfecSJack F Vogel * @byte_offset: byte offset to read 19977d48aa4cSEric Joyner * @dev_addr: address to read from 19980ac6dfecSJack F Vogel * @data: value read 199979b36ec9SKevin Bowling * @lock: true if to take and release semaphore 20000ac6dfecSJack F Vogel * 20010ac6dfecSJack F Vogel * Performs byte read operation to SFP module's EEPROM over I2C interface at 200285d0a26eSJack F Vogel * a specified device address. 20030ac6dfecSJack F Vogel **/ 20046f37f232SEric Joyner static s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, 20056f37f232SEric Joyner u8 dev_addr, u8 *data, bool lock) 20060ac6dfecSJack F Vogel { 2007758cc3dcSJack F Vogel s32 status; 2008d8602bb9SJack F Vogel u32 max_retry = 10; 20090ac6dfecSJack F Vogel u32 retry = 0; 2010758cc3dcSJack F Vogel u32 swfw_mask = hw->phy.phy_semaphore_mask; 20110ac6dfecSJack F Vogel bool nack = 1; 201285d0a26eSJack F Vogel *data = 0; 20130ac6dfecSJack F Vogel 20140ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_read_i2c_byte_generic"); 20150ac6dfecSJack F Vogel 20166f37f232SEric Joyner if (hw->mac.type >= ixgbe_mac_X550) 20176f37f232SEric Joyner max_retry = 3; 2018758cc3dcSJack F Vogel if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr)) 2019758cc3dcSJack F Vogel max_retry = IXGBE_SFP_DETECT_RETRIES; 20200ac6dfecSJack F Vogel 2021d8602bb9SJack F Vogel do { 20226f37f232SEric Joyner if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) 2023758cc3dcSJack F Vogel return IXGBE_ERR_SWFW_SYNC; 20240ac6dfecSJack F Vogel 20250ac6dfecSJack F Vogel ixgbe_i2c_start(hw); 20260ac6dfecSJack F Vogel 20270ac6dfecSJack F Vogel /* Device Address and write indication */ 20280ac6dfecSJack F Vogel status = ixgbe_clock_out_i2c_byte(hw, dev_addr); 20290ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 20300ac6dfecSJack F Vogel goto fail; 20310ac6dfecSJack F Vogel 20320ac6dfecSJack F Vogel status = ixgbe_get_i2c_ack(hw); 20330ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 20340ac6dfecSJack F Vogel goto fail; 20350ac6dfecSJack F Vogel 20360ac6dfecSJack F Vogel status = ixgbe_clock_out_i2c_byte(hw, byte_offset); 20370ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 20380ac6dfecSJack F Vogel goto fail; 20390ac6dfecSJack F Vogel 20400ac6dfecSJack F Vogel status = ixgbe_get_i2c_ack(hw); 20410ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 20420ac6dfecSJack F Vogel goto fail; 20430ac6dfecSJack F Vogel 20440ac6dfecSJack F Vogel ixgbe_i2c_start(hw); 20450ac6dfecSJack F Vogel 20460ac6dfecSJack F Vogel /* Device Address and read indication */ 20470ac6dfecSJack F Vogel status = ixgbe_clock_out_i2c_byte(hw, (dev_addr | 0x1)); 20480ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 20490ac6dfecSJack F Vogel goto fail; 20500ac6dfecSJack F Vogel 20510ac6dfecSJack F Vogel status = ixgbe_get_i2c_ack(hw); 20520ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 20530ac6dfecSJack F Vogel goto fail; 20540ac6dfecSJack F Vogel 20553a890053SGuinan Sun ixgbe_clock_in_i2c_byte(hw, data); 20560ac6dfecSJack F Vogel 20570ac6dfecSJack F Vogel status = ixgbe_clock_out_i2c_bit(hw, nack); 20580ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 20590ac6dfecSJack F Vogel goto fail; 20600ac6dfecSJack F Vogel 20610ac6dfecSJack F Vogel ixgbe_i2c_stop(hw); 20626f37f232SEric Joyner if (lock) 2063758cc3dcSJack F Vogel hw->mac.ops.release_swfw_sync(hw, swfw_mask); 2064758cc3dcSJack F Vogel return IXGBE_SUCCESS; 20650ac6dfecSJack F Vogel 20660ac6dfecSJack F Vogel fail: 20670ecc2ff0SJack F Vogel ixgbe_i2c_bus_clear(hw); 20686f37f232SEric Joyner if (lock) { 206985d0a26eSJack F Vogel hw->mac.ops.release_swfw_sync(hw, swfw_mask); 2070d8602bb9SJack F Vogel msec_delay(100); 20716f37f232SEric Joyner } 20720ac6dfecSJack F Vogel if (retry < max_retry) 20730ac6dfecSJack F Vogel DEBUGOUT("I2C byte read error - Retrying.\n"); 20740ac6dfecSJack F Vogel else 20750ac6dfecSJack F Vogel DEBUGOUT("I2C byte read error.\n"); 2076dc11ba4eSGuinan Sun retry++; 2077dc11ba4eSGuinan Sun } while (retry <= max_retry); 20780ac6dfecSJack F Vogel 20790ac6dfecSJack F Vogel return status; 20800ac6dfecSJack F Vogel } 20810ac6dfecSJack F Vogel 20820ac6dfecSJack F Vogel /** 20836f37f232SEric Joyner * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C 20846f37f232SEric Joyner * @hw: pointer to hardware structure 20856f37f232SEric Joyner * @byte_offset: byte offset to read 20867d48aa4cSEric Joyner * @dev_addr: address to read from 20876f37f232SEric Joyner * @data: value read 20886f37f232SEric Joyner * 20896f37f232SEric Joyner * Performs byte read operation to SFP module's EEPROM over I2C interface at 20906f37f232SEric Joyner * a specified device address. 20916f37f232SEric Joyner **/ 20926f37f232SEric Joyner s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, 20936f37f232SEric Joyner u8 dev_addr, u8 *data) 20946f37f232SEric Joyner { 20956f37f232SEric Joyner return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr, 209679b36ec9SKevin Bowling data, true); 20976f37f232SEric Joyner } 20986f37f232SEric Joyner 20996f37f232SEric Joyner /** 21006f37f232SEric Joyner * ixgbe_read_i2c_byte_generic_unlocked - Reads 8 bit word over I2C 21016f37f232SEric Joyner * @hw: pointer to hardware structure 21026f37f232SEric Joyner * @byte_offset: byte offset to read 21037d48aa4cSEric Joyner * @dev_addr: address to read from 21046f37f232SEric Joyner * @data: value read 21056f37f232SEric Joyner * 21066f37f232SEric Joyner * Performs byte read operation to SFP module's EEPROM over I2C interface at 21076f37f232SEric Joyner * a specified device address. 21086f37f232SEric Joyner **/ 21096f37f232SEric Joyner s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, 21106f37f232SEric Joyner u8 dev_addr, u8 *data) 21116f37f232SEric Joyner { 21126f37f232SEric Joyner return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr, 211379b36ec9SKevin Bowling data, false); 21146f37f232SEric Joyner } 21156f37f232SEric Joyner 21166f37f232SEric Joyner /** 21176f37f232SEric Joyner * ixgbe_write_i2c_byte_generic_int - Writes 8 bit word over I2C 21180ac6dfecSJack F Vogel * @hw: pointer to hardware structure 21190ac6dfecSJack F Vogel * @byte_offset: byte offset to write 21207d48aa4cSEric Joyner * @dev_addr: address to write to 21210ac6dfecSJack F Vogel * @data: value to write 212279b36ec9SKevin Bowling * @lock: true if to take and release semaphore 21230ac6dfecSJack F Vogel * 21240ac6dfecSJack F Vogel * Performs byte write operation to SFP module's EEPROM over I2C interface at 21250ac6dfecSJack F Vogel * a specified device address. 21260ac6dfecSJack F Vogel **/ 21276f37f232SEric Joyner static s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset, 21286f37f232SEric Joyner u8 dev_addr, u8 data, bool lock) 21290ac6dfecSJack F Vogel { 21306f37f232SEric Joyner s32 status; 21310ac6dfecSJack F Vogel u32 max_retry = 1; 21320ac6dfecSJack F Vogel u32 retry = 0; 2133758cc3dcSJack F Vogel u32 swfw_mask = hw->phy.phy_semaphore_mask; 21340ac6dfecSJack F Vogel 21350ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_write_i2c_byte_generic"); 21360ac6dfecSJack F Vogel 21376f37f232SEric Joyner if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 21386f37f232SEric Joyner IXGBE_SUCCESS) 21396f37f232SEric Joyner return IXGBE_ERR_SWFW_SYNC; 21400ac6dfecSJack F Vogel 21410ac6dfecSJack F Vogel do { 21420ac6dfecSJack F Vogel ixgbe_i2c_start(hw); 21430ac6dfecSJack F Vogel 21440ac6dfecSJack F Vogel status = ixgbe_clock_out_i2c_byte(hw, dev_addr); 21450ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 21460ac6dfecSJack F Vogel goto fail; 21470ac6dfecSJack F Vogel 21480ac6dfecSJack F Vogel status = ixgbe_get_i2c_ack(hw); 21490ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 21500ac6dfecSJack F Vogel goto fail; 21510ac6dfecSJack F Vogel 21520ac6dfecSJack F Vogel status = ixgbe_clock_out_i2c_byte(hw, byte_offset); 21530ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 21540ac6dfecSJack F Vogel goto fail; 21550ac6dfecSJack F Vogel 21560ac6dfecSJack F Vogel status = ixgbe_get_i2c_ack(hw); 21570ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 21580ac6dfecSJack F Vogel goto fail; 21590ac6dfecSJack F Vogel 21600ac6dfecSJack F Vogel status = ixgbe_clock_out_i2c_byte(hw, data); 21610ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 21620ac6dfecSJack F Vogel goto fail; 21630ac6dfecSJack F Vogel 21640ac6dfecSJack F Vogel status = ixgbe_get_i2c_ack(hw); 21650ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 21660ac6dfecSJack F Vogel goto fail; 21670ac6dfecSJack F Vogel 21680ac6dfecSJack F Vogel ixgbe_i2c_stop(hw); 21696f37f232SEric Joyner if (lock) 2170758cc3dcSJack F Vogel hw->mac.ops.release_swfw_sync(hw, swfw_mask); 2171758cc3dcSJack F Vogel return IXGBE_SUCCESS; 21720ac6dfecSJack F Vogel 21730ac6dfecSJack F Vogel fail: 21740ac6dfecSJack F Vogel ixgbe_i2c_bus_clear(hw); 21750ac6dfecSJack F Vogel if (retry < max_retry) 21760ac6dfecSJack F Vogel DEBUGOUT("I2C byte write error - Retrying.\n"); 21770ac6dfecSJack F Vogel else 21780ac6dfecSJack F Vogel DEBUGOUT("I2C byte write error.\n"); 2179dc11ba4eSGuinan Sun retry++; 2180dc11ba4eSGuinan Sun } while (retry <= max_retry); 21810ac6dfecSJack F Vogel 21826f37f232SEric Joyner if (lock) 218385d0a26eSJack F Vogel hw->mac.ops.release_swfw_sync(hw, swfw_mask); 21840ac6dfecSJack F Vogel 21850ac6dfecSJack F Vogel return status; 21860ac6dfecSJack F Vogel } 21870ac6dfecSJack F Vogel 21880ac6dfecSJack F Vogel /** 21896f37f232SEric Joyner * ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C 21906f37f232SEric Joyner * @hw: pointer to hardware structure 21916f37f232SEric Joyner * @byte_offset: byte offset to write 21927d48aa4cSEric Joyner * @dev_addr: address to write to 21936f37f232SEric Joyner * @data: value to write 21946f37f232SEric Joyner * 21956f37f232SEric Joyner * Performs byte write operation to SFP module's EEPROM over I2C interface at 21966f37f232SEric Joyner * a specified device address. 21976f37f232SEric Joyner **/ 21986f37f232SEric Joyner s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, 21996f37f232SEric Joyner u8 dev_addr, u8 data) 22006f37f232SEric Joyner { 22016f37f232SEric Joyner return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr, 220279b36ec9SKevin Bowling data, true); 22036f37f232SEric Joyner } 22046f37f232SEric Joyner 22056f37f232SEric Joyner /** 22066f37f232SEric Joyner * ixgbe_write_i2c_byte_generic_unlocked - Writes 8 bit word over I2C 22076f37f232SEric Joyner * @hw: pointer to hardware structure 22086f37f232SEric Joyner * @byte_offset: byte offset to write 22097d48aa4cSEric Joyner * @dev_addr: address to write to 22106f37f232SEric Joyner * @data: value to write 22116f37f232SEric Joyner * 22126f37f232SEric Joyner * Performs byte write operation to SFP module's EEPROM over I2C interface at 22136f37f232SEric Joyner * a specified device address. 22146f37f232SEric Joyner **/ 22156f37f232SEric Joyner s32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset, 22166f37f232SEric Joyner u8 dev_addr, u8 data) 22176f37f232SEric Joyner { 22186f37f232SEric Joyner return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr, 221979b36ec9SKevin Bowling data, false); 22206f37f232SEric Joyner } 22216f37f232SEric Joyner 22226f37f232SEric Joyner /** 22230ac6dfecSJack F Vogel * ixgbe_i2c_start - Sets I2C start condition 22240ac6dfecSJack F Vogel * @hw: pointer to hardware structure 22250ac6dfecSJack F Vogel * 22260ac6dfecSJack F Vogel * Sets I2C start condition (High -> Low on SDA while SCL is High) 2227758cc3dcSJack F Vogel * Set bit-bang mode on X550 hardware. 22280ac6dfecSJack F Vogel **/ 22290ac6dfecSJack F Vogel static void ixgbe_i2c_start(struct ixgbe_hw *hw) 22300ac6dfecSJack F Vogel { 2231758cc3dcSJack F Vogel u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 22320ac6dfecSJack F Vogel 22330ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_i2c_start"); 22340ac6dfecSJack F Vogel 2235758cc3dcSJack F Vogel i2cctl |= IXGBE_I2C_BB_EN_BY_MAC(hw); 2236758cc3dcSJack F Vogel 22370ac6dfecSJack F Vogel /* Start condition must begin with data and clock high */ 22380ac6dfecSJack F Vogel ixgbe_set_i2c_data(hw, &i2cctl, 1); 22390ac6dfecSJack F Vogel ixgbe_raise_i2c_clk(hw, &i2cctl); 22400ac6dfecSJack F Vogel 22410ac6dfecSJack F Vogel /* Setup time for start condition (4.7us) */ 22420ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_SU_STA); 22430ac6dfecSJack F Vogel 22440ac6dfecSJack F Vogel ixgbe_set_i2c_data(hw, &i2cctl, 0); 22450ac6dfecSJack F Vogel 22460ac6dfecSJack F Vogel /* Hold time for start condition (4us) */ 22470ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_HD_STA); 22480ac6dfecSJack F Vogel 22490ac6dfecSJack F Vogel ixgbe_lower_i2c_clk(hw, &i2cctl); 22500ac6dfecSJack F Vogel 22510ac6dfecSJack F Vogel /* Minimum low period of clock is 4.7 us */ 22520ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_LOW); 22530ac6dfecSJack F Vogel 22540ac6dfecSJack F Vogel } 22550ac6dfecSJack F Vogel 22560ac6dfecSJack F Vogel /** 22570ac6dfecSJack F Vogel * ixgbe_i2c_stop - Sets I2C stop condition 22580ac6dfecSJack F Vogel * @hw: pointer to hardware structure 22590ac6dfecSJack F Vogel * 22600ac6dfecSJack F Vogel * Sets I2C stop condition (Low -> High on SDA while SCL is High) 2261758cc3dcSJack F Vogel * Disables bit-bang mode and negates data output enable on X550 2262758cc3dcSJack F Vogel * hardware. 22630ac6dfecSJack F Vogel **/ 22640ac6dfecSJack F Vogel static void ixgbe_i2c_stop(struct ixgbe_hw *hw) 22650ac6dfecSJack F Vogel { 2266758cc3dcSJack F Vogel u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 2267758cc3dcSJack F Vogel u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); 2268758cc3dcSJack F Vogel u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw); 2269758cc3dcSJack F Vogel u32 bb_en_bit = IXGBE_I2C_BB_EN_BY_MAC(hw); 22700ac6dfecSJack F Vogel 22710ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_i2c_stop"); 22720ac6dfecSJack F Vogel 22730ac6dfecSJack F Vogel /* Stop condition must begin with data low and clock high */ 22740ac6dfecSJack F Vogel ixgbe_set_i2c_data(hw, &i2cctl, 0); 22750ac6dfecSJack F Vogel ixgbe_raise_i2c_clk(hw, &i2cctl); 22760ac6dfecSJack F Vogel 22770ac6dfecSJack F Vogel /* Setup time for stop condition (4us) */ 22780ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_SU_STO); 22790ac6dfecSJack F Vogel 22800ac6dfecSJack F Vogel ixgbe_set_i2c_data(hw, &i2cctl, 1); 22810ac6dfecSJack F Vogel 22820ac6dfecSJack F Vogel /* bus free time between stop and start (4.7us)*/ 22830ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_BUF); 2284758cc3dcSJack F Vogel 2285758cc3dcSJack F Vogel if (bb_en_bit || data_oe_bit || clk_oe_bit) { 2286758cc3dcSJack F Vogel i2cctl &= ~bb_en_bit; 2287758cc3dcSJack F Vogel i2cctl |= data_oe_bit | clk_oe_bit; 2288758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl); 2289758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 2290758cc3dcSJack F Vogel } 22910ac6dfecSJack F Vogel } 22920ac6dfecSJack F Vogel 22930ac6dfecSJack F Vogel /** 22940ac6dfecSJack F Vogel * ixgbe_clock_in_i2c_byte - Clocks in one byte via I2C 22950ac6dfecSJack F Vogel * @hw: pointer to hardware structure 22960ac6dfecSJack F Vogel * @data: data byte to clock in 22970ac6dfecSJack F Vogel * 22980ac6dfecSJack F Vogel * Clocks in one byte data via I2C data/clock 22990ac6dfecSJack F Vogel **/ 23003a890053SGuinan Sun static void ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data) 23010ac6dfecSJack F Vogel { 23020ac6dfecSJack F Vogel s32 i; 23030ac6dfecSJack F Vogel bool bit = 0; 23040ac6dfecSJack F Vogel 23050ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_clock_in_i2c_byte"); 23060ac6dfecSJack F Vogel 2307758cc3dcSJack F Vogel *data = 0; 23080ac6dfecSJack F Vogel for (i = 7; i >= 0; i--) { 230985d0a26eSJack F Vogel ixgbe_clock_in_i2c_bit(hw, &bit); 23100ac6dfecSJack F Vogel *data |= bit << i; 23110ac6dfecSJack F Vogel } 23120ac6dfecSJack F Vogel } 23130ac6dfecSJack F Vogel 23140ac6dfecSJack F Vogel /** 23150ac6dfecSJack F Vogel * ixgbe_clock_out_i2c_byte - Clocks out one byte via I2C 23160ac6dfecSJack F Vogel * @hw: pointer to hardware structure 23170ac6dfecSJack F Vogel * @data: data byte clocked out 23180ac6dfecSJack F Vogel * 23190ac6dfecSJack F Vogel * Clocks out one byte data via I2C data/clock 23200ac6dfecSJack F Vogel **/ 23210ac6dfecSJack F Vogel static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) 23220ac6dfecSJack F Vogel { 23230ac6dfecSJack F Vogel s32 status = IXGBE_SUCCESS; 23240ac6dfecSJack F Vogel s32 i; 23250ac6dfecSJack F Vogel u32 i2cctl; 2326758cc3dcSJack F Vogel bool bit; 23270ac6dfecSJack F Vogel 23280ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_clock_out_i2c_byte"); 23290ac6dfecSJack F Vogel 23300ac6dfecSJack F Vogel for (i = 7; i >= 0; i--) { 23310ac6dfecSJack F Vogel bit = (data >> i) & 0x1; 23320ac6dfecSJack F Vogel status = ixgbe_clock_out_i2c_bit(hw, bit); 23330ac6dfecSJack F Vogel 23340ac6dfecSJack F Vogel if (status != IXGBE_SUCCESS) 23350ac6dfecSJack F Vogel break; 23360ac6dfecSJack F Vogel } 23370ac6dfecSJack F Vogel 23380ac6dfecSJack F Vogel /* Release SDA line (set high) */ 2339758cc3dcSJack F Vogel i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 2340758cc3dcSJack F Vogel i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw); 2341758cc3dcSJack F Vogel i2cctl |= IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); 2342758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl); 234385d0a26eSJack F Vogel IXGBE_WRITE_FLUSH(hw); 23440ac6dfecSJack F Vogel 23450ac6dfecSJack F Vogel return status; 23460ac6dfecSJack F Vogel } 23470ac6dfecSJack F Vogel 23480ac6dfecSJack F Vogel /** 23490ac6dfecSJack F Vogel * ixgbe_get_i2c_ack - Polls for I2C ACK 23500ac6dfecSJack F Vogel * @hw: pointer to hardware structure 23510ac6dfecSJack F Vogel * 23520ac6dfecSJack F Vogel * Clocks in/out one bit via I2C data/clock 23530ac6dfecSJack F Vogel **/ 23540ac6dfecSJack F Vogel static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) 23550ac6dfecSJack F Vogel { 2356758cc3dcSJack F Vogel u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); 235785d0a26eSJack F Vogel s32 status = IXGBE_SUCCESS; 23580ac6dfecSJack F Vogel u32 i = 0; 2359758cc3dcSJack F Vogel u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 23600ac6dfecSJack F Vogel u32 timeout = 10; 23610ac6dfecSJack F Vogel bool ack = 1; 23620ac6dfecSJack F Vogel 23630ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_get_i2c_ack"); 23640ac6dfecSJack F Vogel 2365758cc3dcSJack F Vogel if (data_oe_bit) { 2366758cc3dcSJack F Vogel i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw); 2367758cc3dcSJack F Vogel i2cctl |= data_oe_bit; 2368758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl); 2369758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 2370758cc3dcSJack F Vogel } 237185d0a26eSJack F Vogel ixgbe_raise_i2c_clk(hw, &i2cctl); 23720ac6dfecSJack F Vogel 23730ac6dfecSJack F Vogel /* Minimum high period of clock is 4us */ 23740ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_HIGH); 23750ac6dfecSJack F Vogel 23760ac6dfecSJack F Vogel /* Poll for ACK. Note that ACK in I2C spec is 23770ac6dfecSJack F Vogel * transition from 1 to 0 */ 23780ac6dfecSJack F Vogel for (i = 0; i < timeout; i++) { 2379758cc3dcSJack F Vogel i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 2380758cc3dcSJack F Vogel ack = ixgbe_get_i2c_data(hw, &i2cctl); 23810ac6dfecSJack F Vogel 23820ac6dfecSJack F Vogel usec_delay(1); 2383758cc3dcSJack F Vogel if (!ack) 23840ac6dfecSJack F Vogel break; 23850ac6dfecSJack F Vogel } 23860ac6dfecSJack F Vogel 2387758cc3dcSJack F Vogel if (ack) { 2388758cc3dcSJack F Vogel DEBUGOUT("I2C ack was not received.\n"); 23890ac6dfecSJack F Vogel status = IXGBE_ERR_I2C; 23900ac6dfecSJack F Vogel } 23910ac6dfecSJack F Vogel 23920ac6dfecSJack F Vogel ixgbe_lower_i2c_clk(hw, &i2cctl); 23930ac6dfecSJack F Vogel 23940ac6dfecSJack F Vogel /* Minimum low period of clock is 4.7 us */ 23950ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_LOW); 23960ac6dfecSJack F Vogel 23970ac6dfecSJack F Vogel return status; 23980ac6dfecSJack F Vogel } 23990ac6dfecSJack F Vogel 24000ac6dfecSJack F Vogel /** 24010ac6dfecSJack F Vogel * ixgbe_clock_in_i2c_bit - Clocks in one bit via I2C data/clock 24020ac6dfecSJack F Vogel * @hw: pointer to hardware structure 24030ac6dfecSJack F Vogel * @data: read data value 24040ac6dfecSJack F Vogel * 24050ac6dfecSJack F Vogel * Clocks in one bit via I2C data/clock 24060ac6dfecSJack F Vogel **/ 24073a890053SGuinan Sun static void ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) 24080ac6dfecSJack F Vogel { 2409758cc3dcSJack F Vogel u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 2410758cc3dcSJack F Vogel u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); 24110ac6dfecSJack F Vogel 24122969bf0eSJack F Vogel DEBUGFUNC("ixgbe_clock_in_i2c_bit"); 24132969bf0eSJack F Vogel 2414758cc3dcSJack F Vogel if (data_oe_bit) { 2415758cc3dcSJack F Vogel i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw); 2416758cc3dcSJack F Vogel i2cctl |= data_oe_bit; 2417758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl); 2418758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 2419758cc3dcSJack F Vogel } 242085d0a26eSJack F Vogel ixgbe_raise_i2c_clk(hw, &i2cctl); 24210ac6dfecSJack F Vogel 24220ac6dfecSJack F Vogel /* Minimum high period of clock is 4us */ 24230ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_HIGH); 24240ac6dfecSJack F Vogel 2425758cc3dcSJack F Vogel i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 2426758cc3dcSJack F Vogel *data = ixgbe_get_i2c_data(hw, &i2cctl); 24270ac6dfecSJack F Vogel 24280ac6dfecSJack F Vogel ixgbe_lower_i2c_clk(hw, &i2cctl); 24290ac6dfecSJack F Vogel 24300ac6dfecSJack F Vogel /* Minimum low period of clock is 4.7 us */ 24310ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_LOW); 24320ac6dfecSJack F Vogel } 24330ac6dfecSJack F Vogel 24340ac6dfecSJack F Vogel /** 24350ac6dfecSJack F Vogel * ixgbe_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock 24360ac6dfecSJack F Vogel * @hw: pointer to hardware structure 24370ac6dfecSJack F Vogel * @data: data value to write 24380ac6dfecSJack F Vogel * 24390ac6dfecSJack F Vogel * Clocks out one bit via I2C data/clock 24400ac6dfecSJack F Vogel **/ 24410ac6dfecSJack F Vogel static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) 24420ac6dfecSJack F Vogel { 24430ac6dfecSJack F Vogel s32 status; 2444758cc3dcSJack F Vogel u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 24450ac6dfecSJack F Vogel 24462969bf0eSJack F Vogel DEBUGFUNC("ixgbe_clock_out_i2c_bit"); 24472969bf0eSJack F Vogel 24480ac6dfecSJack F Vogel status = ixgbe_set_i2c_data(hw, &i2cctl, data); 24490ac6dfecSJack F Vogel if (status == IXGBE_SUCCESS) { 245085d0a26eSJack F Vogel ixgbe_raise_i2c_clk(hw, &i2cctl); 24510ac6dfecSJack F Vogel 24520ac6dfecSJack F Vogel /* Minimum high period of clock is 4us */ 24530ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_HIGH); 24540ac6dfecSJack F Vogel 24550ac6dfecSJack F Vogel ixgbe_lower_i2c_clk(hw, &i2cctl); 24560ac6dfecSJack F Vogel 24570ac6dfecSJack F Vogel /* Minimum low period of clock is 4.7 us. 24580ac6dfecSJack F Vogel * This also takes care of the data hold time. 24590ac6dfecSJack F Vogel */ 24600ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_LOW); 24610ac6dfecSJack F Vogel } else { 24620ac6dfecSJack F Vogel status = IXGBE_ERR_I2C; 2463fd75b91dSJack F Vogel ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, 2464fd75b91dSJack F Vogel "I2C data was not set to %X\n", data); 24650ac6dfecSJack F Vogel } 24660ac6dfecSJack F Vogel 24670ac6dfecSJack F Vogel return status; 24680ac6dfecSJack F Vogel } 2469758cc3dcSJack F Vogel 24700ac6dfecSJack F Vogel /** 24710ac6dfecSJack F Vogel * ixgbe_raise_i2c_clk - Raises the I2C SCL clock 24720ac6dfecSJack F Vogel * @hw: pointer to hardware structure 24730ac6dfecSJack F Vogel * @i2cctl: Current value of I2CCTL register 24740ac6dfecSJack F Vogel * 24750ac6dfecSJack F Vogel * Raises the I2C clock line '0'->'1' 2476758cc3dcSJack F Vogel * Negates the I2C clock output enable on X550 hardware. 24770ac6dfecSJack F Vogel **/ 247885d0a26eSJack F Vogel static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) 24790ac6dfecSJack F Vogel { 2480758cc3dcSJack F Vogel u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw); 2481a621e3c8SJack F Vogel u32 i = 0; 2482a621e3c8SJack F Vogel u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT; 2483a621e3c8SJack F Vogel u32 i2cctl_r = 0; 2484a621e3c8SJack F Vogel 24852969bf0eSJack F Vogel DEBUGFUNC("ixgbe_raise_i2c_clk"); 24862969bf0eSJack F Vogel 2487758cc3dcSJack F Vogel if (clk_oe_bit) { 2488758cc3dcSJack F Vogel *i2cctl |= clk_oe_bit; 2489758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); 2490758cc3dcSJack F Vogel } 24910ac6dfecSJack F Vogel 2492758cc3dcSJack F Vogel for (i = 0; i < timeout; i++) { 2493758cc3dcSJack F Vogel *i2cctl |= IXGBE_I2C_CLK_OUT_BY_MAC(hw); 2494758cc3dcSJack F Vogel 2495758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); 249685d0a26eSJack F Vogel IXGBE_WRITE_FLUSH(hw); 24970ac6dfecSJack F Vogel /* SCL rise time (1000ns) */ 24980ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_RISE); 2499a621e3c8SJack F Vogel 2500758cc3dcSJack F Vogel i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 2501758cc3dcSJack F Vogel if (i2cctl_r & IXGBE_I2C_CLK_IN_BY_MAC(hw)) 2502a621e3c8SJack F Vogel break; 2503a621e3c8SJack F Vogel } 25040ac6dfecSJack F Vogel } 25050ac6dfecSJack F Vogel 25060ac6dfecSJack F Vogel /** 25070ac6dfecSJack F Vogel * ixgbe_lower_i2c_clk - Lowers the I2C SCL clock 25080ac6dfecSJack F Vogel * @hw: pointer to hardware structure 25090ac6dfecSJack F Vogel * @i2cctl: Current value of I2CCTL register 25100ac6dfecSJack F Vogel * 25110ac6dfecSJack F Vogel * Lowers the I2C clock line '1'->'0' 2512758cc3dcSJack F Vogel * Asserts the I2C clock output enable on X550 hardware. 25130ac6dfecSJack F Vogel **/ 25140ac6dfecSJack F Vogel static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) 25150ac6dfecSJack F Vogel { 25162969bf0eSJack F Vogel DEBUGFUNC("ixgbe_lower_i2c_clk"); 25172969bf0eSJack F Vogel 2518758cc3dcSJack F Vogel *i2cctl &= ~(IXGBE_I2C_CLK_OUT_BY_MAC(hw)); 2519758cc3dcSJack F Vogel *i2cctl &= ~IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw); 25200ac6dfecSJack F Vogel 2521758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); 252285d0a26eSJack F Vogel IXGBE_WRITE_FLUSH(hw); 25230ac6dfecSJack F Vogel 25240ac6dfecSJack F Vogel /* SCL fall time (300ns) */ 25250ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_FALL); 25260ac6dfecSJack F Vogel } 25270ac6dfecSJack F Vogel 25280ac6dfecSJack F Vogel /** 25290ac6dfecSJack F Vogel * ixgbe_set_i2c_data - Sets the I2C data bit 25300ac6dfecSJack F Vogel * @hw: pointer to hardware structure 25310ac6dfecSJack F Vogel * @i2cctl: Current value of I2CCTL register 25320ac6dfecSJack F Vogel * @data: I2C data value (0 or 1) to set 25330ac6dfecSJack F Vogel * 25340ac6dfecSJack F Vogel * Sets the I2C data bit 2535758cc3dcSJack F Vogel * Asserts the I2C data output enable on X550 hardware. 25360ac6dfecSJack F Vogel **/ 25370ac6dfecSJack F Vogel static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) 25380ac6dfecSJack F Vogel { 2539758cc3dcSJack F Vogel u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); 25400ac6dfecSJack F Vogel s32 status = IXGBE_SUCCESS; 25410ac6dfecSJack F Vogel 25422969bf0eSJack F Vogel DEBUGFUNC("ixgbe_set_i2c_data"); 25432969bf0eSJack F Vogel 25440ac6dfecSJack F Vogel if (data) 2545758cc3dcSJack F Vogel *i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw); 25460ac6dfecSJack F Vogel else 2547758cc3dcSJack F Vogel *i2cctl &= ~(IXGBE_I2C_DATA_OUT_BY_MAC(hw)); 2548758cc3dcSJack F Vogel *i2cctl &= ~data_oe_bit; 25490ac6dfecSJack F Vogel 2550758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); 255185d0a26eSJack F Vogel IXGBE_WRITE_FLUSH(hw); 25520ac6dfecSJack F Vogel 25530ac6dfecSJack F Vogel /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */ 25540ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA); 25550ac6dfecSJack F Vogel 2556758cc3dcSJack F Vogel if (!data) /* Can't verify data in this case */ 2557758cc3dcSJack F Vogel return IXGBE_SUCCESS; 2558758cc3dcSJack F Vogel if (data_oe_bit) { 2559758cc3dcSJack F Vogel *i2cctl |= data_oe_bit; 2560758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); 2561758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 2562758cc3dcSJack F Vogel } 2563758cc3dcSJack F Vogel 25640ac6dfecSJack F Vogel /* Verify data was set correctly */ 2565758cc3dcSJack F Vogel *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 2566758cc3dcSJack F Vogel if (data != ixgbe_get_i2c_data(hw, i2cctl)) { 25670ac6dfecSJack F Vogel status = IXGBE_ERR_I2C; 2568fd75b91dSJack F Vogel ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, 2569fd75b91dSJack F Vogel "Error - I2C data was not set to %X.\n", 2570fd75b91dSJack F Vogel data); 25710ac6dfecSJack F Vogel } 25720ac6dfecSJack F Vogel 25730ac6dfecSJack F Vogel return status; 25740ac6dfecSJack F Vogel } 25750ac6dfecSJack F Vogel 25760ac6dfecSJack F Vogel /** 25770ac6dfecSJack F Vogel * ixgbe_get_i2c_data - Reads the I2C SDA data bit 25780ac6dfecSJack F Vogel * @hw: pointer to hardware structure 25790ac6dfecSJack F Vogel * @i2cctl: Current value of I2CCTL register 25800ac6dfecSJack F Vogel * 25810ac6dfecSJack F Vogel * Returns the I2C data bit value 2582758cc3dcSJack F Vogel * Negates the I2C data output enable on X550 hardware. 25830ac6dfecSJack F Vogel **/ 2584758cc3dcSJack F Vogel static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl) 25850ac6dfecSJack F Vogel { 2586758cc3dcSJack F Vogel u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); 25870ac6dfecSJack F Vogel bool data; 25880ac6dfecSJack F Vogel 25892969bf0eSJack F Vogel DEBUGFUNC("ixgbe_get_i2c_data"); 25902969bf0eSJack F Vogel 2591758cc3dcSJack F Vogel if (data_oe_bit) { 2592758cc3dcSJack F Vogel *i2cctl |= data_oe_bit; 2593758cc3dcSJack F Vogel IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); 2594758cc3dcSJack F Vogel IXGBE_WRITE_FLUSH(hw); 2595758cc3dcSJack F Vogel usec_delay(IXGBE_I2C_T_FALL); 2596758cc3dcSJack F Vogel } 2597758cc3dcSJack F Vogel 2598758cc3dcSJack F Vogel if (*i2cctl & IXGBE_I2C_DATA_IN_BY_MAC(hw)) 25990ac6dfecSJack F Vogel data = 1; 26000ac6dfecSJack F Vogel else 26010ac6dfecSJack F Vogel data = 0; 26020ac6dfecSJack F Vogel 26030ac6dfecSJack F Vogel return data; 26040ac6dfecSJack F Vogel } 26050ac6dfecSJack F Vogel 26060ac6dfecSJack F Vogel /** 26070ac6dfecSJack F Vogel * ixgbe_i2c_bus_clear - Clears the I2C bus 26080ac6dfecSJack F Vogel * @hw: pointer to hardware structure 26090ac6dfecSJack F Vogel * 26100ac6dfecSJack F Vogel * Clears the I2C bus by sending nine clock pulses. 26110ac6dfecSJack F Vogel * Used when data line is stuck low. 26120ac6dfecSJack F Vogel **/ 26130ac6dfecSJack F Vogel void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw) 26140ac6dfecSJack F Vogel { 2615758cc3dcSJack F Vogel u32 i2cctl; 26160ac6dfecSJack F Vogel u32 i; 26170ac6dfecSJack F Vogel 26180ac6dfecSJack F Vogel DEBUGFUNC("ixgbe_i2c_bus_clear"); 26190ac6dfecSJack F Vogel 26200ac6dfecSJack F Vogel ixgbe_i2c_start(hw); 2621758cc3dcSJack F Vogel i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); 26220ac6dfecSJack F Vogel 26230ac6dfecSJack F Vogel ixgbe_set_i2c_data(hw, &i2cctl, 1); 26240ac6dfecSJack F Vogel 26250ac6dfecSJack F Vogel for (i = 0; i < 9; i++) { 26260ac6dfecSJack F Vogel ixgbe_raise_i2c_clk(hw, &i2cctl); 26270ac6dfecSJack F Vogel 26280ac6dfecSJack F Vogel /* Min high period of clock is 4us */ 26290ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_HIGH); 26300ac6dfecSJack F Vogel 26310ac6dfecSJack F Vogel ixgbe_lower_i2c_clk(hw, &i2cctl); 26320ac6dfecSJack F Vogel 26330ac6dfecSJack F Vogel /* Min low period of clock is 4.7us*/ 26340ac6dfecSJack F Vogel usec_delay(IXGBE_I2C_T_LOW); 26350ac6dfecSJack F Vogel } 26360ac6dfecSJack F Vogel 26370ac6dfecSJack F Vogel ixgbe_i2c_start(hw); 26380ac6dfecSJack F Vogel 26390ac6dfecSJack F Vogel /* Put the i2c bus back to default state */ 26400ac6dfecSJack F Vogel ixgbe_i2c_stop(hw); 26410ac6dfecSJack F Vogel } 2642c0014855SJack F Vogel 2643c0014855SJack F Vogel /** 2644a621e3c8SJack F Vogel * ixgbe_tn_check_overtemp - Checks if an overtemp occurred. 2645c0014855SJack F Vogel * @hw: pointer to hardware structure 2646c0014855SJack F Vogel * 2647c0014855SJack F Vogel * Checks if the LASI temp alarm status was triggered due to overtemp 2648c0014855SJack F Vogel **/ 2649c0014855SJack F Vogel s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw) 2650c0014855SJack F Vogel { 2651c0014855SJack F Vogel s32 status = IXGBE_SUCCESS; 2652c0014855SJack F Vogel u16 phy_data = 0; 2653c0014855SJack F Vogel 2654c0014855SJack F Vogel DEBUGFUNC("ixgbe_tn_check_overtemp"); 2655c0014855SJack F Vogel 2656c0014855SJack F Vogel if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM) 2657c0014855SJack F Vogel goto out; 2658c0014855SJack F Vogel 2659c0014855SJack F Vogel /* Check that the LASI temp alarm status was triggered */ 2660c0014855SJack F Vogel hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG, 2661c0014855SJack F Vogel IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_data); 2662c0014855SJack F Vogel 2663c0014855SJack F Vogel if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM)) 2664c0014855SJack F Vogel goto out; 2665c0014855SJack F Vogel 2666c0014855SJack F Vogel status = IXGBE_ERR_OVERTEMP; 2667fd75b91dSJack F Vogel ERROR_REPORT1(IXGBE_ERROR_CAUTION, "Device over temperature"); 2668c0014855SJack F Vogel out: 2669c0014855SJack F Vogel return status; 2670c0014855SJack F Vogel } 2671758cc3dcSJack F Vogel 2672758cc3dcSJack F Vogel /** 2673758cc3dcSJack F Vogel * ixgbe_set_copper_phy_power - Control power for copper phy 2674758cc3dcSJack F Vogel * @hw: pointer to hardware structure 267579b36ec9SKevin Bowling * @on: true for on, false for off 2676758cc3dcSJack F Vogel */ 2677758cc3dcSJack F Vogel s32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on) 2678758cc3dcSJack F Vogel { 2679758cc3dcSJack F Vogel u32 status; 2680758cc3dcSJack F Vogel u16 reg; 2681758cc3dcSJack F Vogel 26821ebf555bSSteven Hartland if (!on && ixgbe_mng_present(hw)) 26831ebf555bSSteven Hartland return 0; 26841ebf555bSSteven Hartland 2685758cc3dcSJack F Vogel status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL, 2686758cc3dcSJack F Vogel IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2687758cc3dcSJack F Vogel ®); 2688758cc3dcSJack F Vogel if (status) 2689758cc3dcSJack F Vogel return status; 2690758cc3dcSJack F Vogel 2691758cc3dcSJack F Vogel if (on) { 2692758cc3dcSJack F Vogel reg &= ~IXGBE_MDIO_PHY_SET_LOW_POWER_MODE; 2693758cc3dcSJack F Vogel } else { 2694758cc3dcSJack F Vogel if (ixgbe_check_reset_blocked(hw)) 2695758cc3dcSJack F Vogel return 0; 2696758cc3dcSJack F Vogel reg |= IXGBE_MDIO_PHY_SET_LOW_POWER_MODE; 2697758cc3dcSJack F Vogel } 2698758cc3dcSJack F Vogel 2699758cc3dcSJack F Vogel status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL, 2700758cc3dcSJack F Vogel IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, 2701758cc3dcSJack F Vogel reg); 2702758cc3dcSJack F Vogel return status; 2703758cc3dcSJack F Vogel } 2704