xref: /onnv-gate/usr/src/uts/common/io/ixgbe/ixgbe_phy.c (revision 13006:22e6d3edaab5)
16621Sbt150084 /*
26621Sbt150084  * CDDL HEADER START
36621Sbt150084  *
46621Sbt150084  * The contents of this file are subject to the terms of the
56621Sbt150084  * Common Development and Distribution License (the "License").
66621Sbt150084  * You may not use this file except in compliance with the License.
76621Sbt150084  *
86621Sbt150084  * You can obtain a copy of the license at:
96621Sbt150084  *      http://www.opensolaris.org/os/licensing.
106621Sbt150084  * See the License for the specific language governing permissions
116621Sbt150084  * and limitations under the License.
126621Sbt150084  *
136621Sbt150084  * When using or redistributing this file, you may do so under the
146621Sbt150084  * License only. No other modification of this header is permitted.
156621Sbt150084  *
166621Sbt150084  * If applicable, add the following below this CDDL HEADER, with the
176621Sbt150084  * fields enclosed by brackets "[]" replaced with your own identifying
186621Sbt150084  * information: Portions Copyright [yyyy] [name of copyright owner]
196621Sbt150084  *
206621Sbt150084  * CDDL HEADER END
216621Sbt150084  */
226621Sbt150084 
236621Sbt150084 /*
24*13006SChenlu.Chen@Sun.COM  * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
256621Sbt150084  */
266621Sbt150084 
27*13006SChenlu.Chen@Sun.COM /*
28*13006SChenlu.Chen@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
29*13006SChenlu.Chen@Sun.COM  */
30*13006SChenlu.Chen@Sun.COM 
31*13006SChenlu.Chen@Sun.COM /* IntelVersion: 1.109 scm_061610_003709 */
326621Sbt150084 
336621Sbt150084 #include "ixgbe_api.h"
346621Sbt150084 #include "ixgbe_common.h"
356621Sbt150084 #include "ixgbe_phy.h"
369353SSamuel.Tu@Sun.COM 
379353SSamuel.Tu@Sun.COM static void ixgbe_i2c_start(struct ixgbe_hw *hw);
389353SSamuel.Tu@Sun.COM static void ixgbe_i2c_stop(struct ixgbe_hw *hw);
399353SSamuel.Tu@Sun.COM static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data);
409353SSamuel.Tu@Sun.COM static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data);
419353SSamuel.Tu@Sun.COM static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw);
429353SSamuel.Tu@Sun.COM static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data);
439353SSamuel.Tu@Sun.COM static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data);
449353SSamuel.Tu@Sun.COM static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
459353SSamuel.Tu@Sun.COM static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
469353SSamuel.Tu@Sun.COM static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data);
479353SSamuel.Tu@Sun.COM static bool ixgbe_get_i2c_data(u32 *i2cctl);
489353SSamuel.Tu@Sun.COM void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw);
496621Sbt150084 
506621Sbt150084 /*
516621Sbt150084  * ixgbe_init_phy_ops_generic - Inits PHY function ptrs
526621Sbt150084  * @hw: pointer to the hardware structure
536621Sbt150084  *
546621Sbt150084  * Initialize the function pointers.
556621Sbt150084  */
566621Sbt150084 s32
ixgbe_init_phy_ops_generic(struct ixgbe_hw * hw)576621Sbt150084 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw)
586621Sbt150084 {
596621Sbt150084 	struct ixgbe_phy_info *phy = &hw->phy;
606621Sbt150084 
6110998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_init_phy_ops_generic");
6210998SChenlu.Chen@Sun.COM 
636621Sbt150084 	/* PHY */
646621Sbt150084 	phy->ops.identify = &ixgbe_identify_phy_generic;
656621Sbt150084 	phy->ops.reset = &ixgbe_reset_phy_generic;
666621Sbt150084 	phy->ops.read_reg = &ixgbe_read_phy_reg_generic;
676621Sbt150084 	phy->ops.write_reg = &ixgbe_write_phy_reg_generic;
686621Sbt150084 	phy->ops.setup_link = &ixgbe_setup_phy_link_generic;
696621Sbt150084 	phy->ops.setup_link_speed = &ixgbe_setup_phy_link_speed_generic;
708490SPaul.Guo@Sun.COM 	phy->ops.check_link = NULL;
7110998SChenlu.Chen@Sun.COM 	phy->ops.get_firmware_version = ixgbe_get_phy_firmware_version_generic;
729353SSamuel.Tu@Sun.COM 	phy->ops.read_i2c_byte = &ixgbe_read_i2c_byte_generic;
739353SSamuel.Tu@Sun.COM 	phy->ops.write_i2c_byte = &ixgbe_write_i2c_byte_generic;
749353SSamuel.Tu@Sun.COM 	phy->ops.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic;
759353SSamuel.Tu@Sun.COM 	phy->ops.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic;
769353SSamuel.Tu@Sun.COM 	phy->ops.i2c_bus_clear = &ixgbe_i2c_bus_clear;
778490SPaul.Guo@Sun.COM 	phy->ops.identify_sfp = &ixgbe_identify_sfp_module_generic;
788490SPaul.Guo@Sun.COM 	phy->sfp_type = ixgbe_sfp_type_unknown;
79*13006SChenlu.Chen@Sun.COM 	phy->ops.check_overtemp = &ixgbe_tn_check_overtemp;
806621Sbt150084 
816621Sbt150084 	return (IXGBE_SUCCESS);
826621Sbt150084 }
836621Sbt150084 
846621Sbt150084 /*
856621Sbt150084  * ixgbe_identify_phy_generic - Get physical layer module
866621Sbt150084  * @hw: pointer to hardware structure
876621Sbt150084  *
886621Sbt150084  * Determines the physical layer module found on the current adapter.
896621Sbt150084  */
906621Sbt150084 s32
ixgbe_identify_phy_generic(struct ixgbe_hw * hw)916621Sbt150084 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
926621Sbt150084 {
936621Sbt150084 	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
946621Sbt150084 	u32 phy_addr;
959353SSamuel.Tu@Sun.COM 	u16 ext_ability = 0;
966621Sbt150084 
9710998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_identify_phy_generic");
9810998SChenlu.Chen@Sun.COM 
996621Sbt150084 	if (hw->phy.type == ixgbe_phy_unknown) {
1006621Sbt150084 		for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
1016621Sbt150084 			if (ixgbe_validate_phy_addr(hw, phy_addr)) {
1026621Sbt150084 				hw->phy.addr = phy_addr;
1036621Sbt150084 				(void) ixgbe_get_phy_id(hw);
1046621Sbt150084 				hw->phy.type =
1056621Sbt150084 				    ixgbe_get_phy_type_from_id(hw->phy.id);
1069353SSamuel.Tu@Sun.COM 
1079353SSamuel.Tu@Sun.COM 				if (hw->phy.type == ixgbe_phy_unknown) {
1089353SSamuel.Tu@Sun.COM 					hw->phy.ops.read_reg(hw,
1099353SSamuel.Tu@Sun.COM 					    IXGBE_MDIO_PHY_EXT_ABILITY,
1109353SSamuel.Tu@Sun.COM 					    IXGBE_MDIO_PMA_PMD_DEV_TYPE,
1119353SSamuel.Tu@Sun.COM 					    &ext_ability);
1129353SSamuel.Tu@Sun.COM 					if (ext_ability &
1139353SSamuel.Tu@Sun.COM 					    IXGBE_MDIO_PHY_10GBASET_ABILITY ||
1149353SSamuel.Tu@Sun.COM 					    ext_ability &
1159353SSamuel.Tu@Sun.COM 					    IXGBE_MDIO_PHY_1000BASET_ABILITY)
1169353SSamuel.Tu@Sun.COM 						hw->phy.type =
1179353SSamuel.Tu@Sun.COM 						    ixgbe_phy_cu_unknown;
1189353SSamuel.Tu@Sun.COM 					else
1199353SSamuel.Tu@Sun.COM 						hw->phy.type =
1209353SSamuel.Tu@Sun.COM 						    ixgbe_phy_generic;
1219353SSamuel.Tu@Sun.COM 				}
1229353SSamuel.Tu@Sun.COM 
1236621Sbt150084 				status = IXGBE_SUCCESS;
1246621Sbt150084 				break;
1256621Sbt150084 			}
1266621Sbt150084 		}
1279353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
1289353SSamuel.Tu@Sun.COM 			hw->phy.addr = 0;
1296621Sbt150084 	} else {
1306621Sbt150084 		status = IXGBE_SUCCESS;
1316621Sbt150084 	}
1326621Sbt150084 
1336621Sbt150084 	return (status);
1346621Sbt150084 }
1356621Sbt150084 
1366621Sbt150084 /*
1376621Sbt150084  * ixgbe_validate_phy_addr - Determines phy address is valid
1386621Sbt150084  * @hw: pointer to hardware structure
1396621Sbt150084  *
1406621Sbt150084  */
1416621Sbt150084 bool
ixgbe_validate_phy_addr(struct ixgbe_hw * hw,u32 phy_addr)1426621Sbt150084 ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
1436621Sbt150084 {
1446621Sbt150084 	u16 phy_id = 0;
1458490SPaul.Guo@Sun.COM 	bool valid = false;
1466621Sbt150084 
14710998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_validate_phy_addr");
14810998SChenlu.Chen@Sun.COM 
1496621Sbt150084 	hw->phy.addr = phy_addr;
1506621Sbt150084 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
1516621Sbt150084 	    IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id);
1526621Sbt150084 
1536621Sbt150084 	if (phy_id != 0xFFFF && phy_id != 0x0)
1548490SPaul.Guo@Sun.COM 		valid = true;
1556621Sbt150084 
1566621Sbt150084 	return (valid);
1576621Sbt150084 }
1586621Sbt150084 
1596621Sbt150084 /*
1606621Sbt150084  * ixgbe_get_phy_id - Get the phy type
1616621Sbt150084  * @hw: pointer to hardware structure
1626621Sbt150084  *
1636621Sbt150084  */
1646621Sbt150084 s32
ixgbe_get_phy_id(struct ixgbe_hw * hw)1656621Sbt150084 ixgbe_get_phy_id(struct ixgbe_hw *hw)
1666621Sbt150084 {
1676621Sbt150084 	u32 status;
1686621Sbt150084 	u16 phy_id_high = 0;
1696621Sbt150084 	u16 phy_id_low = 0;
1706621Sbt150084 
17110998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_get_phy_id");
17210998SChenlu.Chen@Sun.COM 
1736621Sbt150084 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
1746621Sbt150084 	    IXGBE_MDIO_PMA_PMD_DEV_TYPE,
1756621Sbt150084 	    &phy_id_high);
1766621Sbt150084 
1776621Sbt150084 	if (status == IXGBE_SUCCESS) {
1786621Sbt150084 		hw->phy.id = (u32)(phy_id_high << 16);
1796621Sbt150084 		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW,
1806621Sbt150084 		    IXGBE_MDIO_PMA_PMD_DEV_TYPE,
1816621Sbt150084 		    &phy_id_low);
1826621Sbt150084 		hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
1836621Sbt150084 		hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
1846621Sbt150084 	}
1856621Sbt150084 
1866621Sbt150084 	return (status);
1876621Sbt150084 }
1886621Sbt150084 
1896621Sbt150084 /*
1906621Sbt150084  * ixgbe_get_phy_type_from_id - Get the phy type
1916621Sbt150084  * @hw: pointer to hardware structure
1926621Sbt150084  *
1936621Sbt150084  */
1946621Sbt150084 enum ixgbe_phy_type
ixgbe_get_phy_type_from_id(u32 phy_id)1956621Sbt150084 ixgbe_get_phy_type_from_id(u32 phy_id)
1966621Sbt150084 {
1976621Sbt150084 	enum ixgbe_phy_type phy_type;
1986621Sbt150084 
19910998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_get_phy_type_from_id");
20010998SChenlu.Chen@Sun.COM 
2016621Sbt150084 	switch (phy_id) {
2028490SPaul.Guo@Sun.COM 	case TN1010_PHY_ID:
2038490SPaul.Guo@Sun.COM 		phy_type = ixgbe_phy_tn;
2048490SPaul.Guo@Sun.COM 		break;
20510305SPaul.Guo@Sun.COM 	case AQ1002_PHY_ID:
20610305SPaul.Guo@Sun.COM 		phy_type = ixgbe_phy_aq;
20710305SPaul.Guo@Sun.COM 		break;
2086621Sbt150084 	case QT2022_PHY_ID:
2096621Sbt150084 		phy_type = ixgbe_phy_qt;
2106621Sbt150084 		break;
2118490SPaul.Guo@Sun.COM 	case ATH_PHY_ID:
2128490SPaul.Guo@Sun.COM 		phy_type = ixgbe_phy_nl;
2138490SPaul.Guo@Sun.COM 		break;
2146621Sbt150084 	default:
2156621Sbt150084 		phy_type = ixgbe_phy_unknown;
2166621Sbt150084 		break;
2176621Sbt150084 	}
2186621Sbt150084 
2198490SPaul.Guo@Sun.COM 	DEBUGOUT1("phy type found is %d\n", phy_type);
2208490SPaul.Guo@Sun.COM 
2216621Sbt150084 	return (phy_type);
2226621Sbt150084 }
2236621Sbt150084 
2246621Sbt150084 /*
2256621Sbt150084  * ixgbe_reset_phy_generic - Performs a PHY reset
2266621Sbt150084  * @hw: pointer to hardware structure
2276621Sbt150084  */
2286621Sbt150084 s32
ixgbe_reset_phy_generic(struct ixgbe_hw * hw)2296621Sbt150084 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
2306621Sbt150084 {
2319353SSamuel.Tu@Sun.COM 	u32 i;
2329353SSamuel.Tu@Sun.COM 	u16 ctrl = 0;
2339353SSamuel.Tu@Sun.COM 	s32 status = IXGBE_SUCCESS;
2349353SSamuel.Tu@Sun.COM 
23510998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_reset_phy_generic");
23610998SChenlu.Chen@Sun.COM 
2379353SSamuel.Tu@Sun.COM 	if (hw->phy.type == ixgbe_phy_unknown)
2389353SSamuel.Tu@Sun.COM 		status = ixgbe_identify_phy_generic(hw);
2399353SSamuel.Tu@Sun.COM 
2409353SSamuel.Tu@Sun.COM 	if (status != IXGBE_SUCCESS || hw->phy.type == ixgbe_phy_none)
2419353SSamuel.Tu@Sun.COM 		goto out;
2429353SSamuel.Tu@Sun.COM 
243*13006SChenlu.Chen@Sun.COM 	if (!hw->phy.reset_if_overtemp &&
244*13006SChenlu.Chen@Sun.COM 	    (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw))) {
245*13006SChenlu.Chen@Sun.COM 		/* Don't reset PHY if it's shut down due to overtemp. */
246*13006SChenlu.Chen@Sun.COM 		goto out;
247*13006SChenlu.Chen@Sun.COM 	}
248*13006SChenlu.Chen@Sun.COM 
2496621Sbt150084 	/*
2506621Sbt150084 	 * Perform soft PHY reset to the PHY_XS.
2516621Sbt150084 	 * This will cause a soft reset to the PHY
2526621Sbt150084 	 */
2539353SSamuel.Tu@Sun.COM 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
2546621Sbt150084 	    IXGBE_MDIO_PHY_XS_DEV_TYPE,
2556621Sbt150084 	    IXGBE_MDIO_PHY_XS_RESET);
2569353SSamuel.Tu@Sun.COM 
257*13006SChenlu.Chen@Sun.COM 	/*
258*13006SChenlu.Chen@Sun.COM 	 * Poll for reset bit to self-clear indicating reset is complete.
259*13006SChenlu.Chen@Sun.COM 	 * Some PHYs could take up to 3 seconds to complete and need about
260*13006SChenlu.Chen@Sun.COM 	 * 1.7 usec delay after the reset is complete.
261*13006SChenlu.Chen@Sun.COM 	 */
262*13006SChenlu.Chen@Sun.COM 	for (i = 0; i < 30; i++) {
263*13006SChenlu.Chen@Sun.COM 		msec_delay(100);
2649353SSamuel.Tu@Sun.COM 		hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
2659353SSamuel.Tu@Sun.COM 		    IXGBE_MDIO_PHY_XS_DEV_TYPE, &ctrl);
266*13006SChenlu.Chen@Sun.COM 		if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) {
267*13006SChenlu.Chen@Sun.COM 			usec_delay(2);
2689353SSamuel.Tu@Sun.COM 			break;
269*13006SChenlu.Chen@Sun.COM 		}
2709353SSamuel.Tu@Sun.COM 	}
2719353SSamuel.Tu@Sun.COM 
2729353SSamuel.Tu@Sun.COM 	if (ctrl & IXGBE_MDIO_PHY_XS_RESET) {
2739353SSamuel.Tu@Sun.COM 		status = IXGBE_ERR_RESET_FAILED;
2749353SSamuel.Tu@Sun.COM 		DEBUGOUT("PHY reset polling failed to complete.\n");
2759353SSamuel.Tu@Sun.COM 	}
2769353SSamuel.Tu@Sun.COM 
2779353SSamuel.Tu@Sun.COM out:
2789353SSamuel.Tu@Sun.COM 	return (status);
2796621Sbt150084 }
2806621Sbt150084 
2816621Sbt150084 /*
2826621Sbt150084  * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register
2836621Sbt150084  * @hw: pointer to hardware structure
2846621Sbt150084  * @reg_addr: 32 bit address of PHY register to read
2856621Sbt150084  * @phy_data: Pointer to read data from PHY register
2866621Sbt150084  */
2876621Sbt150084 s32
ixgbe_read_phy_reg_generic(struct ixgbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)2886621Sbt150084 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
2896621Sbt150084     u32 device_type, u16 *phy_data)
2906621Sbt150084 {
2916621Sbt150084 	u32 command;
2926621Sbt150084 	u32 i;
2936621Sbt150084 	u32 data;
2946621Sbt150084 	s32 status = IXGBE_SUCCESS;
2956621Sbt150084 	u16 gssr;
2966621Sbt150084 
29710998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_read_phy_reg_generic");
29810998SChenlu.Chen@Sun.COM 
2996621Sbt150084 	if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
3006621Sbt150084 		gssr = IXGBE_GSSR_PHY1_SM;
3016621Sbt150084 	else
3026621Sbt150084 		gssr = IXGBE_GSSR_PHY0_SM;
3036621Sbt150084 
3046621Sbt150084 	if (ixgbe_acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS)
3056621Sbt150084 		status = IXGBE_ERR_SWFW_SYNC;
3066621Sbt150084 
3076621Sbt150084 	if (status == IXGBE_SUCCESS) {
3086621Sbt150084 		/* Setup and write the address cycle command */
3096621Sbt150084 		command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
3106621Sbt150084 		    (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
3116621Sbt150084 		    (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
3126621Sbt150084 		    (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
3136621Sbt150084 
3146621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
3156621Sbt150084 
3166621Sbt150084 		/*
3176621Sbt150084 		 * Check every 10 usec to see if the address cycle completed.
3186621Sbt150084 		 * The MDI Command bit will clear when the operation is
3196621Sbt150084 		 * complete
3206621Sbt150084 		 */
3216621Sbt150084 		for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
3226621Sbt150084 			usec_delay(10);
3236621Sbt150084 
3246621Sbt150084 			command = IXGBE_READ_REG(hw, IXGBE_MSCA);
3256621Sbt150084 
3266621Sbt150084 			if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
3276621Sbt150084 				break;
3286621Sbt150084 			}
3296621Sbt150084 		}
3306621Sbt150084 
3316621Sbt150084 		if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
3326621Sbt150084 			DEBUGOUT("PHY address command did not complete.\n");
3336621Sbt150084 			status = IXGBE_ERR_PHY;
3346621Sbt150084 		}
3356621Sbt150084 
3366621Sbt150084 		if (status == IXGBE_SUCCESS) {
3376621Sbt150084 			/*
3386621Sbt150084 			 * Address cycle complete, setup and write the read
3396621Sbt150084 			 * command
3406621Sbt150084 			 */
3416621Sbt150084 			command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
3426621Sbt150084 			    (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
3436621Sbt150084 			    (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
3446621Sbt150084 			    (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
3456621Sbt150084 
3466621Sbt150084 			IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
3476621Sbt150084 
3486621Sbt150084 			/*
3496621Sbt150084 			 * Check every 10 usec to see if the address cycle
3506621Sbt150084 			 * completed. The MDI Command bit will clear when the
3516621Sbt150084 			 * operation is complete
3526621Sbt150084 			 */
3536621Sbt150084 			for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
3546621Sbt150084 				usec_delay(10);
3556621Sbt150084 
3566621Sbt150084 				command = IXGBE_READ_REG(hw, IXGBE_MSCA);
3576621Sbt150084 
3586621Sbt150084 				if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
3596621Sbt150084 					break;
3606621Sbt150084 			}
3616621Sbt150084 
3626621Sbt150084 			if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
3636621Sbt150084 				DEBUGOUT("PHY read command didn't complete\n");
3646621Sbt150084 				status = IXGBE_ERR_PHY;
3656621Sbt150084 			} else {
3666621Sbt150084 				/*
3676621Sbt150084 				 * Read operation is complete.  Get the data
3686621Sbt150084 				 * from MSRWD
3696621Sbt150084 				 */
3706621Sbt150084 				data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
3716621Sbt150084 				data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
3726621Sbt150084 				*phy_data = (u16)(data);
3736621Sbt150084 			}
3746621Sbt150084 		}
3756621Sbt150084 
3766621Sbt150084 		ixgbe_release_swfw_sync(hw, gssr);
3776621Sbt150084 	}
3786621Sbt150084 
3796621Sbt150084 	return (status);
3806621Sbt150084 }
3816621Sbt150084 
3826621Sbt150084 /*
3836621Sbt150084  * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register
3846621Sbt150084  * @hw: pointer to hardware structure
3856621Sbt150084  * @reg_addr: 32 bit PHY register to write
3866621Sbt150084  * @device_type: 5 bit device type
3876621Sbt150084  * @phy_data: Data to write to the PHY register
3886621Sbt150084  */
ixgbe_write_phy_reg_generic(struct ixgbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)3896621Sbt150084 s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
3906621Sbt150084     u32 device_type, u16 phy_data)
3916621Sbt150084 {
3926621Sbt150084 	u32 command;
3936621Sbt150084 	u32 i;
3946621Sbt150084 	s32 status = IXGBE_SUCCESS;
3956621Sbt150084 	u16 gssr;
3966621Sbt150084 
39710998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_write_phy_reg_generic");
39810998SChenlu.Chen@Sun.COM 
3996621Sbt150084 	if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
4006621Sbt150084 		gssr = IXGBE_GSSR_PHY1_SM;
4016621Sbt150084 	else
4026621Sbt150084 		gssr = IXGBE_GSSR_PHY0_SM;
4036621Sbt150084 
4046621Sbt150084 	if (ixgbe_acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS)
4056621Sbt150084 		status = IXGBE_ERR_SWFW_SYNC;
4066621Sbt150084 
4076621Sbt150084 	if (status == IXGBE_SUCCESS) {
4086621Sbt150084 		/*
4096621Sbt150084 		 * Put the data in the MDI single read and write data register
4106621Sbt150084 		 */
4116621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
4126621Sbt150084 
4136621Sbt150084 		/* Setup and write the address cycle command */
4146621Sbt150084 		command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
4156621Sbt150084 		    (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
4166621Sbt150084 		    (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
4176621Sbt150084 		    (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
4186621Sbt150084 
4196621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
4206621Sbt150084 
4216621Sbt150084 		/*
4226621Sbt150084 		 * Check every 10 usec to see if the address cycle completed.
4236621Sbt150084 		 * The MDI Command bit will clear when the operation is
4246621Sbt150084 		 * complete
4256621Sbt150084 		 */
4266621Sbt150084 		for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
4276621Sbt150084 			usec_delay(10);
4286621Sbt150084 
4296621Sbt150084 			command = IXGBE_READ_REG(hw, IXGBE_MSCA);
4306621Sbt150084 
4316621Sbt150084 			if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
4326621Sbt150084 				break;
4336621Sbt150084 		}
4346621Sbt150084 
4356621Sbt150084 		if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
4366621Sbt150084 			DEBUGOUT("PHY address cmd didn't complete\n");
4376621Sbt150084 			status = IXGBE_ERR_PHY;
4386621Sbt150084 		}
4396621Sbt150084 
4406621Sbt150084 		if (status == IXGBE_SUCCESS) {
4416621Sbt150084 			/*
4426621Sbt150084 			 * Address cycle complete, setup and write the write
4436621Sbt150084 			 * command
4446621Sbt150084 			 */
4456621Sbt150084 			command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
4466621Sbt150084 			    (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
4476621Sbt150084 			    (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
4486621Sbt150084 			    (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
4496621Sbt150084 
4506621Sbt150084 			IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
4516621Sbt150084 
4526621Sbt150084 			/*
4536621Sbt150084 			 * Check every 10 usec to see if the address cycle
4546621Sbt150084 			 * completed. The MDI Command bit will clear when the
4556621Sbt150084 			 * operation is complete
4566621Sbt150084 			 */
4576621Sbt150084 			for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
4586621Sbt150084 				usec_delay(10);
4596621Sbt150084 
4606621Sbt150084 				command = IXGBE_READ_REG(hw, IXGBE_MSCA);
4616621Sbt150084 
4626621Sbt150084 				if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
4636621Sbt150084 					break;
4646621Sbt150084 			}
4656621Sbt150084 
4666621Sbt150084 			if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
4676621Sbt150084 				DEBUGOUT("PHY address cmd didn't complete\n");
4686621Sbt150084 				status = IXGBE_ERR_PHY;
4696621Sbt150084 			}
4706621Sbt150084 		}
4716621Sbt150084 
4726621Sbt150084 		ixgbe_release_swfw_sync(hw, gssr);
4736621Sbt150084 	}
4746621Sbt150084 
4756621Sbt150084 	return (status);
4766621Sbt150084 }
4776621Sbt150084 
4786621Sbt150084 /*
4796621Sbt150084  * ixgbe_setup_phy_link_generic - Set and restart autoneg
4806621Sbt150084  * @hw: pointer to hardware structure
4816621Sbt150084  *
4826621Sbt150084  * Restart autonegotiation and PHY and waits for completion.
4836621Sbt150084  */
4846621Sbt150084 s32
ixgbe_setup_phy_link_generic(struct ixgbe_hw * hw)4856621Sbt150084 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
4866621Sbt150084 {
48710305SPaul.Guo@Sun.COM 	s32 status = IXGBE_SUCCESS;
4886621Sbt150084 	u32 time_out;
4896621Sbt150084 	u32 max_time_out = 10;
4906621Sbt150084 	u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
49110998SChenlu.Chen@Sun.COM 	bool autoneg = false;
49210998SChenlu.Chen@Sun.COM 	ixgbe_link_speed speed;
4936621Sbt150084 
49410998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_setup_phy_link_generic");
49510998SChenlu.Chen@Sun.COM 
49610998SChenlu.Chen@Sun.COM 	(void) ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg);
49710998SChenlu.Chen@Sun.COM 
49810998SChenlu.Chen@Sun.COM 	if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
49910998SChenlu.Chen@Sun.COM 		/* Set or unset auto-negotiation 10G advertisement */
50010998SChenlu.Chen@Sun.COM 		hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
50110998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
50210998SChenlu.Chen@Sun.COM 		    &autoneg_reg);
50310998SChenlu.Chen@Sun.COM 
50410998SChenlu.Chen@Sun.COM 		autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE;
50510998SChenlu.Chen@Sun.COM 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
50610998SChenlu.Chen@Sun.COM 			autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE;
50710998SChenlu.Chen@Sun.COM 
50810998SChenlu.Chen@Sun.COM 		hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
50910998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
51010998SChenlu.Chen@Sun.COM 		    autoneg_reg);
51110998SChenlu.Chen@Sun.COM 	}
5126621Sbt150084 
51310998SChenlu.Chen@Sun.COM 	if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
51410998SChenlu.Chen@Sun.COM 		/* Set or unset auto-negotiation 1G advertisement */
51510998SChenlu.Chen@Sun.COM 		hw->phy.ops.read_reg(hw,
51610998SChenlu.Chen@Sun.COM 		    IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
51710998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
51810998SChenlu.Chen@Sun.COM 		    &autoneg_reg);
51910998SChenlu.Chen@Sun.COM 
52010998SChenlu.Chen@Sun.COM 		autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE;
52110998SChenlu.Chen@Sun.COM 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
52210998SChenlu.Chen@Sun.COM 			autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE;
5236621Sbt150084 
52410998SChenlu.Chen@Sun.COM 		hw->phy.ops.write_reg(hw,
52510998SChenlu.Chen@Sun.COM 		    IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
52610998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
52710998SChenlu.Chen@Sun.COM 		    autoneg_reg);
52810998SChenlu.Chen@Sun.COM 	}
52910998SChenlu.Chen@Sun.COM 
53010998SChenlu.Chen@Sun.COM 	if (speed & IXGBE_LINK_SPEED_100_FULL) {
53110998SChenlu.Chen@Sun.COM 		/* Set or unset auto-negotiation 100M advertisement */
53210998SChenlu.Chen@Sun.COM 		hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
53310998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
53410998SChenlu.Chen@Sun.COM 		    &autoneg_reg);
53510998SChenlu.Chen@Sun.COM 
53610998SChenlu.Chen@Sun.COM 		autoneg_reg &= ~IXGBE_MII_100BASE_T_ADVERTISE;
53710998SChenlu.Chen@Sun.COM 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
53810998SChenlu.Chen@Sun.COM 			autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE;
53910998SChenlu.Chen@Sun.COM 
54010998SChenlu.Chen@Sun.COM 		hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
54110998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
54210998SChenlu.Chen@Sun.COM 		    autoneg_reg);
54310998SChenlu.Chen@Sun.COM 	}
5446621Sbt150084 
5456621Sbt150084 	/* Restart PHY autonegotiation and wait for completion */
5466621Sbt150084 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
5476621Sbt150084 	    IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
5486621Sbt150084 
5496621Sbt150084 	autoneg_reg |= IXGBE_MII_RESTART;
5506621Sbt150084 
5516621Sbt150084 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
5526621Sbt150084 	    IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
5536621Sbt150084 
5546621Sbt150084 	/* Wait for autonegotiation to finish */
5556621Sbt150084 	for (time_out = 0; time_out < max_time_out; time_out++) {
5566621Sbt150084 		usec_delay(10);
5576621Sbt150084 		/* Restart PHY autonegotiation and wait for completion */
5586621Sbt150084 		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
5596621Sbt150084 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
5606621Sbt150084 		    &autoneg_reg);
5616621Sbt150084 
5626621Sbt150084 		autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE;
5636621Sbt150084 		if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) {
5646621Sbt150084 			break;
5656621Sbt150084 		}
5666621Sbt150084 	}
5676621Sbt150084 
56810998SChenlu.Chen@Sun.COM 	if (time_out == max_time_out) {
5696621Sbt150084 		status = IXGBE_ERR_LINK_SETUP;
57010998SChenlu.Chen@Sun.COM 		DEBUGOUT("ixgbe_setup_phy_link_generic: time out");
57110998SChenlu.Chen@Sun.COM 	}
5726621Sbt150084 
5736621Sbt150084 	return (status);
5746621Sbt150084 }
5756621Sbt150084 
5766621Sbt150084 /*
5776621Sbt150084  * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities
5786621Sbt150084  * @hw: pointer to hardware structure
5796621Sbt150084  * @speed: new link speed
5808490SPaul.Guo@Sun.COM  * @autoneg: true if autonegotiation enabled
5816621Sbt150084  */
58210998SChenlu.Chen@Sun.COM s32
ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw * hw,ixgbe_link_speed speed,bool autoneg,bool autoneg_wait_to_complete)58310998SChenlu.Chen@Sun.COM ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
5846621Sbt150084     ixgbe_link_speed speed,
5856621Sbt150084     bool autoneg,
5866621Sbt150084     bool autoneg_wait_to_complete)
5876621Sbt150084 {
5886621Sbt150084 	UNREFERENCED_PARAMETER(autoneg);
5896621Sbt150084 	UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
5906621Sbt150084 
59110998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_setup_phy_link_speed_generic");
59210998SChenlu.Chen@Sun.COM 
5936621Sbt150084 	/*
5946621Sbt150084 	 * Clear autoneg_advertised and set new values based on input link
5956621Sbt150084 	 * speed.
5966621Sbt150084 	 */
5976621Sbt150084 	hw->phy.autoneg_advertised = 0;
5986621Sbt150084 
5996621Sbt150084 	if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
6006621Sbt150084 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
6016621Sbt150084 	}
60210305SPaul.Guo@Sun.COM 
6036621Sbt150084 	if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
6046621Sbt150084 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
6056621Sbt150084 	}
6066621Sbt150084 
60710305SPaul.Guo@Sun.COM 	if (speed & IXGBE_LINK_SPEED_100_FULL)
60810305SPaul.Guo@Sun.COM 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;
60910305SPaul.Guo@Sun.COM 
6106621Sbt150084 	/* Setup link based on the new speed settings */
6116621Sbt150084 	hw->phy.ops.setup_link(hw);
6126621Sbt150084 
6136621Sbt150084 	return (IXGBE_SUCCESS);
6146621Sbt150084 }
6158490SPaul.Guo@Sun.COM 
6168490SPaul.Guo@Sun.COM /*
6179353SSamuel.Tu@Sun.COM  * ixgbe_get_copper_link_capabilities_generic - Determines link capabilities
6189353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
6199353SSamuel.Tu@Sun.COM  * @speed: pointer to link speed
6209353SSamuel.Tu@Sun.COM  * @autoneg: boolean auto-negotiation value
6219353SSamuel.Tu@Sun.COM  *
6229353SSamuel.Tu@Sun.COM  * Determines the link capabilities by reading the AUTOC register.
6239353SSamuel.Tu@Sun.COM  */
62410998SChenlu.Chen@Sun.COM s32
ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw * hw,ixgbe_link_speed * speed,bool * autoneg)62510998SChenlu.Chen@Sun.COM ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
6269353SSamuel.Tu@Sun.COM     ixgbe_link_speed *speed, bool *autoneg)
6279353SSamuel.Tu@Sun.COM {
6289353SSamuel.Tu@Sun.COM 	s32 status = IXGBE_ERR_LINK_SETUP;
6299353SSamuel.Tu@Sun.COM 	u16 speed_ability;
6309353SSamuel.Tu@Sun.COM 
63110998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_get_copper_link_capabilities_generic");
63210998SChenlu.Chen@Sun.COM 
6339353SSamuel.Tu@Sun.COM 	*speed = 0;
6349353SSamuel.Tu@Sun.COM 	*autoneg = true;
6359353SSamuel.Tu@Sun.COM 
6369353SSamuel.Tu@Sun.COM 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
6379353SSamuel.Tu@Sun.COM 	    IXGBE_MDIO_PMA_PMD_DEV_TYPE, &speed_ability);
6389353SSamuel.Tu@Sun.COM 
6399353SSamuel.Tu@Sun.COM 	if (status == IXGBE_SUCCESS) {
6409353SSamuel.Tu@Sun.COM 		if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
6419353SSamuel.Tu@Sun.COM 			*speed |= IXGBE_LINK_SPEED_10GB_FULL;
6429353SSamuel.Tu@Sun.COM 		if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
6439353SSamuel.Tu@Sun.COM 			*speed |= IXGBE_LINK_SPEED_1GB_FULL;
64410305SPaul.Guo@Sun.COM 		if (speed_ability & IXGBE_MDIO_PHY_SPEED_100M)
64510305SPaul.Guo@Sun.COM 			*speed |= IXGBE_LINK_SPEED_100_FULL;
6469353SSamuel.Tu@Sun.COM 	}
6479353SSamuel.Tu@Sun.COM 
6489353SSamuel.Tu@Sun.COM 	return (status);
6499353SSamuel.Tu@Sun.COM }
6509353SSamuel.Tu@Sun.COM 
6519353SSamuel.Tu@Sun.COM /*
6528490SPaul.Guo@Sun.COM  * ixgbe_check_phy_link_tnx - Determine link and speed status
6538490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
6548490SPaul.Guo@Sun.COM  *
6558490SPaul.Guo@Sun.COM  * Reads the VS1 register to determine if link is up and the current speed for
6568490SPaul.Guo@Sun.COM  * the PHY.
6578490SPaul.Guo@Sun.COM  */
6588490SPaul.Guo@Sun.COM s32
ixgbe_check_phy_link_tnx(struct ixgbe_hw * hw,ixgbe_link_speed * speed,bool * link_up)6598490SPaul.Guo@Sun.COM ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
6608490SPaul.Guo@Sun.COM     bool *link_up)
6618490SPaul.Guo@Sun.COM {
6628490SPaul.Guo@Sun.COM 	s32 status = IXGBE_SUCCESS;
6638490SPaul.Guo@Sun.COM 	u32 time_out;
6648490SPaul.Guo@Sun.COM 	u32 max_time_out = 10;
6658490SPaul.Guo@Sun.COM 	u16 phy_link = 0;
6668490SPaul.Guo@Sun.COM 	u16 phy_speed = 0;
6678490SPaul.Guo@Sun.COM 	u16 phy_data = 0;
6688490SPaul.Guo@Sun.COM 
66910998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_check_phy_link_tnx");
67010998SChenlu.Chen@Sun.COM 
6718490SPaul.Guo@Sun.COM 	/* Initialize speed and link to default case */
6728490SPaul.Guo@Sun.COM 	*link_up = false;
6738490SPaul.Guo@Sun.COM 	*speed = IXGBE_LINK_SPEED_10GB_FULL;
6748490SPaul.Guo@Sun.COM 
6758490SPaul.Guo@Sun.COM 	/*
6768490SPaul.Guo@Sun.COM 	 * Check current speed and link status of the PHY register.
6778490SPaul.Guo@Sun.COM 	 * This is a vendor specific register and may have to
6788490SPaul.Guo@Sun.COM 	 * be changed for other copper PHYs.
6798490SPaul.Guo@Sun.COM 	 */
6808490SPaul.Guo@Sun.COM 	for (time_out = 0; time_out < max_time_out; time_out++) {
6818490SPaul.Guo@Sun.COM 		usec_delay(10);
6828490SPaul.Guo@Sun.COM 		status = hw->phy.ops.read_reg(hw,
6838490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
6848490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
6858490SPaul.Guo@Sun.COM 		    &phy_data);
6868490SPaul.Guo@Sun.COM 		phy_link = phy_data &
6878490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
6888490SPaul.Guo@Sun.COM 		phy_speed = phy_data &
6898490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
6908490SPaul.Guo@Sun.COM 		if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
6918490SPaul.Guo@Sun.COM 			*link_up = true;
6928490SPaul.Guo@Sun.COM 			if (phy_speed ==
6938490SPaul.Guo@Sun.COM 			    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
6948490SPaul.Guo@Sun.COM 				*speed = IXGBE_LINK_SPEED_1GB_FULL;
6958490SPaul.Guo@Sun.COM 			break;
6968490SPaul.Guo@Sun.COM 		}
6978490SPaul.Guo@Sun.COM 	}
6988490SPaul.Guo@Sun.COM 
6998490SPaul.Guo@Sun.COM 	return (status);
7008490SPaul.Guo@Sun.COM }
7018490SPaul.Guo@Sun.COM 
7028490SPaul.Guo@Sun.COM /*
70310998SChenlu.Chen@Sun.COM  * ixgbe_setup_phy_link_tnx - Set and restart autoneg
70410998SChenlu.Chen@Sun.COM  * @hw: pointer to hardware structure
70510998SChenlu.Chen@Sun.COM  *
70610998SChenlu.Chen@Sun.COM  * Restart autonegotiation and PHY and waits for completion.
70710998SChenlu.Chen@Sun.COM  */
70810998SChenlu.Chen@Sun.COM s32
ixgbe_setup_phy_link_tnx(struct ixgbe_hw * hw)70910998SChenlu.Chen@Sun.COM ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw)
71010998SChenlu.Chen@Sun.COM {
71110998SChenlu.Chen@Sun.COM 	s32 status = IXGBE_SUCCESS;
71210998SChenlu.Chen@Sun.COM 	u32 time_out;
71310998SChenlu.Chen@Sun.COM 	u32 max_time_out = 10;
71410998SChenlu.Chen@Sun.COM 	u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
71510998SChenlu.Chen@Sun.COM 	bool autoneg = false;
71610998SChenlu.Chen@Sun.COM 	ixgbe_link_speed speed;
71710998SChenlu.Chen@Sun.COM 
71810998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_setup_phy_link_tnx");
71910998SChenlu.Chen@Sun.COM 
72010998SChenlu.Chen@Sun.COM 	(void) ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg);
72110998SChenlu.Chen@Sun.COM 
72210998SChenlu.Chen@Sun.COM 	if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
72310998SChenlu.Chen@Sun.COM 		/* Set or unset auto-negotiation 10G advertisement */
72410998SChenlu.Chen@Sun.COM 		hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
72510998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
72610998SChenlu.Chen@Sun.COM 		    &autoneg_reg);
72710998SChenlu.Chen@Sun.COM 
72810998SChenlu.Chen@Sun.COM 		autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE;
72910998SChenlu.Chen@Sun.COM 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
73010998SChenlu.Chen@Sun.COM 			autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE;
73110998SChenlu.Chen@Sun.COM 
73210998SChenlu.Chen@Sun.COM 		hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
73310998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
73410998SChenlu.Chen@Sun.COM 		    autoneg_reg);
73510998SChenlu.Chen@Sun.COM 	}
73610998SChenlu.Chen@Sun.COM 
73710998SChenlu.Chen@Sun.COM 	if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
73810998SChenlu.Chen@Sun.COM 		/* Set or unset auto-negotiation 1G advertisement */
73910998SChenlu.Chen@Sun.COM 		hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG,
74010998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
74110998SChenlu.Chen@Sun.COM 		    &autoneg_reg);
74210998SChenlu.Chen@Sun.COM 
74310998SChenlu.Chen@Sun.COM 		autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX;
74410998SChenlu.Chen@Sun.COM 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
74510998SChenlu.Chen@Sun.COM 			autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX;
74610998SChenlu.Chen@Sun.COM 
74710998SChenlu.Chen@Sun.COM 		hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_XNP_TX_REG,
74810998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
74910998SChenlu.Chen@Sun.COM 		    autoneg_reg);
75010998SChenlu.Chen@Sun.COM 	}
75110998SChenlu.Chen@Sun.COM 
75210998SChenlu.Chen@Sun.COM 	if (speed & IXGBE_LINK_SPEED_100_FULL) {
75310998SChenlu.Chen@Sun.COM 		/* Set or unset auto-negotiation 100M advertisement */
75410998SChenlu.Chen@Sun.COM 		hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
75510998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
75610998SChenlu.Chen@Sun.COM 		    &autoneg_reg);
75710998SChenlu.Chen@Sun.COM 
75810998SChenlu.Chen@Sun.COM 		autoneg_reg &= ~IXGBE_MII_100BASE_T_ADVERTISE;
75910998SChenlu.Chen@Sun.COM 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
76010998SChenlu.Chen@Sun.COM 			autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE;
76110998SChenlu.Chen@Sun.COM 
76210998SChenlu.Chen@Sun.COM 		hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
76310998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
76410998SChenlu.Chen@Sun.COM 		    autoneg_reg);
76510998SChenlu.Chen@Sun.COM 	}
76610998SChenlu.Chen@Sun.COM 
76710998SChenlu.Chen@Sun.COM 	/* Restart PHY autonegotiation and wait for completion */
76810998SChenlu.Chen@Sun.COM 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
76910998SChenlu.Chen@Sun.COM 	    IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
77010998SChenlu.Chen@Sun.COM 
77110998SChenlu.Chen@Sun.COM 	autoneg_reg |= IXGBE_MII_RESTART;
77210998SChenlu.Chen@Sun.COM 
77310998SChenlu.Chen@Sun.COM 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
77410998SChenlu.Chen@Sun.COM 	    IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
77510998SChenlu.Chen@Sun.COM 
77610998SChenlu.Chen@Sun.COM 	/* Wait for autonegotiation to finish */
77710998SChenlu.Chen@Sun.COM 	for (time_out = 0; time_out < max_time_out; time_out++) {
77810998SChenlu.Chen@Sun.COM 		usec_delay(10);
77910998SChenlu.Chen@Sun.COM 		/* Restart PHY autonegotiation and wait for completion */
78010998SChenlu.Chen@Sun.COM 		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
78110998SChenlu.Chen@Sun.COM 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
78210998SChenlu.Chen@Sun.COM 		    &autoneg_reg);
78310998SChenlu.Chen@Sun.COM 
78410998SChenlu.Chen@Sun.COM 		autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE;
78510998SChenlu.Chen@Sun.COM 		if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) {
78610998SChenlu.Chen@Sun.COM 			break;
78710998SChenlu.Chen@Sun.COM 		}
78810998SChenlu.Chen@Sun.COM 	}
78910998SChenlu.Chen@Sun.COM 
79010998SChenlu.Chen@Sun.COM 	if (time_out == max_time_out) {
79110998SChenlu.Chen@Sun.COM 		status = IXGBE_ERR_LINK_SETUP;
79210998SChenlu.Chen@Sun.COM 		DEBUGOUT("ixgbe_setup_phy_link_tnx: time out");
79310998SChenlu.Chen@Sun.COM 	}
79410998SChenlu.Chen@Sun.COM 
79510998SChenlu.Chen@Sun.COM 	return (status);
79610998SChenlu.Chen@Sun.COM }
79710998SChenlu.Chen@Sun.COM 
79810998SChenlu.Chen@Sun.COM /*
7998490SPaul.Guo@Sun.COM  * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version
8008490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
8018490SPaul.Guo@Sun.COM  * @firmware_version: pointer to the PHY Firmware Version
8028490SPaul.Guo@Sun.COM  */
8038490SPaul.Guo@Sun.COM s32
ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw * hw,u16 * firmware_version)8048490SPaul.Guo@Sun.COM ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, u16 *firmware_version)
8058490SPaul.Guo@Sun.COM {
8068490SPaul.Guo@Sun.COM 	s32 status = IXGBE_SUCCESS;
8078490SPaul.Guo@Sun.COM 
80810998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_get_phy_firmware_version_tnx");
80910998SChenlu.Chen@Sun.COM 
8108490SPaul.Guo@Sun.COM 	status = hw->phy.ops.read_reg(hw, TNX_FW_REV,
8118490SPaul.Guo@Sun.COM 	    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, firmware_version);
8128490SPaul.Guo@Sun.COM 
8138490SPaul.Guo@Sun.COM 	return (status);
8148490SPaul.Guo@Sun.COM }
8158490SPaul.Guo@Sun.COM 
8168490SPaul.Guo@Sun.COM /*
81710998SChenlu.Chen@Sun.COM  * ixgbe_get_phy_firmware_version_generic - Gets the PHY Firmware Version
81810305SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
81910305SPaul.Guo@Sun.COM  * @firmware_version: pointer to the PHY Firmware Version
82010305SPaul.Guo@Sun.COM  */
82110305SPaul.Guo@Sun.COM s32
ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw * hw,u16 * firmware_version)82210998SChenlu.Chen@Sun.COM ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw,
82310998SChenlu.Chen@Sun.COM     u16 *firmware_version)
82410305SPaul.Guo@Sun.COM {
82510305SPaul.Guo@Sun.COM 	s32 status = IXGBE_SUCCESS;
82610305SPaul.Guo@Sun.COM 
82710998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_get_phy_firmware_version_generic");
82810998SChenlu.Chen@Sun.COM 
82910305SPaul.Guo@Sun.COM 	status = hw->phy.ops.read_reg(hw, AQ_FW_REV,
83010305SPaul.Guo@Sun.COM 	    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, firmware_version);
83110305SPaul.Guo@Sun.COM 
83210305SPaul.Guo@Sun.COM 	return (status);
83310305SPaul.Guo@Sun.COM }
83410305SPaul.Guo@Sun.COM 
83510305SPaul.Guo@Sun.COM /*
8368490SPaul.Guo@Sun.COM  * ixgbe_reset_phy_nl - Performs a PHY reset
8378490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
8388490SPaul.Guo@Sun.COM  */
8398490SPaul.Guo@Sun.COM s32
ixgbe_reset_phy_nl(struct ixgbe_hw * hw)8408490SPaul.Guo@Sun.COM ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
8418490SPaul.Guo@Sun.COM {
8428490SPaul.Guo@Sun.COM 	u16 phy_offset, control, eword, edata, block_crc;
8438490SPaul.Guo@Sun.COM 	bool end_data = false;
8448490SPaul.Guo@Sun.COM 	u16 list_offset, data_offset;
8458490SPaul.Guo@Sun.COM 	u16 phy_data = 0;
8468490SPaul.Guo@Sun.COM 	s32 ret_val = IXGBE_SUCCESS;
8478490SPaul.Guo@Sun.COM 	u32 i;
8488490SPaul.Guo@Sun.COM 
84910998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_reset_phy_nl");
85010998SChenlu.Chen@Sun.COM 
8518490SPaul.Guo@Sun.COM 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
8528490SPaul.Guo@Sun.COM 	    IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
8538490SPaul.Guo@Sun.COM 
8548490SPaul.Guo@Sun.COM 	/* reset the PHY and poll for completion */
8558490SPaul.Guo@Sun.COM 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
8568490SPaul.Guo@Sun.COM 	    IXGBE_MDIO_PHY_XS_DEV_TYPE,
8578490SPaul.Guo@Sun.COM 	    (phy_data | IXGBE_MDIO_PHY_XS_RESET));
8588490SPaul.Guo@Sun.COM 
8598490SPaul.Guo@Sun.COM 	for (i = 0; i < 100; i++) {
8608490SPaul.Guo@Sun.COM 		hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
8618490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
8628490SPaul.Guo@Sun.COM 		if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0)
8638490SPaul.Guo@Sun.COM 			break;
8648490SPaul.Guo@Sun.COM 		msec_delay(10);
8658490SPaul.Guo@Sun.COM 	}
8668490SPaul.Guo@Sun.COM 
8678490SPaul.Guo@Sun.COM 	if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) {
8688490SPaul.Guo@Sun.COM 		DEBUGOUT("PHY reset did not complete.\n");
8698490SPaul.Guo@Sun.COM 		ret_val = IXGBE_ERR_PHY;
8708490SPaul.Guo@Sun.COM 		goto out;
8718490SPaul.Guo@Sun.COM 	}
8728490SPaul.Guo@Sun.COM 
8738490SPaul.Guo@Sun.COM 	/* Get init offsets */
8748490SPaul.Guo@Sun.COM 	ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
8758490SPaul.Guo@Sun.COM 	    &data_offset);
8768490SPaul.Guo@Sun.COM 	if (ret_val != IXGBE_SUCCESS)
8778490SPaul.Guo@Sun.COM 		goto out;
8788490SPaul.Guo@Sun.COM 
8798490SPaul.Guo@Sun.COM 	ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc);
8808490SPaul.Guo@Sun.COM 	data_offset++;
8818490SPaul.Guo@Sun.COM 	while (!end_data) {
8828490SPaul.Guo@Sun.COM 		/*
8838490SPaul.Guo@Sun.COM 		 * Read control word from PHY init contents offset
8848490SPaul.Guo@Sun.COM 		 */
8858490SPaul.Guo@Sun.COM 		ret_val = hw->eeprom.ops.read(hw, data_offset, &eword);
8868490SPaul.Guo@Sun.COM 		control = (eword & IXGBE_CONTROL_MASK_NL) >>
8878490SPaul.Guo@Sun.COM 		    IXGBE_CONTROL_SHIFT_NL;
8888490SPaul.Guo@Sun.COM 		edata = eword & IXGBE_DATA_MASK_NL;
8898490SPaul.Guo@Sun.COM 		switch (control) {
8908490SPaul.Guo@Sun.COM 		case IXGBE_DELAY_NL:
8918490SPaul.Guo@Sun.COM 			data_offset++;
8928490SPaul.Guo@Sun.COM 			DEBUGOUT1("DELAY: %d MS\n", edata);
8938490SPaul.Guo@Sun.COM 			msec_delay(edata);
8948490SPaul.Guo@Sun.COM 			break;
8958490SPaul.Guo@Sun.COM 		case IXGBE_DATA_NL:
8968490SPaul.Guo@Sun.COM 			DEBUGOUT("DATA:  \n");
8978490SPaul.Guo@Sun.COM 			data_offset++;
8988490SPaul.Guo@Sun.COM 			hw->eeprom.ops.read(hw, data_offset++, &phy_offset);
8998490SPaul.Guo@Sun.COM 			for (i = 0; i < edata; i++) {
9008490SPaul.Guo@Sun.COM 				hw->eeprom.ops.read(hw, data_offset, &eword);
9018490SPaul.Guo@Sun.COM 				hw->phy.ops.write_reg(hw, phy_offset,
9028490SPaul.Guo@Sun.COM 				    IXGBE_TWINAX_DEV, eword);
9038490SPaul.Guo@Sun.COM 				DEBUGOUT2("Wrote %4.4x to %4.4x\n", eword,
9048490SPaul.Guo@Sun.COM 				    phy_offset);
9058490SPaul.Guo@Sun.COM 				data_offset++;
9068490SPaul.Guo@Sun.COM 				phy_offset++;
9078490SPaul.Guo@Sun.COM 			}
9088490SPaul.Guo@Sun.COM 			break;
9098490SPaul.Guo@Sun.COM 		case IXGBE_CONTROL_NL:
9108490SPaul.Guo@Sun.COM 			data_offset++;
9118490SPaul.Guo@Sun.COM 			DEBUGOUT("CONTROL: \n");
9128490SPaul.Guo@Sun.COM 			if (edata == IXGBE_CONTROL_EOL_NL) {
9138490SPaul.Guo@Sun.COM 				DEBUGOUT("EOL\n");
9148490SPaul.Guo@Sun.COM 				end_data = true;
9158490SPaul.Guo@Sun.COM 			} else if (edata == IXGBE_CONTROL_SOL_NL) {
9168490SPaul.Guo@Sun.COM 				DEBUGOUT("SOL\n");
9178490SPaul.Guo@Sun.COM 			} else {
9188490SPaul.Guo@Sun.COM 				DEBUGOUT("Bad control value\n");
9198490SPaul.Guo@Sun.COM 				ret_val = IXGBE_ERR_PHY;
9208490SPaul.Guo@Sun.COM 				goto out;
9218490SPaul.Guo@Sun.COM 			}
9228490SPaul.Guo@Sun.COM 			break;
9238490SPaul.Guo@Sun.COM 		default:
9248490SPaul.Guo@Sun.COM 			DEBUGOUT("Bad control type\n");
9258490SPaul.Guo@Sun.COM 			ret_val = IXGBE_ERR_PHY;
9268490SPaul.Guo@Sun.COM 			goto out;
9278490SPaul.Guo@Sun.COM 		}
9288490SPaul.Guo@Sun.COM 	}
9298490SPaul.Guo@Sun.COM 
9308490SPaul.Guo@Sun.COM out:
9318490SPaul.Guo@Sun.COM 	return (ret_val);
9328490SPaul.Guo@Sun.COM }
9338490SPaul.Guo@Sun.COM 
9348490SPaul.Guo@Sun.COM /*
9359353SSamuel.Tu@Sun.COM  * ixgbe_identify_sfp_module_generic - Identifies SFP module
9368490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
9378490SPaul.Guo@Sun.COM  *
9389353SSamuel.Tu@Sun.COM  * Searches for and identifies the SFP module and assigns appropriate PHY type.
9398490SPaul.Guo@Sun.COM  */
9408490SPaul.Guo@Sun.COM s32
ixgbe_identify_sfp_module_generic(struct ixgbe_hw * hw)9418490SPaul.Guo@Sun.COM ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
9428490SPaul.Guo@Sun.COM {
9438490SPaul.Guo@Sun.COM 	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
9448490SPaul.Guo@Sun.COM 	u32 vendor_oui = 0;
9459353SSamuel.Tu@Sun.COM 	enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
9468490SPaul.Guo@Sun.COM 	u8 identifier = 0;
9478490SPaul.Guo@Sun.COM 	u8 comp_codes_1g = 0;
9488490SPaul.Guo@Sun.COM 	u8 comp_codes_10g = 0;
9499353SSamuel.Tu@Sun.COM 	u8 oui_bytes[3] = {0, 0, 0};
95010305SPaul.Guo@Sun.COM 	u8 cable_tech = 0;
951*13006SChenlu.Chen@Sun.COM 	u8 cable_spec = 0;
9529353SSamuel.Tu@Sun.COM 	u16 enforce_sfp = 0;
9538490SPaul.Guo@Sun.COM 
95410998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_identify_sfp_module_generic");
95510998SChenlu.Chen@Sun.COM 
95610305SPaul.Guo@Sun.COM 	if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) {
95710305SPaul.Guo@Sun.COM 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
95810305SPaul.Guo@Sun.COM 		status = IXGBE_ERR_SFP_NOT_PRESENT;
95910305SPaul.Guo@Sun.COM 		goto out;
96010305SPaul.Guo@Sun.COM 	}
96110305SPaul.Guo@Sun.COM 
9628490SPaul.Guo@Sun.COM 	status = hw->phy.ops.read_i2c_eeprom(hw,
9638490SPaul.Guo@Sun.COM 	    IXGBE_SFF_IDENTIFIER, &identifier);
9648490SPaul.Guo@Sun.COM 
9659353SSamuel.Tu@Sun.COM 	if (status == IXGBE_ERR_SFP_NOT_PRESENT || status == IXGBE_ERR_I2C) {
9669353SSamuel.Tu@Sun.COM 		status = IXGBE_ERR_SFP_NOT_PRESENT;
9678490SPaul.Guo@Sun.COM 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
9689353SSamuel.Tu@Sun.COM 		if (hw->phy.type != ixgbe_phy_nl) {
9699353SSamuel.Tu@Sun.COM 			hw->phy.id = 0;
9709353SSamuel.Tu@Sun.COM 			hw->phy.type = ixgbe_phy_unknown;
9719353SSamuel.Tu@Sun.COM 		}
9728490SPaul.Guo@Sun.COM 		goto out;
9738490SPaul.Guo@Sun.COM 	}
9748490SPaul.Guo@Sun.COM 
9759353SSamuel.Tu@Sun.COM 	/* LAN ID is needed for sfp_type determination */
9769353SSamuel.Tu@Sun.COM 	hw->mac.ops.set_lan_id(hw);
9779353SSamuel.Tu@Sun.COM 
97810305SPaul.Guo@Sun.COM 	if (identifier != IXGBE_SFF_IDENTIFIER_SFP) {
97910305SPaul.Guo@Sun.COM 		hw->phy.type = ixgbe_phy_sfp_unsupported;
98010305SPaul.Guo@Sun.COM 		status = IXGBE_ERR_SFP_NOT_SUPPORTED;
98110305SPaul.Guo@Sun.COM 	} else {
9828490SPaul.Guo@Sun.COM 		hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES,
9838490SPaul.Guo@Sun.COM 		    &comp_codes_1g);
9848490SPaul.Guo@Sun.COM 		hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES,
9858490SPaul.Guo@Sun.COM 		    &comp_codes_10g);
98610305SPaul.Guo@Sun.COM 		hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_CABLE_TECHNOLOGY,
98710305SPaul.Guo@Sun.COM 		    &cable_tech);
9888490SPaul.Guo@Sun.COM 
9898490SPaul.Guo@Sun.COM 		/*
9908490SPaul.Guo@Sun.COM 		 * ID  Module
9918490SPaul.Guo@Sun.COM 		 * ============
9928490SPaul.Guo@Sun.COM 		 * 0    SFP_DA_CU
9938490SPaul.Guo@Sun.COM 		 * 1    SFP_SR
9948490SPaul.Guo@Sun.COM 		 * 2    SFP_LR
9959353SSamuel.Tu@Sun.COM 		 * 3	SFP_DA_CORE0 - 82599-specific
9969353SSamuel.Tu@Sun.COM 		 * 4	SFP_DA_CORE1 - 82599-specific
9979353SSamuel.Tu@Sun.COM 		 * 5	SFP_SR/LR_CORE0 - 82599-specific
9989353SSamuel.Tu@Sun.COM 		 * 6	SFP_SR/LR_CORE1 - 82599-specific
999*13006SChenlu.Chen@Sun.COM 		 * 7	SFP_act_lmt_DA_CORE0 - 82599-specific
1000*13006SChenlu.Chen@Sun.COM 		 * 8	SFP_act_lmt_DA_CORE1 - 82599-specific
1001*13006SChenlu.Chen@Sun.COM 		 * 9	SFP_1g_cu_CORE0 - 82599-specific
1002*13006SChenlu.Chen@Sun.COM 		 * 10	SFP_1g_cu_CORE1 - 82599-specific
10038490SPaul.Guo@Sun.COM 		 */
10049353SSamuel.Tu@Sun.COM 		if (hw->mac.type == ixgbe_mac_82598EB) {
100510305SPaul.Guo@Sun.COM 			if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
10069353SSamuel.Tu@Sun.COM 				hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
10079353SSamuel.Tu@Sun.COM 			else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
10089353SSamuel.Tu@Sun.COM 				hw->phy.sfp_type = ixgbe_sfp_type_sr;
10099353SSamuel.Tu@Sun.COM 			else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
10109353SSamuel.Tu@Sun.COM 				hw->phy.sfp_type = ixgbe_sfp_type_lr;
10119353SSamuel.Tu@Sun.COM 			else
10129353SSamuel.Tu@Sun.COM 				hw->phy.sfp_type = ixgbe_sfp_type_unknown;
10139353SSamuel.Tu@Sun.COM 		} else if (hw->mac.type == ixgbe_mac_82599EB) {
1014*13006SChenlu.Chen@Sun.COM 			if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) {
10159353SSamuel.Tu@Sun.COM 				if (hw->bus.lan_id == 0)
10169353SSamuel.Tu@Sun.COM 					hw->phy.sfp_type =
10179353SSamuel.Tu@Sun.COM 					    ixgbe_sfp_type_da_cu_core0;
10189353SSamuel.Tu@Sun.COM 				else
10199353SSamuel.Tu@Sun.COM 					hw->phy.sfp_type =
10209353SSamuel.Tu@Sun.COM 					    ixgbe_sfp_type_da_cu_core1;
1021*13006SChenlu.Chen@Sun.COM 			} else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) {
1022*13006SChenlu.Chen@Sun.COM 				hw->phy.ops.read_i2c_eeprom(
1023*13006SChenlu.Chen@Sun.COM 				    hw, IXGBE_SFF_CABLE_SPEC_COMP, &cable_spec);
1024*13006SChenlu.Chen@Sun.COM 				if (cable_spec &
1025*13006SChenlu.Chen@Sun.COM 				    IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) {
1026*13006SChenlu.Chen@Sun.COM 					if (hw->bus.lan_id == 0)
1027*13006SChenlu.Chen@Sun.COM 					hw->phy.sfp_type =
1028*13006SChenlu.Chen@Sun.COM 					    ixgbe_sfp_type_da_act_lmt_core0;
1029*13006SChenlu.Chen@Sun.COM 					else
1030*13006SChenlu.Chen@Sun.COM 					hw->phy.sfp_type =
1031*13006SChenlu.Chen@Sun.COM 					    ixgbe_sfp_type_da_act_lmt_core1;
1032*13006SChenlu.Chen@Sun.COM 				} else
1033*13006SChenlu.Chen@Sun.COM 					hw->phy.sfp_type =
1034*13006SChenlu.Chen@Sun.COM 					    ixgbe_sfp_type_unknown;
1035*13006SChenlu.Chen@Sun.COM 			} else if (comp_codes_10g &
1036*13006SChenlu.Chen@Sun.COM 			    (IXGBE_SFF_10GBASESR_CAPABLE |
1037*13006SChenlu.Chen@Sun.COM 			    IXGBE_SFF_10GBASELR_CAPABLE)) {
10389353SSamuel.Tu@Sun.COM 				if (hw->bus.lan_id == 0)
10399353SSamuel.Tu@Sun.COM 					hw->phy.sfp_type =
10409353SSamuel.Tu@Sun.COM 					    ixgbe_sfp_type_srlr_core0;
10419353SSamuel.Tu@Sun.COM 				else
10429353SSamuel.Tu@Sun.COM 					hw->phy.sfp_type =
10439353SSamuel.Tu@Sun.COM 					    ixgbe_sfp_type_srlr_core1;
1044*13006SChenlu.Chen@Sun.COM 			} else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) {
10459353SSamuel.Tu@Sun.COM 				if (hw->bus.lan_id == 0)
10469353SSamuel.Tu@Sun.COM 					hw->phy.sfp_type =
1047*13006SChenlu.Chen@Sun.COM 					    ixgbe_sfp_type_1g_cu_core0;
10489353SSamuel.Tu@Sun.COM 				else
10499353SSamuel.Tu@Sun.COM 					hw->phy.sfp_type =
1050*13006SChenlu.Chen@Sun.COM 					    ixgbe_sfp_type_1g_cu_core1;
1051*13006SChenlu.Chen@Sun.COM 			} else {
10529353SSamuel.Tu@Sun.COM 				hw->phy.sfp_type = ixgbe_sfp_type_unknown;
1053*13006SChenlu.Chen@Sun.COM 			}
10549353SSamuel.Tu@Sun.COM 		}
10559353SSamuel.Tu@Sun.COM 
10569353SSamuel.Tu@Sun.COM 		if (hw->phy.sfp_type != stored_sfp_type)
10579353SSamuel.Tu@Sun.COM 			hw->phy.sfp_setup_needed = true;
10589353SSamuel.Tu@Sun.COM 
10599353SSamuel.Tu@Sun.COM 		/* Determine if the SFP+ PHY is dual speed or not. */
106010305SPaul.Guo@Sun.COM 		hw->phy.multispeed_fiber = false;
10619353SSamuel.Tu@Sun.COM 		if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) &&
10629353SSamuel.Tu@Sun.COM 		    (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) ||
10639353SSamuel.Tu@Sun.COM 		    ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) &&
10649353SSamuel.Tu@Sun.COM 		    (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)))
10659353SSamuel.Tu@Sun.COM 			hw->phy.multispeed_fiber = true;
10668490SPaul.Guo@Sun.COM 
10678490SPaul.Guo@Sun.COM 		/* Determine PHY vendor */
10689353SSamuel.Tu@Sun.COM 		if (hw->phy.type != ixgbe_phy_nl) {
10698490SPaul.Guo@Sun.COM 			hw->phy.id = identifier;
10708490SPaul.Guo@Sun.COM 			hw->phy.ops.read_i2c_eeprom(hw,
10718490SPaul.Guo@Sun.COM 			    IXGBE_SFF_VENDOR_OUI_BYTE0, &oui_bytes[0]);
10728490SPaul.Guo@Sun.COM 			hw->phy.ops.read_i2c_eeprom(hw,
10738490SPaul.Guo@Sun.COM 			    IXGBE_SFF_VENDOR_OUI_BYTE1, &oui_bytes[1]);
10748490SPaul.Guo@Sun.COM 			hw->phy.ops.read_i2c_eeprom(hw,
10758490SPaul.Guo@Sun.COM 			    IXGBE_SFF_VENDOR_OUI_BYTE2, &oui_bytes[2]);
10768490SPaul.Guo@Sun.COM 
10778490SPaul.Guo@Sun.COM 			vendor_oui =
10788490SPaul.Guo@Sun.COM 			    ((oui_bytes[0] <<
10798490SPaul.Guo@Sun.COM 			    IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
10808490SPaul.Guo@Sun.COM 			    (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
10818490SPaul.Guo@Sun.COM 			    (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
10828490SPaul.Guo@Sun.COM 
10838490SPaul.Guo@Sun.COM 			switch (vendor_oui) {
10848490SPaul.Guo@Sun.COM 			case IXGBE_SFF_VENDOR_OUI_TYCO:
108510305SPaul.Guo@Sun.COM 				if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
1086*13006SChenlu.Chen@Sun.COM 					hw->phy.type =
1087*13006SChenlu.Chen@Sun.COM 					    ixgbe_phy_sfp_passive_tyco;
10888490SPaul.Guo@Sun.COM 				break;
10898490SPaul.Guo@Sun.COM 			case IXGBE_SFF_VENDOR_OUI_FTL:
1090*13006SChenlu.Chen@Sun.COM 				if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
1091*13006SChenlu.Chen@Sun.COM 					hw->phy.type = ixgbe_phy_sfp_ftl_active;
1092*13006SChenlu.Chen@Sun.COM 				else
1093*13006SChenlu.Chen@Sun.COM 					hw->phy.type = ixgbe_phy_sfp_ftl;
10948490SPaul.Guo@Sun.COM 				break;
10958490SPaul.Guo@Sun.COM 			case IXGBE_SFF_VENDOR_OUI_AVAGO:
10968490SPaul.Guo@Sun.COM 				hw->phy.type = ixgbe_phy_sfp_avago;
10978490SPaul.Guo@Sun.COM 				break;
10989353SSamuel.Tu@Sun.COM 			case IXGBE_SFF_VENDOR_OUI_INTEL:
10999353SSamuel.Tu@Sun.COM 				hw->phy.type = ixgbe_phy_sfp_intel;
11009353SSamuel.Tu@Sun.COM 				break;
11018490SPaul.Guo@Sun.COM 			default:
110210305SPaul.Guo@Sun.COM 				if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
1103*13006SChenlu.Chen@Sun.COM 					hw->phy.type =
1104*13006SChenlu.Chen@Sun.COM 					    ixgbe_phy_sfp_passive_unknown;
1105*13006SChenlu.Chen@Sun.COM 				else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
1106*13006SChenlu.Chen@Sun.COM 					hw->phy.type =
1107*13006SChenlu.Chen@Sun.COM 					    ixgbe_phy_sfp_active_unknown;
11088490SPaul.Guo@Sun.COM 				else
11098490SPaul.Guo@Sun.COM 					hw->phy.type = ixgbe_phy_sfp_unknown;
11108490SPaul.Guo@Sun.COM 				break;
11118490SPaul.Guo@Sun.COM 			}
11128490SPaul.Guo@Sun.COM 		}
11139353SSamuel.Tu@Sun.COM 
1114*13006SChenlu.Chen@Sun.COM 		/* Allow any DA cable vendor */
1115*13006SChenlu.Chen@Sun.COM 		if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE |
1116*13006SChenlu.Chen@Sun.COM 		    IXGBE_SFF_DA_ACTIVE_CABLE)) {
111710305SPaul.Guo@Sun.COM 			status = IXGBE_SUCCESS;
111810305SPaul.Guo@Sun.COM 			goto out;
111910305SPaul.Guo@Sun.COM 		}
112010305SPaul.Guo@Sun.COM 
1121*13006SChenlu.Chen@Sun.COM 		/* Verify supporteed 1G SFP modules */
1122*13006SChenlu.Chen@Sun.COM 		if (comp_codes_10g == 0 &&
1123*13006SChenlu.Chen@Sun.COM 		    !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
1124*13006SChenlu.Chen@Sun.COM 		    hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0)) {
112510305SPaul.Guo@Sun.COM 			hw->phy.type = ixgbe_phy_sfp_unsupported;
112610305SPaul.Guo@Sun.COM 			status = IXGBE_ERR_SFP_NOT_SUPPORTED;
112710305SPaul.Guo@Sun.COM 			goto out;
112810305SPaul.Guo@Sun.COM 		}
112910305SPaul.Guo@Sun.COM 
113010305SPaul.Guo@Sun.COM 		/* Anything else 82598-based is supported */
113110305SPaul.Guo@Sun.COM 		if (hw->mac.type == ixgbe_mac_82598EB) {
11329353SSamuel.Tu@Sun.COM 			status = IXGBE_SUCCESS;
11339353SSamuel.Tu@Sun.COM 			goto out;
11349353SSamuel.Tu@Sun.COM 		}
11359353SSamuel.Tu@Sun.COM 
11369353SSamuel.Tu@Sun.COM 		(void) ixgbe_get_device_caps(hw, &enforce_sfp);
1137*13006SChenlu.Chen@Sun.COM 		if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) &&
1138*13006SChenlu.Chen@Sun.COM 		    !((hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0) ||
1139*13006SChenlu.Chen@Sun.COM 		    (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1))) {
11409353SSamuel.Tu@Sun.COM 			/* Make sure we're a supported PHY type */
11419353SSamuel.Tu@Sun.COM 			if (hw->phy.type == ixgbe_phy_sfp_intel) {
11429353SSamuel.Tu@Sun.COM 				status = IXGBE_SUCCESS;
11439353SSamuel.Tu@Sun.COM 			} else {
11449353SSamuel.Tu@Sun.COM 				DEBUGOUT("SFP+ module not supported\n");
11459353SSamuel.Tu@Sun.COM 				hw->phy.type = ixgbe_phy_sfp_unsupported;
11469353SSamuel.Tu@Sun.COM 				status = IXGBE_ERR_SFP_NOT_SUPPORTED;
11479353SSamuel.Tu@Sun.COM 			}
11489353SSamuel.Tu@Sun.COM 		} else {
11499353SSamuel.Tu@Sun.COM 			status = IXGBE_SUCCESS;
11509353SSamuel.Tu@Sun.COM 		}
11518490SPaul.Guo@Sun.COM 	}
11528490SPaul.Guo@Sun.COM 
11538490SPaul.Guo@Sun.COM out:
11548490SPaul.Guo@Sun.COM 	return (status);
11558490SPaul.Guo@Sun.COM }
11568490SPaul.Guo@Sun.COM 
11578490SPaul.Guo@Sun.COM 
11588490SPaul.Guo@Sun.COM /*
11599353SSamuel.Tu@Sun.COM  * ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence
11608490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
11618490SPaul.Guo@Sun.COM  * @list_offset: offset to the SFP ID list
11628490SPaul.Guo@Sun.COM  * @data_offset: offset to the SFP data block
11639353SSamuel.Tu@Sun.COM  *
11649353SSamuel.Tu@Sun.COM  * Checks the MAC's EEPROM to see if it supports a given SFP+ module type, if
11659353SSamuel.Tu@Sun.COM  * so it returns the offsets to the phy init sequence block.
11668490SPaul.Guo@Sun.COM  */
ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw * hw,u16 * list_offset,u16 * data_offset)11678490SPaul.Guo@Sun.COM s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
11688490SPaul.Guo@Sun.COM     u16 *list_offset, u16 *data_offset)
11698490SPaul.Guo@Sun.COM {
11708490SPaul.Guo@Sun.COM 	u16 sfp_id;
1171*13006SChenlu.Chen@Sun.COM 	u16 sfp_type = hw->phy.sfp_type;
11728490SPaul.Guo@Sun.COM 
117310998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_get_sfp_init_sequence_offsets");
117410998SChenlu.Chen@Sun.COM 
11758490SPaul.Guo@Sun.COM 	if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
11768490SPaul.Guo@Sun.COM 		return (IXGBE_ERR_SFP_NOT_SUPPORTED);
11778490SPaul.Guo@Sun.COM 
11788490SPaul.Guo@Sun.COM 	if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
11798490SPaul.Guo@Sun.COM 		return (IXGBE_ERR_SFP_NOT_PRESENT);
11808490SPaul.Guo@Sun.COM 
11818490SPaul.Guo@Sun.COM 	if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) &&
11828490SPaul.Guo@Sun.COM 	    (hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
11838490SPaul.Guo@Sun.COM 		return (IXGBE_ERR_SFP_NOT_SUPPORTED);
11848490SPaul.Guo@Sun.COM 
1185*13006SChenlu.Chen@Sun.COM 	/*
1186*13006SChenlu.Chen@Sun.COM 	 * Limiting active cables and 1G Phys must be initialized as
1187*13006SChenlu.Chen@Sun.COM 	 * SR modules
1188*13006SChenlu.Chen@Sun.COM 	 */
1189*13006SChenlu.Chen@Sun.COM 	if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
1190*13006SChenlu.Chen@Sun.COM 	    sfp_type == ixgbe_sfp_type_1g_cu_core0)
1191*13006SChenlu.Chen@Sun.COM 		sfp_type = ixgbe_sfp_type_srlr_core0;
1192*13006SChenlu.Chen@Sun.COM 	else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
1193*13006SChenlu.Chen@Sun.COM 	    sfp_type == ixgbe_sfp_type_1g_cu_core1)
1194*13006SChenlu.Chen@Sun.COM 		sfp_type = ixgbe_sfp_type_srlr_core1;
1195*13006SChenlu.Chen@Sun.COM 
11968490SPaul.Guo@Sun.COM 	/* Read offset to PHY init contents */
11978490SPaul.Guo@Sun.COM 	hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset);
11988490SPaul.Guo@Sun.COM 
11998490SPaul.Guo@Sun.COM 	if ((!*list_offset) || (*list_offset == 0xFFFF))
12009353SSamuel.Tu@Sun.COM 		return (IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT);
12018490SPaul.Guo@Sun.COM 
12028490SPaul.Guo@Sun.COM 	/* Shift offset to first ID word */
12038490SPaul.Guo@Sun.COM 	(*list_offset)++;
12048490SPaul.Guo@Sun.COM 
12058490SPaul.Guo@Sun.COM 	/*
12068490SPaul.Guo@Sun.COM 	 * Find the matching SFP ID in the EEPROM
12078490SPaul.Guo@Sun.COM 	 * and program the init sequence
12088490SPaul.Guo@Sun.COM 	 */
12098490SPaul.Guo@Sun.COM 	hw->eeprom.ops.read(hw, *list_offset, &sfp_id);
12108490SPaul.Guo@Sun.COM 
12118490SPaul.Guo@Sun.COM 	while (sfp_id != IXGBE_PHY_INIT_END_NL) {
1212*13006SChenlu.Chen@Sun.COM 		if (sfp_id == sfp_type) {
12138490SPaul.Guo@Sun.COM 			(*list_offset)++;
12148490SPaul.Guo@Sun.COM 			hw->eeprom.ops.read(hw, *list_offset, data_offset);
12158490SPaul.Guo@Sun.COM 			if ((!*data_offset) || (*data_offset == 0xFFFF)) {
12168490SPaul.Guo@Sun.COM 				DEBUGOUT("SFP+ module not supported\n");
12178490SPaul.Guo@Sun.COM 				return (IXGBE_ERR_SFP_NOT_SUPPORTED);
12188490SPaul.Guo@Sun.COM 			} else {
12198490SPaul.Guo@Sun.COM 				break;
12208490SPaul.Guo@Sun.COM 			}
12218490SPaul.Guo@Sun.COM 		} else {
12228490SPaul.Guo@Sun.COM 			(*list_offset) += 2;
12238490SPaul.Guo@Sun.COM 			if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id))
12248490SPaul.Guo@Sun.COM 				return (IXGBE_ERR_PHY);
12258490SPaul.Guo@Sun.COM 		}
12268490SPaul.Guo@Sun.COM 	}
12278490SPaul.Guo@Sun.COM 
12288490SPaul.Guo@Sun.COM 	if (sfp_id == IXGBE_PHY_INIT_END_NL) {
12298490SPaul.Guo@Sun.COM 		DEBUGOUT("No matching SFP+ module found\n");
12308490SPaul.Guo@Sun.COM 		return (IXGBE_ERR_SFP_NOT_SUPPORTED);
12318490SPaul.Guo@Sun.COM 	}
12328490SPaul.Guo@Sun.COM 
12338490SPaul.Guo@Sun.COM 	return (IXGBE_SUCCESS);
12348490SPaul.Guo@Sun.COM }
12359353SSamuel.Tu@Sun.COM 
12369353SSamuel.Tu@Sun.COM /*
12379353SSamuel.Tu@Sun.COM  * ixgbe_read_i2c_eeprom_generic - Reads 8 bit EEPROM word over I2C interface
12389353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
12399353SSamuel.Tu@Sun.COM  * @byte_offset: EEPROM byte offset to read
12409353SSamuel.Tu@Sun.COM  * @eeprom_data: value read
12419353SSamuel.Tu@Sun.COM  *
12429353SSamuel.Tu@Sun.COM  * Performs byte read operation to SFP module's EEPROM over I2C interface.
12439353SSamuel.Tu@Sun.COM  */
12449353SSamuel.Tu@Sun.COM s32
ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 * eeprom_data)12459353SSamuel.Tu@Sun.COM ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
12469353SSamuel.Tu@Sun.COM     u8 *eeprom_data)
12479353SSamuel.Tu@Sun.COM {
12489353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_read_i2c_eeprom_generic");
12499353SSamuel.Tu@Sun.COM 
12509353SSamuel.Tu@Sun.COM 	return (hw->phy.ops.read_i2c_byte(hw, byte_offset,
12519353SSamuel.Tu@Sun.COM 	    IXGBE_I2C_EEPROM_DEV_ADDR, eeprom_data));
12529353SSamuel.Tu@Sun.COM }
12539353SSamuel.Tu@Sun.COM 
12549353SSamuel.Tu@Sun.COM /*
12559353SSamuel.Tu@Sun.COM  * ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface
12569353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
12579353SSamuel.Tu@Sun.COM  * @byte_offset: EEPROM byte offset to write
12589353SSamuel.Tu@Sun.COM  * @eeprom_data: value to write
12599353SSamuel.Tu@Sun.COM  *
12609353SSamuel.Tu@Sun.COM  * Performs byte write operation to SFP module's EEPROM over I2C interface.
12619353SSamuel.Tu@Sun.COM  */
ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 eeprom_data)12629353SSamuel.Tu@Sun.COM s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
12639353SSamuel.Tu@Sun.COM     u8 eeprom_data)
12649353SSamuel.Tu@Sun.COM {
12659353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_write_i2c_eeprom_generic");
12669353SSamuel.Tu@Sun.COM 
12679353SSamuel.Tu@Sun.COM 	return (hw->phy.ops.write_i2c_byte(hw, byte_offset,
12689353SSamuel.Tu@Sun.COM 	    IXGBE_I2C_EEPROM_DEV_ADDR, eeprom_data));
12699353SSamuel.Tu@Sun.COM }
12709353SSamuel.Tu@Sun.COM 
12719353SSamuel.Tu@Sun.COM /*
12729353SSamuel.Tu@Sun.COM  * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
12739353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
12749353SSamuel.Tu@Sun.COM  * @byte_offset: byte offset to read
12759353SSamuel.Tu@Sun.COM  * @data: value read
12769353SSamuel.Tu@Sun.COM  *
12779353SSamuel.Tu@Sun.COM  * Performs byte read operation to SFP module's EEPROM over I2C interface at
12789353SSamuel.Tu@Sun.COM  * a specified deivce address.
12799353SSamuel.Tu@Sun.COM  */
12809353SSamuel.Tu@Sun.COM s32
ixgbe_read_i2c_byte_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 * data)12819353SSamuel.Tu@Sun.COM ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
12829353SSamuel.Tu@Sun.COM     u8 dev_addr, u8 *data)
12839353SSamuel.Tu@Sun.COM {
12849353SSamuel.Tu@Sun.COM 	s32 status = IXGBE_SUCCESS;
128510305SPaul.Guo@Sun.COM 	u32 max_retry = 10;
12869353SSamuel.Tu@Sun.COM 	u32 retry = 0;
12879353SSamuel.Tu@Sun.COM 	u16 swfw_mask = 0;
12889353SSamuel.Tu@Sun.COM 	bool nack = 1;
12899353SSamuel.Tu@Sun.COM 
12909353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_read_i2c_byte_generic");
12919353SSamuel.Tu@Sun.COM 
12929353SSamuel.Tu@Sun.COM 	if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
12939353SSamuel.Tu@Sun.COM 		swfw_mask = IXGBE_GSSR_PHY1_SM;
12949353SSamuel.Tu@Sun.COM 	else
12959353SSamuel.Tu@Sun.COM 		swfw_mask = IXGBE_GSSR_PHY0_SM;
12969353SSamuel.Tu@Sun.COM 
129710305SPaul.Guo@Sun.COM 	do {
129810305SPaul.Guo@Sun.COM 		if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != IXGBE_SUCCESS) {
129910305SPaul.Guo@Sun.COM 			status = IXGBE_ERR_SWFW_SYNC;
130010305SPaul.Guo@Sun.COM 			goto read_byte_out;
130110305SPaul.Guo@Sun.COM 		}
13029353SSamuel.Tu@Sun.COM 
13039353SSamuel.Tu@Sun.COM 		ixgbe_i2c_start(hw);
13049353SSamuel.Tu@Sun.COM 
13059353SSamuel.Tu@Sun.COM 		/* Device Address and write indication */
13069353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
13079353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
13089353SSamuel.Tu@Sun.COM 			goto fail;
13099353SSamuel.Tu@Sun.COM 
13109353SSamuel.Tu@Sun.COM 		status = ixgbe_get_i2c_ack(hw);
13119353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
13129353SSamuel.Tu@Sun.COM 			goto fail;
13139353SSamuel.Tu@Sun.COM 
13149353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
13159353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
13169353SSamuel.Tu@Sun.COM 			goto fail;
13179353SSamuel.Tu@Sun.COM 
13189353SSamuel.Tu@Sun.COM 		status = ixgbe_get_i2c_ack(hw);
13199353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
13209353SSamuel.Tu@Sun.COM 			goto fail;
13219353SSamuel.Tu@Sun.COM 
13229353SSamuel.Tu@Sun.COM 		ixgbe_i2c_start(hw);
13239353SSamuel.Tu@Sun.COM 
13249353SSamuel.Tu@Sun.COM 		/* Device Address and read indication */
13259353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_out_i2c_byte(hw, (dev_addr | 0x1));
13269353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
13279353SSamuel.Tu@Sun.COM 			goto fail;
13289353SSamuel.Tu@Sun.COM 
13299353SSamuel.Tu@Sun.COM 		status = ixgbe_get_i2c_ack(hw);
13309353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
13319353SSamuel.Tu@Sun.COM 			goto fail;
13329353SSamuel.Tu@Sun.COM 
13339353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_in_i2c_byte(hw, data);
13349353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
13359353SSamuel.Tu@Sun.COM 			goto fail;
13369353SSamuel.Tu@Sun.COM 
13379353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_out_i2c_bit(hw, nack);
13389353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
13399353SSamuel.Tu@Sun.COM 			goto fail;
13409353SSamuel.Tu@Sun.COM 
13419353SSamuel.Tu@Sun.COM 		ixgbe_i2c_stop(hw);
13429353SSamuel.Tu@Sun.COM 		break;
13439353SSamuel.Tu@Sun.COM 
13449353SSamuel.Tu@Sun.COM fail:
134510305SPaul.Guo@Sun.COM 		ixgbe_release_swfw_sync(hw, swfw_mask);
134610305SPaul.Guo@Sun.COM 		msec_delay(100);
13479353SSamuel.Tu@Sun.COM 		ixgbe_i2c_bus_clear(hw);
13489353SSamuel.Tu@Sun.COM 		retry++;
13499353SSamuel.Tu@Sun.COM 		if (retry < max_retry)
13509353SSamuel.Tu@Sun.COM 			DEBUGOUT("I2C byte read error - Retrying.\n");
13519353SSamuel.Tu@Sun.COM 		else
13529353SSamuel.Tu@Sun.COM 			DEBUGOUT("I2C byte read error.\n");
13539353SSamuel.Tu@Sun.COM 	} while (retry < max_retry);
13549353SSamuel.Tu@Sun.COM 
13559353SSamuel.Tu@Sun.COM 	ixgbe_release_swfw_sync(hw, swfw_mask);
13569353SSamuel.Tu@Sun.COM 
13579353SSamuel.Tu@Sun.COM read_byte_out:
13589353SSamuel.Tu@Sun.COM 	return (status);
13599353SSamuel.Tu@Sun.COM }
13609353SSamuel.Tu@Sun.COM 
13619353SSamuel.Tu@Sun.COM /*
13629353SSamuel.Tu@Sun.COM  * ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
13639353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
13649353SSamuel.Tu@Sun.COM  * @byte_offset: byte offset to write
13659353SSamuel.Tu@Sun.COM  * @data: value to write
13669353SSamuel.Tu@Sun.COM  *
13679353SSamuel.Tu@Sun.COM  * Performs byte write operation to SFP module's EEPROM over I2C interface at
13689353SSamuel.Tu@Sun.COM  * a specified device address.
13699353SSamuel.Tu@Sun.COM  */
13709353SSamuel.Tu@Sun.COM s32
ixgbe_write_i2c_byte_generic(struct ixgbe_hw * hw,u8 byte_offset,u8 dev_addr,u8 data)13719353SSamuel.Tu@Sun.COM ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
13729353SSamuel.Tu@Sun.COM     u8 dev_addr, u8 data)
13739353SSamuel.Tu@Sun.COM {
13749353SSamuel.Tu@Sun.COM 	s32 status = IXGBE_SUCCESS;
13759353SSamuel.Tu@Sun.COM 	u32 max_retry = 1;
13769353SSamuel.Tu@Sun.COM 	u32 retry = 0;
13779353SSamuel.Tu@Sun.COM 	u16 swfw_mask = 0;
13789353SSamuel.Tu@Sun.COM 
13799353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_write_i2c_byte_generic");
13809353SSamuel.Tu@Sun.COM 
13819353SSamuel.Tu@Sun.COM 	if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
13829353SSamuel.Tu@Sun.COM 		swfw_mask = IXGBE_GSSR_PHY1_SM;
13839353SSamuel.Tu@Sun.COM 	else
13849353SSamuel.Tu@Sun.COM 		swfw_mask = IXGBE_GSSR_PHY0_SM;
13859353SSamuel.Tu@Sun.COM 
13869353SSamuel.Tu@Sun.COM 	if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != IXGBE_SUCCESS) {
13879353SSamuel.Tu@Sun.COM 		status = IXGBE_ERR_SWFW_SYNC;
13889353SSamuel.Tu@Sun.COM 		goto write_byte_out;
13899353SSamuel.Tu@Sun.COM 	}
13909353SSamuel.Tu@Sun.COM 
13919353SSamuel.Tu@Sun.COM 	do {
13929353SSamuel.Tu@Sun.COM 		ixgbe_i2c_start(hw);
13939353SSamuel.Tu@Sun.COM 
13949353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
13959353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
13969353SSamuel.Tu@Sun.COM 			goto fail;
13979353SSamuel.Tu@Sun.COM 
13989353SSamuel.Tu@Sun.COM 		status = ixgbe_get_i2c_ack(hw);
13999353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
14009353SSamuel.Tu@Sun.COM 			goto fail;
14019353SSamuel.Tu@Sun.COM 
14029353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
14039353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
14049353SSamuel.Tu@Sun.COM 			goto fail;
14059353SSamuel.Tu@Sun.COM 
14069353SSamuel.Tu@Sun.COM 		status = ixgbe_get_i2c_ack(hw);
14079353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
14089353SSamuel.Tu@Sun.COM 			goto fail;
14099353SSamuel.Tu@Sun.COM 
14109353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_out_i2c_byte(hw, data);
14119353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
14129353SSamuel.Tu@Sun.COM 			goto fail;
14139353SSamuel.Tu@Sun.COM 
14149353SSamuel.Tu@Sun.COM 		status = ixgbe_get_i2c_ack(hw);
14159353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
14169353SSamuel.Tu@Sun.COM 			goto fail;
14179353SSamuel.Tu@Sun.COM 
14189353SSamuel.Tu@Sun.COM 		ixgbe_i2c_stop(hw);
14199353SSamuel.Tu@Sun.COM 		break;
14209353SSamuel.Tu@Sun.COM 
14219353SSamuel.Tu@Sun.COM fail:
14229353SSamuel.Tu@Sun.COM 		ixgbe_i2c_bus_clear(hw);
14239353SSamuel.Tu@Sun.COM 		retry++;
14249353SSamuel.Tu@Sun.COM 		if (retry < max_retry)
14259353SSamuel.Tu@Sun.COM 			DEBUGOUT("I2C byte write error - Retrying.\n");
14269353SSamuel.Tu@Sun.COM 		else
14279353SSamuel.Tu@Sun.COM 			DEBUGOUT("I2C byte write error.\n");
14289353SSamuel.Tu@Sun.COM 	} while (retry < max_retry);
14299353SSamuel.Tu@Sun.COM 
14309353SSamuel.Tu@Sun.COM 	ixgbe_release_swfw_sync(hw, swfw_mask);
14319353SSamuel.Tu@Sun.COM 
14329353SSamuel.Tu@Sun.COM write_byte_out:
14339353SSamuel.Tu@Sun.COM 	return (status);
14349353SSamuel.Tu@Sun.COM }
14359353SSamuel.Tu@Sun.COM 
14369353SSamuel.Tu@Sun.COM /*
14379353SSamuel.Tu@Sun.COM  * ixgbe_i2c_start - Sets I2C start condition
14389353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
14399353SSamuel.Tu@Sun.COM  *
14409353SSamuel.Tu@Sun.COM  * Sets I2C start condition (High -> Low on SDA while SCL is High)
14419353SSamuel.Tu@Sun.COM  */
14429353SSamuel.Tu@Sun.COM static void
ixgbe_i2c_start(struct ixgbe_hw * hw)14439353SSamuel.Tu@Sun.COM ixgbe_i2c_start(struct ixgbe_hw *hw)
14449353SSamuel.Tu@Sun.COM {
14459353SSamuel.Tu@Sun.COM 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
14469353SSamuel.Tu@Sun.COM 
14479353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_i2c_start");
14489353SSamuel.Tu@Sun.COM 
14499353SSamuel.Tu@Sun.COM 	/* Start condition must begin with data and clock high */
14509353SSamuel.Tu@Sun.COM 	(void) ixgbe_set_i2c_data(hw, &i2cctl, 1);
14519353SSamuel.Tu@Sun.COM 	(void) ixgbe_raise_i2c_clk(hw, &i2cctl);
14529353SSamuel.Tu@Sun.COM 
14539353SSamuel.Tu@Sun.COM 	/* Setup time for start condition (4.7us) */
14549353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_SU_STA);
14559353SSamuel.Tu@Sun.COM 
14569353SSamuel.Tu@Sun.COM 	(void) ixgbe_set_i2c_data(hw, &i2cctl, 0);
14579353SSamuel.Tu@Sun.COM 
14589353SSamuel.Tu@Sun.COM 	/* Hold time for start condition (4us) */
14599353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_HD_STA);
14609353SSamuel.Tu@Sun.COM 
14619353SSamuel.Tu@Sun.COM 	ixgbe_lower_i2c_clk(hw, &i2cctl);
14629353SSamuel.Tu@Sun.COM 
14639353SSamuel.Tu@Sun.COM 	/* Minimum low period of clock is 4.7 us */
14649353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_LOW);
14659353SSamuel.Tu@Sun.COM }
14669353SSamuel.Tu@Sun.COM 
14679353SSamuel.Tu@Sun.COM /*
14689353SSamuel.Tu@Sun.COM  * ixgbe_i2c_stop - Sets I2C stop condition
14699353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
14709353SSamuel.Tu@Sun.COM  *
14719353SSamuel.Tu@Sun.COM  * Sets I2C stop condition (Low -> High on SDA while SCL is High)
14729353SSamuel.Tu@Sun.COM  */
14739353SSamuel.Tu@Sun.COM static void
ixgbe_i2c_stop(struct ixgbe_hw * hw)14749353SSamuel.Tu@Sun.COM ixgbe_i2c_stop(struct ixgbe_hw *hw)
14759353SSamuel.Tu@Sun.COM {
14769353SSamuel.Tu@Sun.COM 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
14779353SSamuel.Tu@Sun.COM 
14789353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_i2c_stop");
14799353SSamuel.Tu@Sun.COM 
14809353SSamuel.Tu@Sun.COM 	/* Stop condition must begin with data low and clock high */
14819353SSamuel.Tu@Sun.COM 	(void) ixgbe_set_i2c_data(hw, &i2cctl, 0);
14829353SSamuel.Tu@Sun.COM 	(void) ixgbe_raise_i2c_clk(hw, &i2cctl);
14839353SSamuel.Tu@Sun.COM 
14849353SSamuel.Tu@Sun.COM 	/* Setup time for stop condition (4us) */
14859353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_SU_STO);
14869353SSamuel.Tu@Sun.COM 
14879353SSamuel.Tu@Sun.COM 	(void) ixgbe_set_i2c_data(hw, &i2cctl, 1);
14889353SSamuel.Tu@Sun.COM 
14899353SSamuel.Tu@Sun.COM 	/* bus free time between stop and start (4.7us) */
14909353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_BUF);
14919353SSamuel.Tu@Sun.COM }
14929353SSamuel.Tu@Sun.COM 
14939353SSamuel.Tu@Sun.COM /*
14949353SSamuel.Tu@Sun.COM  * ixgbe_clock_in_i2c_byte - Clocks in one byte via I2C
14959353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
14969353SSamuel.Tu@Sun.COM  * @data: data byte to clock in
14979353SSamuel.Tu@Sun.COM  *
14989353SSamuel.Tu@Sun.COM  * Clocks in one byte data via I2C data/clock
14999353SSamuel.Tu@Sun.COM  */
15009353SSamuel.Tu@Sun.COM static s32
ixgbe_clock_in_i2c_byte(struct ixgbe_hw * hw,u8 * data)15019353SSamuel.Tu@Sun.COM ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data)
15029353SSamuel.Tu@Sun.COM {
15039353SSamuel.Tu@Sun.COM 	s32 status = IXGBE_SUCCESS;
15049353SSamuel.Tu@Sun.COM 	s32 i;
15059353SSamuel.Tu@Sun.COM 	bool bit = 0;
15069353SSamuel.Tu@Sun.COM 
15079353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_clock_in_i2c_byte");
15089353SSamuel.Tu@Sun.COM 
15099353SSamuel.Tu@Sun.COM 	for (i = 7; i >= 0; i--) {
15109353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_in_i2c_bit(hw, &bit);
15119353SSamuel.Tu@Sun.COM 		*data |= bit<<i;
15129353SSamuel.Tu@Sun.COM 
15139353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
15149353SSamuel.Tu@Sun.COM 			break;
15159353SSamuel.Tu@Sun.COM 	}
15169353SSamuel.Tu@Sun.COM 
15179353SSamuel.Tu@Sun.COM 	return (status);
15189353SSamuel.Tu@Sun.COM }
15199353SSamuel.Tu@Sun.COM 
15209353SSamuel.Tu@Sun.COM /*
15219353SSamuel.Tu@Sun.COM  * ixgbe_clock_out_i2c_byte - Clocks out one byte via I2C
15229353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
15239353SSamuel.Tu@Sun.COM  * @data: data byte clocked out
15249353SSamuel.Tu@Sun.COM  *
15259353SSamuel.Tu@Sun.COM  * Clocks out one byte data via I2C data/clock
15269353SSamuel.Tu@Sun.COM  */
15279353SSamuel.Tu@Sun.COM static s32
ixgbe_clock_out_i2c_byte(struct ixgbe_hw * hw,u8 data)15289353SSamuel.Tu@Sun.COM ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
15299353SSamuel.Tu@Sun.COM {
15309353SSamuel.Tu@Sun.COM 	s32 status = IXGBE_SUCCESS;
15319353SSamuel.Tu@Sun.COM 	s32 i;
15329353SSamuel.Tu@Sun.COM 	u32 i2cctl;
15339353SSamuel.Tu@Sun.COM 	bool bit = 0;
15349353SSamuel.Tu@Sun.COM 
15359353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_clock_out_i2c_byte");
15369353SSamuel.Tu@Sun.COM 
15379353SSamuel.Tu@Sun.COM 	for (i = 7; i >= 0; i--) {
15389353SSamuel.Tu@Sun.COM 		bit = (data >> i) & 0x1;
15399353SSamuel.Tu@Sun.COM 		status = ixgbe_clock_out_i2c_bit(hw, bit);
15409353SSamuel.Tu@Sun.COM 
15419353SSamuel.Tu@Sun.COM 		if (status != IXGBE_SUCCESS)
15429353SSamuel.Tu@Sun.COM 			break;
15439353SSamuel.Tu@Sun.COM 	}
15449353SSamuel.Tu@Sun.COM 
15459353SSamuel.Tu@Sun.COM 	/* Release SDA line (set high) */
15469353SSamuel.Tu@Sun.COM 	i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
15479353SSamuel.Tu@Sun.COM 	i2cctl |= IXGBE_I2C_DATA_OUT;
15489353SSamuel.Tu@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, i2cctl);
15499353SSamuel.Tu@Sun.COM 
15509353SSamuel.Tu@Sun.COM 	return (status);
15519353SSamuel.Tu@Sun.COM }
15529353SSamuel.Tu@Sun.COM 
15539353SSamuel.Tu@Sun.COM /*
15549353SSamuel.Tu@Sun.COM  * ixgbe_get_i2c_ack - Polls for I2C ACK
15559353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
15569353SSamuel.Tu@Sun.COM  *
15579353SSamuel.Tu@Sun.COM  * Clocks in/out one bit via I2C data/clock
15589353SSamuel.Tu@Sun.COM  */
15599353SSamuel.Tu@Sun.COM static s32
ixgbe_get_i2c_ack(struct ixgbe_hw * hw)15609353SSamuel.Tu@Sun.COM ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
15619353SSamuel.Tu@Sun.COM {
15629353SSamuel.Tu@Sun.COM 	s32 status;
15639353SSamuel.Tu@Sun.COM 	u32 i = 0;
15649353SSamuel.Tu@Sun.COM 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
15659353SSamuel.Tu@Sun.COM 	u32 timeout = 10;
15669353SSamuel.Tu@Sun.COM 	bool ack = 1;
15679353SSamuel.Tu@Sun.COM 
15689353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_get_i2c_ack");
15699353SSamuel.Tu@Sun.COM 
15709353SSamuel.Tu@Sun.COM 	status = ixgbe_raise_i2c_clk(hw, &i2cctl);
15719353SSamuel.Tu@Sun.COM 
15729353SSamuel.Tu@Sun.COM 	if (status != IXGBE_SUCCESS)
15739353SSamuel.Tu@Sun.COM 		goto out;
15749353SSamuel.Tu@Sun.COM 
15759353SSamuel.Tu@Sun.COM 	/* Minimum high period of clock is 4us */
15769353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_HIGH);
15779353SSamuel.Tu@Sun.COM 
15789353SSamuel.Tu@Sun.COM 	/*
15799353SSamuel.Tu@Sun.COM 	 * Poll for ACK.  Note that ACK in I2C spec is
15809353SSamuel.Tu@Sun.COM 	 * transition from 1 to 0
15819353SSamuel.Tu@Sun.COM 	 */
15829353SSamuel.Tu@Sun.COM 	for (i = 0; i < timeout; i++) {
15839353SSamuel.Tu@Sun.COM 		i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
15849353SSamuel.Tu@Sun.COM 		ack = ixgbe_get_i2c_data(&i2cctl);
15859353SSamuel.Tu@Sun.COM 
15869353SSamuel.Tu@Sun.COM 		usec_delay(1);
15879353SSamuel.Tu@Sun.COM 		if (ack == 0)
15889353SSamuel.Tu@Sun.COM 			break;
15899353SSamuel.Tu@Sun.COM 	}
15909353SSamuel.Tu@Sun.COM 
15919353SSamuel.Tu@Sun.COM 	if (ack == 1) {
15929353SSamuel.Tu@Sun.COM 		DEBUGOUT("I2C ack was not received.\n");
15939353SSamuel.Tu@Sun.COM 		status = IXGBE_ERR_I2C;
15949353SSamuel.Tu@Sun.COM 	}
15959353SSamuel.Tu@Sun.COM 
15969353SSamuel.Tu@Sun.COM 	ixgbe_lower_i2c_clk(hw, &i2cctl);
15979353SSamuel.Tu@Sun.COM 
15989353SSamuel.Tu@Sun.COM 	/* Minimum low period of clock is 4.7 us */
15999353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_LOW);
16009353SSamuel.Tu@Sun.COM 
16019353SSamuel.Tu@Sun.COM out:
16029353SSamuel.Tu@Sun.COM 	return (status);
16039353SSamuel.Tu@Sun.COM }
16049353SSamuel.Tu@Sun.COM 
16059353SSamuel.Tu@Sun.COM /*
16069353SSamuel.Tu@Sun.COM  * ixgbe_clock_in_i2c_bit - Clocks in one bit via I2C data/clock
16079353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
16089353SSamuel.Tu@Sun.COM  * @data: read data value
16099353SSamuel.Tu@Sun.COM  *
16109353SSamuel.Tu@Sun.COM  * Clocks in one bit via I2C data/clock
16119353SSamuel.Tu@Sun.COM  */
16129353SSamuel.Tu@Sun.COM static s32
ixgbe_clock_in_i2c_bit(struct ixgbe_hw * hw,bool * data)16139353SSamuel.Tu@Sun.COM ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
16149353SSamuel.Tu@Sun.COM {
16159353SSamuel.Tu@Sun.COM 	s32 status;
16169353SSamuel.Tu@Sun.COM 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
16179353SSamuel.Tu@Sun.COM 
161810998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_clock_in_i2c_bit");
161910998SChenlu.Chen@Sun.COM 
16209353SSamuel.Tu@Sun.COM 	status = ixgbe_raise_i2c_clk(hw, &i2cctl);
16219353SSamuel.Tu@Sun.COM 
16229353SSamuel.Tu@Sun.COM 	/* Minimum high period of clock is 4us */
16239353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_HIGH);
16249353SSamuel.Tu@Sun.COM 
16259353SSamuel.Tu@Sun.COM 	i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
16269353SSamuel.Tu@Sun.COM 	*data = ixgbe_get_i2c_data(&i2cctl);
16279353SSamuel.Tu@Sun.COM 
16289353SSamuel.Tu@Sun.COM 	ixgbe_lower_i2c_clk(hw, &i2cctl);
16299353SSamuel.Tu@Sun.COM 
16309353SSamuel.Tu@Sun.COM 	/* Minimum low period of clock is 4.7 us */
16319353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_LOW);
16329353SSamuel.Tu@Sun.COM 
16339353SSamuel.Tu@Sun.COM 	return (status);
16349353SSamuel.Tu@Sun.COM }
16359353SSamuel.Tu@Sun.COM 
16369353SSamuel.Tu@Sun.COM /*
16379353SSamuel.Tu@Sun.COM  * ixgbe_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock
16389353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
16399353SSamuel.Tu@Sun.COM  * @data: data value to write
16409353SSamuel.Tu@Sun.COM  *
16419353SSamuel.Tu@Sun.COM  * Clocks out one bit via I2C data/clock
16429353SSamuel.Tu@Sun.COM  */
16439353SSamuel.Tu@Sun.COM static s32
ixgbe_clock_out_i2c_bit(struct ixgbe_hw * hw,bool data)16449353SSamuel.Tu@Sun.COM ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
16459353SSamuel.Tu@Sun.COM {
16469353SSamuel.Tu@Sun.COM 	s32 status;
16479353SSamuel.Tu@Sun.COM 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
16489353SSamuel.Tu@Sun.COM 
164910998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_clock_out_i2c_bit");
165010998SChenlu.Chen@Sun.COM 
16519353SSamuel.Tu@Sun.COM 	status = ixgbe_set_i2c_data(hw, &i2cctl, data);
16529353SSamuel.Tu@Sun.COM 	if (status == IXGBE_SUCCESS) {
16539353SSamuel.Tu@Sun.COM 		status = ixgbe_raise_i2c_clk(hw, &i2cctl);
16549353SSamuel.Tu@Sun.COM 
16559353SSamuel.Tu@Sun.COM 		/* Minimum high period of clock is 4us */
16569353SSamuel.Tu@Sun.COM 		usec_delay(IXGBE_I2C_T_HIGH);
16579353SSamuel.Tu@Sun.COM 
16589353SSamuel.Tu@Sun.COM 		ixgbe_lower_i2c_clk(hw, &i2cctl);
16599353SSamuel.Tu@Sun.COM 
16609353SSamuel.Tu@Sun.COM 		/*
16619353SSamuel.Tu@Sun.COM 		 * Minimum low period of clock is 4.7 us.
16629353SSamuel.Tu@Sun.COM 		 * This also takes care of the data hold time.
16639353SSamuel.Tu@Sun.COM 		 */
16649353SSamuel.Tu@Sun.COM 		usec_delay(IXGBE_I2C_T_LOW);
16659353SSamuel.Tu@Sun.COM 	} else {
16669353SSamuel.Tu@Sun.COM 		status = IXGBE_ERR_I2C;
16679353SSamuel.Tu@Sun.COM 		DEBUGOUT1("I2C data was not set to %X\n", data);
16689353SSamuel.Tu@Sun.COM 	}
16699353SSamuel.Tu@Sun.COM 
16709353SSamuel.Tu@Sun.COM 	return (status);
16719353SSamuel.Tu@Sun.COM }
16729353SSamuel.Tu@Sun.COM 
16739353SSamuel.Tu@Sun.COM /*
16749353SSamuel.Tu@Sun.COM  * ixgbe_raise_i2c_clk - Raises the I2C SCL clock
16759353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
16769353SSamuel.Tu@Sun.COM  * @i2cctl: Current value of I2CCTL register
16779353SSamuel.Tu@Sun.COM  *
16789353SSamuel.Tu@Sun.COM  * Raises the I2C clock line '0'->'1'
16799353SSamuel.Tu@Sun.COM  */
16809353SSamuel.Tu@Sun.COM static s32
ixgbe_raise_i2c_clk(struct ixgbe_hw * hw,u32 * i2cctl)16819353SSamuel.Tu@Sun.COM ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
16829353SSamuel.Tu@Sun.COM {
16839353SSamuel.Tu@Sun.COM 	s32 status = IXGBE_SUCCESS;
16849353SSamuel.Tu@Sun.COM 
168510998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_raise_i2c_clk");
168610998SChenlu.Chen@Sun.COM 
16879353SSamuel.Tu@Sun.COM 	*i2cctl |= IXGBE_I2C_CLK_OUT;
16889353SSamuel.Tu@Sun.COM 
16899353SSamuel.Tu@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
16909353SSamuel.Tu@Sun.COM 
16919353SSamuel.Tu@Sun.COM 	/* SCL rise time (1000ns) */
16929353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_RISE);
16939353SSamuel.Tu@Sun.COM 
16949353SSamuel.Tu@Sun.COM 	return (status);
16959353SSamuel.Tu@Sun.COM }
16969353SSamuel.Tu@Sun.COM 
16979353SSamuel.Tu@Sun.COM /*
16989353SSamuel.Tu@Sun.COM  * ixgbe_lower_i2c_clk - Lowers the I2C SCL clock
16999353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
17009353SSamuel.Tu@Sun.COM  * @i2cctl: Current value of I2CCTL register
17019353SSamuel.Tu@Sun.COM  *
17029353SSamuel.Tu@Sun.COM  * Lowers the I2C clock line '1'->'0'
17039353SSamuel.Tu@Sun.COM  */
17049353SSamuel.Tu@Sun.COM static void
ixgbe_lower_i2c_clk(struct ixgbe_hw * hw,u32 * i2cctl)17059353SSamuel.Tu@Sun.COM ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
17069353SSamuel.Tu@Sun.COM {
170710998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_lower_i2c_clk");
170810998SChenlu.Chen@Sun.COM 
17099353SSamuel.Tu@Sun.COM 	*i2cctl &= ~IXGBE_I2C_CLK_OUT;
17109353SSamuel.Tu@Sun.COM 
17119353SSamuel.Tu@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
17129353SSamuel.Tu@Sun.COM 
17139353SSamuel.Tu@Sun.COM 	/* SCL fall time (300ns) */
17149353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_FALL);
17159353SSamuel.Tu@Sun.COM }
17169353SSamuel.Tu@Sun.COM 
17179353SSamuel.Tu@Sun.COM /*
17189353SSamuel.Tu@Sun.COM  * ixgbe_set_i2c_data - Sets the I2C data bit
17199353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
17209353SSamuel.Tu@Sun.COM  * @i2cctl: Current value of I2CCTL register
17219353SSamuel.Tu@Sun.COM  * @data: I2C data value (0 or 1) to set
17229353SSamuel.Tu@Sun.COM  *
17239353SSamuel.Tu@Sun.COM  * Sets the I2C data bit
17249353SSamuel.Tu@Sun.COM  */
17259353SSamuel.Tu@Sun.COM static s32
ixgbe_set_i2c_data(struct ixgbe_hw * hw,u32 * i2cctl,bool data)17269353SSamuel.Tu@Sun.COM ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
17279353SSamuel.Tu@Sun.COM {
17289353SSamuel.Tu@Sun.COM 	s32 status = IXGBE_SUCCESS;
17299353SSamuel.Tu@Sun.COM 
173010998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_set_i2c_data");
173110998SChenlu.Chen@Sun.COM 
17329353SSamuel.Tu@Sun.COM 	if (data)
17339353SSamuel.Tu@Sun.COM 		*i2cctl |= IXGBE_I2C_DATA_OUT;
17349353SSamuel.Tu@Sun.COM 	else
17359353SSamuel.Tu@Sun.COM 		*i2cctl &= ~IXGBE_I2C_DATA_OUT;
17369353SSamuel.Tu@Sun.COM 
17379353SSamuel.Tu@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
17389353SSamuel.Tu@Sun.COM 
17399353SSamuel.Tu@Sun.COM 	/* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
17409353SSamuel.Tu@Sun.COM 	usec_delay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
17419353SSamuel.Tu@Sun.COM 
17429353SSamuel.Tu@Sun.COM 	/* Verify data was set correctly */
17439353SSamuel.Tu@Sun.COM 	*i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
17449353SSamuel.Tu@Sun.COM 	if (data != ixgbe_get_i2c_data(i2cctl)) {
17459353SSamuel.Tu@Sun.COM 		status = IXGBE_ERR_I2C;
17469353SSamuel.Tu@Sun.COM 		DEBUGOUT1("Error - I2C data was not set to %X.\n", data);
17479353SSamuel.Tu@Sun.COM 	}
17489353SSamuel.Tu@Sun.COM 
17499353SSamuel.Tu@Sun.COM 	return (status);
17509353SSamuel.Tu@Sun.COM }
17519353SSamuel.Tu@Sun.COM 
17529353SSamuel.Tu@Sun.COM /*
17539353SSamuel.Tu@Sun.COM  * ixgbe_get_i2c_data - Reads the I2C SDA data bit
17549353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
17559353SSamuel.Tu@Sun.COM  * @i2cctl: Current value of I2CCTL register
17569353SSamuel.Tu@Sun.COM  *
17579353SSamuel.Tu@Sun.COM  * Returns the I2C data bit value
17589353SSamuel.Tu@Sun.COM  */
17599353SSamuel.Tu@Sun.COM static bool
ixgbe_get_i2c_data(u32 * i2cctl)17609353SSamuel.Tu@Sun.COM ixgbe_get_i2c_data(u32 *i2cctl)
17619353SSamuel.Tu@Sun.COM {
17629353SSamuel.Tu@Sun.COM 	bool data;
17639353SSamuel.Tu@Sun.COM 
176410998SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_get_i2c_data");
176510998SChenlu.Chen@Sun.COM 
17669353SSamuel.Tu@Sun.COM 	if (*i2cctl & IXGBE_I2C_DATA_IN)
17679353SSamuel.Tu@Sun.COM 		data = 1;
17689353SSamuel.Tu@Sun.COM 	else
17699353SSamuel.Tu@Sun.COM 		data = 0;
17709353SSamuel.Tu@Sun.COM 
17719353SSamuel.Tu@Sun.COM 	return (data);
17729353SSamuel.Tu@Sun.COM }
17739353SSamuel.Tu@Sun.COM 
17749353SSamuel.Tu@Sun.COM /*
17759353SSamuel.Tu@Sun.COM  * ixgbe_i2c_bus_clear - Clears the I2C bus
17769353SSamuel.Tu@Sun.COM  * @hw: pointer to hardware structure
17779353SSamuel.Tu@Sun.COM  *
17789353SSamuel.Tu@Sun.COM  * Clears the I2C bus by sending nine clock pulses.
17799353SSamuel.Tu@Sun.COM  * Used when data line is stuck low.
17809353SSamuel.Tu@Sun.COM  */
17819353SSamuel.Tu@Sun.COM void
ixgbe_i2c_bus_clear(struct ixgbe_hw * hw)17829353SSamuel.Tu@Sun.COM ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
17839353SSamuel.Tu@Sun.COM {
17849353SSamuel.Tu@Sun.COM 	u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
17859353SSamuel.Tu@Sun.COM 	u32 i;
17869353SSamuel.Tu@Sun.COM 
17879353SSamuel.Tu@Sun.COM 	DEBUGFUNC("ixgbe_i2c_bus_clear");
17889353SSamuel.Tu@Sun.COM 
17899353SSamuel.Tu@Sun.COM 	ixgbe_i2c_start(hw);
17909353SSamuel.Tu@Sun.COM 
17919353SSamuel.Tu@Sun.COM 	(void) ixgbe_set_i2c_data(hw, &i2cctl, 1);
17929353SSamuel.Tu@Sun.COM 
17939353SSamuel.Tu@Sun.COM 	for (i = 0; i < 9; i++) {
17949353SSamuel.Tu@Sun.COM 		(void) ixgbe_raise_i2c_clk(hw, &i2cctl);
17959353SSamuel.Tu@Sun.COM 
17969353SSamuel.Tu@Sun.COM 		/* Min high period of clock is 4us */
17979353SSamuel.Tu@Sun.COM 		usec_delay(IXGBE_I2C_T_HIGH);
17989353SSamuel.Tu@Sun.COM 
17999353SSamuel.Tu@Sun.COM 		ixgbe_lower_i2c_clk(hw, &i2cctl);
18009353SSamuel.Tu@Sun.COM 
18019353SSamuel.Tu@Sun.COM 		/* Min low period of clock is 4.7us */
18029353SSamuel.Tu@Sun.COM 		usec_delay(IXGBE_I2C_T_LOW);
18039353SSamuel.Tu@Sun.COM 	}
18049353SSamuel.Tu@Sun.COM 
18059353SSamuel.Tu@Sun.COM 	ixgbe_i2c_start(hw);
18069353SSamuel.Tu@Sun.COM 
18079353SSamuel.Tu@Sun.COM 	/* Put the i2c bus back to default state */
18089353SSamuel.Tu@Sun.COM 	ixgbe_i2c_stop(hw);
18099353SSamuel.Tu@Sun.COM }
1810*13006SChenlu.Chen@Sun.COM 
1811*13006SChenlu.Chen@Sun.COM /*
1812*13006SChenlu.Chen@Sun.COM  * ixgbe_tn_check_overtemp - Checks if an overtemp occured.
1813*13006SChenlu.Chen@Sun.COM  * @hw: pointer to hardware structure
1814*13006SChenlu.Chen@Sun.COM  *
1815*13006SChenlu.Chen@Sun.COM  * Checks if the LASI temp alarm status was triggered due to overtemp
1816*13006SChenlu.Chen@Sun.COM  */
1817*13006SChenlu.Chen@Sun.COM s32
ixgbe_tn_check_overtemp(struct ixgbe_hw * hw)1818*13006SChenlu.Chen@Sun.COM ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
1819*13006SChenlu.Chen@Sun.COM {
1820*13006SChenlu.Chen@Sun.COM 	s32 status = IXGBE_SUCCESS;
1821*13006SChenlu.Chen@Sun.COM 	u16 phy_data = 0;
1822*13006SChenlu.Chen@Sun.COM 
1823*13006SChenlu.Chen@Sun.COM 	DEBUGFUNC("ixgbe_tn_check_overtemp");
1824*13006SChenlu.Chen@Sun.COM 
1825*13006SChenlu.Chen@Sun.COM 	if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
1826*13006SChenlu.Chen@Sun.COM 		goto out;
1827*13006SChenlu.Chen@Sun.COM 
1828*13006SChenlu.Chen@Sun.COM 	/* Check that the LASI temp alarm status was triggered */
1829*13006SChenlu.Chen@Sun.COM 	hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
1830*13006SChenlu.Chen@Sun.COM 	    IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_data);
1831*13006SChenlu.Chen@Sun.COM 
1832*13006SChenlu.Chen@Sun.COM 	if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM))
1833*13006SChenlu.Chen@Sun.COM 		goto out;
1834*13006SChenlu.Chen@Sun.COM 
1835*13006SChenlu.Chen@Sun.COM 	status = IXGBE_ERR_OVERTEMP;
1836*13006SChenlu.Chen@Sun.COM out:
1837*13006SChenlu.Chen@Sun.COM 	return (status);
1838*13006SChenlu.Chen@Sun.COM }
1839