xref: /freebsd-src/sys/dev/ixgbe/ixgbe_phy.c (revision e38f9257c3fac5cb5a62f62c424a976446ae1220)
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 				      &reg);
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