xref: /onnv-gate/usr/src/uts/common/io/ixgbe/ixgbe_phy.c (revision 8490:b196365c7f89)
16621Sbt150084 /*
26621Sbt150084  * CDDL HEADER START
36621Sbt150084  *
46621Sbt150084  * Copyright(c) 2007-2008 Intel Corporation. All rights reserved.
56621Sbt150084  * The contents of this file are subject to the terms of the
66621Sbt150084  * Common Development and Distribution License (the "License").
76621Sbt150084  * You may not use this file except in compliance with the License.
86621Sbt150084  *
96621Sbt150084  * You can obtain a copy of the license at:
106621Sbt150084  *      http://www.opensolaris.org/os/licensing.
116621Sbt150084  * See the License for the specific language governing permissions
126621Sbt150084  * and limitations under the License.
136621Sbt150084  *
146621Sbt150084  * When using or redistributing this file, you may do so under the
156621Sbt150084  * License only. No other modification of this header is permitted.
166621Sbt150084  *
176621Sbt150084  * If applicable, add the following below this CDDL HEADER, with the
186621Sbt150084  * fields enclosed by brackets "[]" replaced with your own identifying
196621Sbt150084  * information: Portions Copyright [yyyy] [name of copyright owner]
206621Sbt150084  *
216621Sbt150084  * CDDL HEADER END
226621Sbt150084  */
236621Sbt150084 
246621Sbt150084 /*
25*8490SPaul.Guo@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
266621Sbt150084  * Use is subject to license terms of the CDDL.
276621Sbt150084  */
286621Sbt150084 
29*8490SPaul.Guo@Sun.COM /* IntelVersion: 1.60 v2008-09-12 */
306621Sbt150084 
316621Sbt150084 #include "ixgbe_api.h"
326621Sbt150084 #include "ixgbe_common.h"
336621Sbt150084 #include "ixgbe_phy.h"
34*8490SPaul.Guo@Sun.COM #ident "$Id: ixgbe_phy.c,v 1.60 2008/09/15 15:47:02 mrchilak Exp $"
356621Sbt150084 
366621Sbt150084 /*
376621Sbt150084  * ixgbe_init_phy_ops_generic - Inits PHY function ptrs
386621Sbt150084  * @hw: pointer to the hardware structure
396621Sbt150084  *
406621Sbt150084  * Initialize the function pointers.
416621Sbt150084  */
426621Sbt150084 s32
436621Sbt150084 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw)
446621Sbt150084 {
456621Sbt150084 	struct ixgbe_phy_info *phy = &hw->phy;
466621Sbt150084 
476621Sbt150084 	/* PHY */
486621Sbt150084 	phy->ops.identify = &ixgbe_identify_phy_generic;
496621Sbt150084 	phy->ops.reset = &ixgbe_reset_phy_generic;
506621Sbt150084 	phy->ops.read_reg = &ixgbe_read_phy_reg_generic;
516621Sbt150084 	phy->ops.write_reg = &ixgbe_write_phy_reg_generic;
526621Sbt150084 	phy->ops.setup_link = &ixgbe_setup_phy_link_generic;
536621Sbt150084 	phy->ops.setup_link_speed = &ixgbe_setup_phy_link_speed_generic;
54*8490SPaul.Guo@Sun.COM 	phy->ops.check_link = NULL;
55*8490SPaul.Guo@Sun.COM 	phy->ops.get_firmware_version = NULL;
56*8490SPaul.Guo@Sun.COM 	phy->ops.identify_sfp = &ixgbe_identify_sfp_module_generic;
57*8490SPaul.Guo@Sun.COM 	phy->sfp_type = ixgbe_sfp_type_unknown;
586621Sbt150084 
596621Sbt150084 	return (IXGBE_SUCCESS);
606621Sbt150084 }
616621Sbt150084 
626621Sbt150084 /*
636621Sbt150084  * ixgbe_identify_phy_generic - Get physical layer module
646621Sbt150084  * @hw: pointer to hardware structure
656621Sbt150084  *
666621Sbt150084  * Determines the physical layer module found on the current adapter.
676621Sbt150084  */
686621Sbt150084 s32
696621Sbt150084 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
706621Sbt150084 {
716621Sbt150084 	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
726621Sbt150084 	u32 phy_addr;
736621Sbt150084 
746621Sbt150084 	if (hw->phy.type == ixgbe_phy_unknown) {
756621Sbt150084 		for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
766621Sbt150084 			if (ixgbe_validate_phy_addr(hw, phy_addr)) {
776621Sbt150084 				hw->phy.addr = phy_addr;
786621Sbt150084 				(void) ixgbe_get_phy_id(hw);
796621Sbt150084 				hw->phy.type =
806621Sbt150084 				    ixgbe_get_phy_type_from_id(hw->phy.id);
816621Sbt150084 				status = IXGBE_SUCCESS;
826621Sbt150084 				break;
836621Sbt150084 			}
846621Sbt150084 		}
856621Sbt150084 	} else {
866621Sbt150084 		status = IXGBE_SUCCESS;
876621Sbt150084 	}
886621Sbt150084 
896621Sbt150084 	return (status);
906621Sbt150084 }
916621Sbt150084 
926621Sbt150084 /*
936621Sbt150084  * ixgbe_validate_phy_addr - Determines phy address is valid
946621Sbt150084  * @hw: pointer to hardware structure
956621Sbt150084  *
966621Sbt150084  */
976621Sbt150084 bool
986621Sbt150084 ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
996621Sbt150084 {
1006621Sbt150084 	u16 phy_id = 0;
101*8490SPaul.Guo@Sun.COM 	bool valid = false;
1026621Sbt150084 
1036621Sbt150084 	hw->phy.addr = phy_addr;
1046621Sbt150084 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
1056621Sbt150084 	    IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id);
1066621Sbt150084 
1076621Sbt150084 	if (phy_id != 0xFFFF && phy_id != 0x0)
108*8490SPaul.Guo@Sun.COM 		valid = true;
1096621Sbt150084 
1106621Sbt150084 	return (valid);
1116621Sbt150084 }
1126621Sbt150084 
1136621Sbt150084 /*
1146621Sbt150084  * ixgbe_get_phy_id - Get the phy type
1156621Sbt150084  * @hw: pointer to hardware structure
1166621Sbt150084  *
1176621Sbt150084  */
1186621Sbt150084 s32
1196621Sbt150084 ixgbe_get_phy_id(struct ixgbe_hw *hw)
1206621Sbt150084 {
1216621Sbt150084 	u32 status;
1226621Sbt150084 	u16 phy_id_high = 0;
1236621Sbt150084 	u16 phy_id_low = 0;
1246621Sbt150084 
1256621Sbt150084 	status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
1266621Sbt150084 	    IXGBE_MDIO_PMA_PMD_DEV_TYPE,
1276621Sbt150084 	    &phy_id_high);
1286621Sbt150084 
1296621Sbt150084 	if (status == IXGBE_SUCCESS) {
1306621Sbt150084 		hw->phy.id = (u32)(phy_id_high << 16);
1316621Sbt150084 		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW,
1326621Sbt150084 		    IXGBE_MDIO_PMA_PMD_DEV_TYPE,
1336621Sbt150084 		    &phy_id_low);
1346621Sbt150084 		hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
1356621Sbt150084 		hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
1366621Sbt150084 	}
1376621Sbt150084 
1386621Sbt150084 	return (status);
1396621Sbt150084 }
1406621Sbt150084 
1416621Sbt150084 /*
1426621Sbt150084  * ixgbe_get_phy_type_from_id - Get the phy type
1436621Sbt150084  * @hw: pointer to hardware structure
1446621Sbt150084  *
1456621Sbt150084  */
1466621Sbt150084 enum ixgbe_phy_type
1476621Sbt150084 ixgbe_get_phy_type_from_id(u32 phy_id)
1486621Sbt150084 {
1496621Sbt150084 	enum ixgbe_phy_type phy_type;
1506621Sbt150084 
1516621Sbt150084 	switch (phy_id) {
152*8490SPaul.Guo@Sun.COM 	case TN1010_PHY_ID:
153*8490SPaul.Guo@Sun.COM 		phy_type = ixgbe_phy_tn;
154*8490SPaul.Guo@Sun.COM 		break;
1556621Sbt150084 	case QT2022_PHY_ID:
1566621Sbt150084 		phy_type = ixgbe_phy_qt;
1576621Sbt150084 		break;
158*8490SPaul.Guo@Sun.COM 	case ATH_PHY_ID:
159*8490SPaul.Guo@Sun.COM 		phy_type = ixgbe_phy_nl;
160*8490SPaul.Guo@Sun.COM 		break;
1616621Sbt150084 	default:
1626621Sbt150084 		phy_type = ixgbe_phy_unknown;
1636621Sbt150084 		break;
1646621Sbt150084 	}
1656621Sbt150084 
166*8490SPaul.Guo@Sun.COM 	DEBUGOUT1("phy type found is %d\n", phy_type);
167*8490SPaul.Guo@Sun.COM 
1686621Sbt150084 	return (phy_type);
1696621Sbt150084 }
1706621Sbt150084 
1716621Sbt150084 /*
1726621Sbt150084  * ixgbe_reset_phy_generic - Performs a PHY reset
1736621Sbt150084  * @hw: pointer to hardware structure
1746621Sbt150084  */
1756621Sbt150084 s32
1766621Sbt150084 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
1776621Sbt150084 {
1786621Sbt150084 	/*
1796621Sbt150084 	 * Perform soft PHY reset to the PHY_XS.
1806621Sbt150084 	 * This will cause a soft reset to the PHY
1816621Sbt150084 	 */
1826621Sbt150084 	return hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
1836621Sbt150084 	    IXGBE_MDIO_PHY_XS_DEV_TYPE,
1846621Sbt150084 	    IXGBE_MDIO_PHY_XS_RESET);
1856621Sbt150084 }
1866621Sbt150084 
1876621Sbt150084 /*
1886621Sbt150084  * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register
1896621Sbt150084  * @hw: pointer to hardware structure
1906621Sbt150084  * @reg_addr: 32 bit address of PHY register to read
1916621Sbt150084  * @phy_data: Pointer to read data from PHY register
1926621Sbt150084  */
1936621Sbt150084 s32
1946621Sbt150084 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
1956621Sbt150084     u32 device_type, u16 *phy_data)
1966621Sbt150084 {
1976621Sbt150084 	u32 command;
1986621Sbt150084 	u32 i;
1996621Sbt150084 	u32 data;
2006621Sbt150084 	s32 status = IXGBE_SUCCESS;
2016621Sbt150084 	u16 gssr;
2026621Sbt150084 
2036621Sbt150084 	if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
2046621Sbt150084 		gssr = IXGBE_GSSR_PHY1_SM;
2056621Sbt150084 	else
2066621Sbt150084 		gssr = IXGBE_GSSR_PHY0_SM;
2076621Sbt150084 
2086621Sbt150084 	if (ixgbe_acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS)
2096621Sbt150084 		status = IXGBE_ERR_SWFW_SYNC;
2106621Sbt150084 
2116621Sbt150084 	if (status == IXGBE_SUCCESS) {
2126621Sbt150084 		/* Setup and write the address cycle command */
2136621Sbt150084 		command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
2146621Sbt150084 		    (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
2156621Sbt150084 		    (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
2166621Sbt150084 		    (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
2176621Sbt150084 
2186621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
2196621Sbt150084 
2206621Sbt150084 		/*
2216621Sbt150084 		 * Check every 10 usec to see if the address cycle completed.
2226621Sbt150084 		 * The MDI Command bit will clear when the operation is
2236621Sbt150084 		 * complete
2246621Sbt150084 		 */
2256621Sbt150084 		for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
2266621Sbt150084 			usec_delay(10);
2276621Sbt150084 
2286621Sbt150084 			command = IXGBE_READ_REG(hw, IXGBE_MSCA);
2296621Sbt150084 
2306621Sbt150084 			if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
2316621Sbt150084 				break;
2326621Sbt150084 			}
2336621Sbt150084 		}
2346621Sbt150084 
2356621Sbt150084 		if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
2366621Sbt150084 			DEBUGOUT("PHY address command did not complete.\n");
2376621Sbt150084 			status = IXGBE_ERR_PHY;
2386621Sbt150084 		}
2396621Sbt150084 
2406621Sbt150084 		if (status == IXGBE_SUCCESS) {
2416621Sbt150084 			/*
2426621Sbt150084 			 * Address cycle complete, setup and write the read
2436621Sbt150084 			 * command
2446621Sbt150084 			 */
2456621Sbt150084 			command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
2466621Sbt150084 			    (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
2476621Sbt150084 			    (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
2486621Sbt150084 			    (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
2496621Sbt150084 
2506621Sbt150084 			IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
2516621Sbt150084 
2526621Sbt150084 			/*
2536621Sbt150084 			 * Check every 10 usec to see if the address cycle
2546621Sbt150084 			 * completed. The MDI Command bit will clear when the
2556621Sbt150084 			 * operation is complete
2566621Sbt150084 			 */
2576621Sbt150084 			for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
2586621Sbt150084 				usec_delay(10);
2596621Sbt150084 
2606621Sbt150084 				command = IXGBE_READ_REG(hw, IXGBE_MSCA);
2616621Sbt150084 
2626621Sbt150084 				if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
2636621Sbt150084 					break;
2646621Sbt150084 			}
2656621Sbt150084 
2666621Sbt150084 			if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
2676621Sbt150084 				DEBUGOUT("PHY read command didn't complete\n");
2686621Sbt150084 				status = IXGBE_ERR_PHY;
2696621Sbt150084 			} else {
2706621Sbt150084 				/*
2716621Sbt150084 				 * Read operation is complete.  Get the data
2726621Sbt150084 				 * from MSRWD
2736621Sbt150084 				 */
2746621Sbt150084 				data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
2756621Sbt150084 				data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
2766621Sbt150084 				*phy_data = (u16)(data);
2776621Sbt150084 			}
2786621Sbt150084 		}
2796621Sbt150084 
2806621Sbt150084 		ixgbe_release_swfw_sync(hw, gssr);
2816621Sbt150084 	}
2826621Sbt150084 
2836621Sbt150084 	return (status);
2846621Sbt150084 }
2856621Sbt150084 
2866621Sbt150084 /*
2876621Sbt150084  * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register
2886621Sbt150084  * @hw: pointer to hardware structure
2896621Sbt150084  * @reg_addr: 32 bit PHY register to write
2906621Sbt150084  * @device_type: 5 bit device type
2916621Sbt150084  * @phy_data: Data to write to the PHY register
2926621Sbt150084  */
2936621Sbt150084 s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
2946621Sbt150084     u32 device_type, u16 phy_data)
2956621Sbt150084 {
2966621Sbt150084 	u32 command;
2976621Sbt150084 	u32 i;
2986621Sbt150084 	s32 status = IXGBE_SUCCESS;
2996621Sbt150084 	u16 gssr;
3006621Sbt150084 
3016621Sbt150084 	if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
3026621Sbt150084 		gssr = IXGBE_GSSR_PHY1_SM;
3036621Sbt150084 	else
3046621Sbt150084 		gssr = IXGBE_GSSR_PHY0_SM;
3056621Sbt150084 
3066621Sbt150084 	if (ixgbe_acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS)
3076621Sbt150084 		status = IXGBE_ERR_SWFW_SYNC;
3086621Sbt150084 
3096621Sbt150084 	if (status == IXGBE_SUCCESS) {
3106621Sbt150084 		/*
3116621Sbt150084 		 * Put the data in the MDI single read and write data register
3126621Sbt150084 		 */
3136621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
3146621Sbt150084 
3156621Sbt150084 		/* Setup and write the address cycle command */
3166621Sbt150084 		command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
3176621Sbt150084 		    (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
3186621Sbt150084 		    (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
3196621Sbt150084 		    (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
3206621Sbt150084 
3216621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
3226621Sbt150084 
3236621Sbt150084 		/*
3246621Sbt150084 		 * Check every 10 usec to see if the address cycle completed.
3256621Sbt150084 		 * The MDI Command bit will clear when the operation is
3266621Sbt150084 		 * complete
3276621Sbt150084 		 */
3286621Sbt150084 		for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
3296621Sbt150084 			usec_delay(10);
3306621Sbt150084 
3316621Sbt150084 			command = IXGBE_READ_REG(hw, IXGBE_MSCA);
3326621Sbt150084 
3336621Sbt150084 			if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
3346621Sbt150084 				break;
3356621Sbt150084 		}
3366621Sbt150084 
3376621Sbt150084 		if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
3386621Sbt150084 			DEBUGOUT("PHY address cmd didn't complete\n");
3396621Sbt150084 			status = IXGBE_ERR_PHY;
3406621Sbt150084 		}
3416621Sbt150084 
3426621Sbt150084 		if (status == IXGBE_SUCCESS) {
3436621Sbt150084 			/*
3446621Sbt150084 			 * Address cycle complete, setup and write the write
3456621Sbt150084 			 * command
3466621Sbt150084 			 */
3476621Sbt150084 			command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
3486621Sbt150084 			    (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
3496621Sbt150084 			    (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
3506621Sbt150084 			    (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
3516621Sbt150084 
3526621Sbt150084 			IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
3536621Sbt150084 
3546621Sbt150084 			/*
3556621Sbt150084 			 * Check every 10 usec to see if the address cycle
3566621Sbt150084 			 * completed. The MDI Command bit will clear when the
3576621Sbt150084 			 * operation is complete
3586621Sbt150084 			 */
3596621Sbt150084 			for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
3606621Sbt150084 				usec_delay(10);
3616621Sbt150084 
3626621Sbt150084 				command = IXGBE_READ_REG(hw, IXGBE_MSCA);
3636621Sbt150084 
3646621Sbt150084 				if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
3656621Sbt150084 					break;
3666621Sbt150084 			}
3676621Sbt150084 
3686621Sbt150084 			if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
3696621Sbt150084 				DEBUGOUT("PHY address cmd didn't complete\n");
3706621Sbt150084 				status = IXGBE_ERR_PHY;
3716621Sbt150084 			}
3726621Sbt150084 		}
3736621Sbt150084 
3746621Sbt150084 		ixgbe_release_swfw_sync(hw, gssr);
3756621Sbt150084 	}
3766621Sbt150084 
3776621Sbt150084 	return (status);
3786621Sbt150084 }
3796621Sbt150084 
3806621Sbt150084 /*
3816621Sbt150084  * ixgbe_setup_phy_link_generic - Set and restart autoneg
3826621Sbt150084  * @hw: pointer to hardware structure
3836621Sbt150084  *
3846621Sbt150084  * Restart autonegotiation and PHY and waits for completion.
3856621Sbt150084  */
3866621Sbt150084 s32
3876621Sbt150084 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
3886621Sbt150084 {
3896621Sbt150084 	s32 status = IXGBE_NOT_IMPLEMENTED;
3906621Sbt150084 	u32 time_out;
3916621Sbt150084 	u32 max_time_out = 10;
3926621Sbt150084 	u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
3936621Sbt150084 
3946621Sbt150084 	/*
3956621Sbt150084 	 * Set advertisement settings in PHY based on autoneg_advertised
3966621Sbt150084 	 * settings. If autoneg_advertised = 0, then advertise default values
3976621Sbt150084 	 * tnx devices cannot be "forced" to a autoneg 10G and fail.  But can
3986621Sbt150084 	 * for a 1G.
3996621Sbt150084 	 */
4006621Sbt150084 	hw->phy.ops.read_reg(hw, IXGBE_MII_SPEED_SELECTION_REG,
4016621Sbt150084 	    IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
4026621Sbt150084 
4036621Sbt150084 	if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL)
4046621Sbt150084 		autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */
4056621Sbt150084 	else
4066621Sbt150084 		autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */
4076621Sbt150084 
4086621Sbt150084 	hw->phy.ops.write_reg(hw, IXGBE_MII_SPEED_SELECTION_REG,
4096621Sbt150084 	    IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
4106621Sbt150084 
4116621Sbt150084 	/* Restart PHY autonegotiation and wait for completion */
4126621Sbt150084 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
4136621Sbt150084 	    IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
4146621Sbt150084 
4156621Sbt150084 	autoneg_reg |= IXGBE_MII_RESTART;
4166621Sbt150084 
4176621Sbt150084 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
4186621Sbt150084 	    IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
4196621Sbt150084 
4206621Sbt150084 	/* Wait for autonegotiation to finish */
4216621Sbt150084 	for (time_out = 0; time_out < max_time_out; time_out++) {
4226621Sbt150084 		usec_delay(10);
4236621Sbt150084 		/* Restart PHY autonegotiation and wait for completion */
4246621Sbt150084 		status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
4256621Sbt150084 		    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
4266621Sbt150084 		    &autoneg_reg);
4276621Sbt150084 
4286621Sbt150084 		autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE;
4296621Sbt150084 		if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) {
4306621Sbt150084 			status = IXGBE_SUCCESS;
4316621Sbt150084 			break;
4326621Sbt150084 		}
4336621Sbt150084 	}
4346621Sbt150084 
4356621Sbt150084 	if (time_out == max_time_out)
4366621Sbt150084 		status = IXGBE_ERR_LINK_SETUP;
4376621Sbt150084 
4386621Sbt150084 	return (status);
4396621Sbt150084 }
4406621Sbt150084 
4416621Sbt150084 /*
4426621Sbt150084  * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities
4436621Sbt150084  * @hw: pointer to hardware structure
4446621Sbt150084  * @speed: new link speed
445*8490SPaul.Guo@Sun.COM  * @autoneg: true if autonegotiation enabled
4466621Sbt150084  */
4476621Sbt150084 s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
4486621Sbt150084     ixgbe_link_speed speed,
4496621Sbt150084     bool autoneg,
4506621Sbt150084     bool autoneg_wait_to_complete)
4516621Sbt150084 {
4526621Sbt150084 	UNREFERENCED_PARAMETER(autoneg);
4536621Sbt150084 	UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
4546621Sbt150084 
4556621Sbt150084 	/*
4566621Sbt150084 	 * Clear autoneg_advertised and set new values based on input link
4576621Sbt150084 	 * speed.
4586621Sbt150084 	 */
4596621Sbt150084 	hw->phy.autoneg_advertised = 0;
4606621Sbt150084 
4616621Sbt150084 	if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
4626621Sbt150084 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
4636621Sbt150084 	}
4646621Sbt150084 	if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
4656621Sbt150084 		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
4666621Sbt150084 	}
4676621Sbt150084 
4686621Sbt150084 	/* Setup link based on the new speed settings */
4696621Sbt150084 	hw->phy.ops.setup_link(hw);
4706621Sbt150084 
4716621Sbt150084 	return (IXGBE_SUCCESS);
4726621Sbt150084 }
473*8490SPaul.Guo@Sun.COM 
474*8490SPaul.Guo@Sun.COM /*
475*8490SPaul.Guo@Sun.COM  * ixgbe_check_phy_link_tnx - Determine link and speed status
476*8490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
477*8490SPaul.Guo@Sun.COM  *
478*8490SPaul.Guo@Sun.COM  * Reads the VS1 register to determine if link is up and the current speed for
479*8490SPaul.Guo@Sun.COM  * the PHY.
480*8490SPaul.Guo@Sun.COM  */
481*8490SPaul.Guo@Sun.COM s32
482*8490SPaul.Guo@Sun.COM ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
483*8490SPaul.Guo@Sun.COM     bool *link_up)
484*8490SPaul.Guo@Sun.COM {
485*8490SPaul.Guo@Sun.COM 	s32 status = IXGBE_SUCCESS;
486*8490SPaul.Guo@Sun.COM 	u32 time_out;
487*8490SPaul.Guo@Sun.COM 	u32 max_time_out = 10;
488*8490SPaul.Guo@Sun.COM 	u16 phy_link = 0;
489*8490SPaul.Guo@Sun.COM 	u16 phy_speed = 0;
490*8490SPaul.Guo@Sun.COM 	u16 phy_data = 0;
491*8490SPaul.Guo@Sun.COM 
492*8490SPaul.Guo@Sun.COM 	/* Initialize speed and link to default case */
493*8490SPaul.Guo@Sun.COM 	*link_up = false;
494*8490SPaul.Guo@Sun.COM 	*speed = IXGBE_LINK_SPEED_10GB_FULL;
495*8490SPaul.Guo@Sun.COM 
496*8490SPaul.Guo@Sun.COM 	/*
497*8490SPaul.Guo@Sun.COM 	 * Check current speed and link status of the PHY register.
498*8490SPaul.Guo@Sun.COM 	 * This is a vendor specific register and may have to
499*8490SPaul.Guo@Sun.COM 	 * be changed for other copper PHYs.
500*8490SPaul.Guo@Sun.COM 	 */
501*8490SPaul.Guo@Sun.COM 	for (time_out = 0; time_out < max_time_out; time_out++) {
502*8490SPaul.Guo@Sun.COM 		usec_delay(10);
503*8490SPaul.Guo@Sun.COM 		status = hw->phy.ops.read_reg(hw,
504*8490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
505*8490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
506*8490SPaul.Guo@Sun.COM 		    &phy_data);
507*8490SPaul.Guo@Sun.COM 		phy_link = phy_data &
508*8490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
509*8490SPaul.Guo@Sun.COM 		phy_speed = phy_data &
510*8490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
511*8490SPaul.Guo@Sun.COM 		if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
512*8490SPaul.Guo@Sun.COM 			*link_up = true;
513*8490SPaul.Guo@Sun.COM 			if (phy_speed ==
514*8490SPaul.Guo@Sun.COM 			    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
515*8490SPaul.Guo@Sun.COM 				*speed = IXGBE_LINK_SPEED_1GB_FULL;
516*8490SPaul.Guo@Sun.COM 			break;
517*8490SPaul.Guo@Sun.COM 		}
518*8490SPaul.Guo@Sun.COM 	}
519*8490SPaul.Guo@Sun.COM 
520*8490SPaul.Guo@Sun.COM 	return (status);
521*8490SPaul.Guo@Sun.COM }
522*8490SPaul.Guo@Sun.COM 
523*8490SPaul.Guo@Sun.COM /*
524*8490SPaul.Guo@Sun.COM  * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version
525*8490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
526*8490SPaul.Guo@Sun.COM  * @firmware_version: pointer to the PHY Firmware Version
527*8490SPaul.Guo@Sun.COM  */
528*8490SPaul.Guo@Sun.COM s32
529*8490SPaul.Guo@Sun.COM ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, u16 *firmware_version)
530*8490SPaul.Guo@Sun.COM {
531*8490SPaul.Guo@Sun.COM 	s32 status = IXGBE_SUCCESS;
532*8490SPaul.Guo@Sun.COM 
533*8490SPaul.Guo@Sun.COM 	status = hw->phy.ops.read_reg(hw, TNX_FW_REV,
534*8490SPaul.Guo@Sun.COM 	    IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, firmware_version);
535*8490SPaul.Guo@Sun.COM 
536*8490SPaul.Guo@Sun.COM 	return (status);
537*8490SPaul.Guo@Sun.COM }
538*8490SPaul.Guo@Sun.COM 
539*8490SPaul.Guo@Sun.COM /*
540*8490SPaul.Guo@Sun.COM  * ixgbe_reset_phy_nl - Performs a PHY reset
541*8490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
542*8490SPaul.Guo@Sun.COM  */
543*8490SPaul.Guo@Sun.COM s32
544*8490SPaul.Guo@Sun.COM ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
545*8490SPaul.Guo@Sun.COM {
546*8490SPaul.Guo@Sun.COM 	u16 phy_offset, control, eword, edata, block_crc;
547*8490SPaul.Guo@Sun.COM 	bool end_data = false;
548*8490SPaul.Guo@Sun.COM 	u16 list_offset, data_offset;
549*8490SPaul.Guo@Sun.COM 	u16 phy_data = 0;
550*8490SPaul.Guo@Sun.COM 	s32 ret_val = IXGBE_SUCCESS;
551*8490SPaul.Guo@Sun.COM 	u32 i;
552*8490SPaul.Guo@Sun.COM 
553*8490SPaul.Guo@Sun.COM 	hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
554*8490SPaul.Guo@Sun.COM 	    IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
555*8490SPaul.Guo@Sun.COM 
556*8490SPaul.Guo@Sun.COM 	/* reset the PHY and poll for completion */
557*8490SPaul.Guo@Sun.COM 	hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
558*8490SPaul.Guo@Sun.COM 	    IXGBE_MDIO_PHY_XS_DEV_TYPE,
559*8490SPaul.Guo@Sun.COM 	    (phy_data | IXGBE_MDIO_PHY_XS_RESET));
560*8490SPaul.Guo@Sun.COM 
561*8490SPaul.Guo@Sun.COM 	for (i = 0; i < 100; i++) {
562*8490SPaul.Guo@Sun.COM 		hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
563*8490SPaul.Guo@Sun.COM 		    IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
564*8490SPaul.Guo@Sun.COM 		if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0)
565*8490SPaul.Guo@Sun.COM 			break;
566*8490SPaul.Guo@Sun.COM 		msec_delay(10);
567*8490SPaul.Guo@Sun.COM 	}
568*8490SPaul.Guo@Sun.COM 
569*8490SPaul.Guo@Sun.COM 	if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) {
570*8490SPaul.Guo@Sun.COM 		DEBUGOUT("PHY reset did not complete.\n");
571*8490SPaul.Guo@Sun.COM 		ret_val = IXGBE_ERR_PHY;
572*8490SPaul.Guo@Sun.COM 		goto out;
573*8490SPaul.Guo@Sun.COM 	}
574*8490SPaul.Guo@Sun.COM 
575*8490SPaul.Guo@Sun.COM 	/* Get init offsets */
576*8490SPaul.Guo@Sun.COM 	ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
577*8490SPaul.Guo@Sun.COM 	    &data_offset);
578*8490SPaul.Guo@Sun.COM 	if (ret_val != IXGBE_SUCCESS)
579*8490SPaul.Guo@Sun.COM 		goto out;
580*8490SPaul.Guo@Sun.COM 
581*8490SPaul.Guo@Sun.COM 	ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc);
582*8490SPaul.Guo@Sun.COM 	data_offset++;
583*8490SPaul.Guo@Sun.COM 	while (!end_data) {
584*8490SPaul.Guo@Sun.COM 		/*
585*8490SPaul.Guo@Sun.COM 		 * Read control word from PHY init contents offset
586*8490SPaul.Guo@Sun.COM 		 */
587*8490SPaul.Guo@Sun.COM 		ret_val = hw->eeprom.ops.read(hw, data_offset, &eword);
588*8490SPaul.Guo@Sun.COM 		control = (eword & IXGBE_CONTROL_MASK_NL) >>
589*8490SPaul.Guo@Sun.COM 		    IXGBE_CONTROL_SHIFT_NL;
590*8490SPaul.Guo@Sun.COM 		edata = eword & IXGBE_DATA_MASK_NL;
591*8490SPaul.Guo@Sun.COM 		switch (control) {
592*8490SPaul.Guo@Sun.COM 		case IXGBE_DELAY_NL:
593*8490SPaul.Guo@Sun.COM 			data_offset++;
594*8490SPaul.Guo@Sun.COM 			DEBUGOUT1("DELAY: %d MS\n", edata);
595*8490SPaul.Guo@Sun.COM 			msec_delay(edata);
596*8490SPaul.Guo@Sun.COM 			break;
597*8490SPaul.Guo@Sun.COM 		case IXGBE_DATA_NL:
598*8490SPaul.Guo@Sun.COM 			DEBUGOUT("DATA:  \n");
599*8490SPaul.Guo@Sun.COM 			data_offset++;
600*8490SPaul.Guo@Sun.COM 			hw->eeprom.ops.read(hw, data_offset++, &phy_offset);
601*8490SPaul.Guo@Sun.COM 			for (i = 0; i < edata; i++) {
602*8490SPaul.Guo@Sun.COM 				hw->eeprom.ops.read(hw, data_offset, &eword);
603*8490SPaul.Guo@Sun.COM 				hw->phy.ops.write_reg(hw, phy_offset,
604*8490SPaul.Guo@Sun.COM 				    IXGBE_TWINAX_DEV, eword);
605*8490SPaul.Guo@Sun.COM 				DEBUGOUT2("Wrote %4.4x to %4.4x\n", eword,
606*8490SPaul.Guo@Sun.COM 				    phy_offset);
607*8490SPaul.Guo@Sun.COM 				data_offset++;
608*8490SPaul.Guo@Sun.COM 				phy_offset++;
609*8490SPaul.Guo@Sun.COM 			}
610*8490SPaul.Guo@Sun.COM 			break;
611*8490SPaul.Guo@Sun.COM 		case IXGBE_CONTROL_NL:
612*8490SPaul.Guo@Sun.COM 			data_offset++;
613*8490SPaul.Guo@Sun.COM 			DEBUGOUT("CONTROL: \n");
614*8490SPaul.Guo@Sun.COM 			if (edata == IXGBE_CONTROL_EOL_NL) {
615*8490SPaul.Guo@Sun.COM 				DEBUGOUT("EOL\n");
616*8490SPaul.Guo@Sun.COM 				end_data = true;
617*8490SPaul.Guo@Sun.COM 			} else if (edata == IXGBE_CONTROL_SOL_NL) {
618*8490SPaul.Guo@Sun.COM 				DEBUGOUT("SOL\n");
619*8490SPaul.Guo@Sun.COM 			} else {
620*8490SPaul.Guo@Sun.COM 				DEBUGOUT("Bad control value\n");
621*8490SPaul.Guo@Sun.COM 				ret_val = IXGBE_ERR_PHY;
622*8490SPaul.Guo@Sun.COM 				goto out;
623*8490SPaul.Guo@Sun.COM 			}
624*8490SPaul.Guo@Sun.COM 			break;
625*8490SPaul.Guo@Sun.COM 		default:
626*8490SPaul.Guo@Sun.COM 			DEBUGOUT("Bad control type\n");
627*8490SPaul.Guo@Sun.COM 			ret_val = IXGBE_ERR_PHY;
628*8490SPaul.Guo@Sun.COM 			goto out;
629*8490SPaul.Guo@Sun.COM 		}
630*8490SPaul.Guo@Sun.COM 	}
631*8490SPaul.Guo@Sun.COM 
632*8490SPaul.Guo@Sun.COM out:
633*8490SPaul.Guo@Sun.COM 	return (ret_val);
634*8490SPaul.Guo@Sun.COM }
635*8490SPaul.Guo@Sun.COM 
636*8490SPaul.Guo@Sun.COM /*
637*8490SPaul.Guo@Sun.COM  * ixgbe_identify_sfp_module_generic - Identifies SFP module and assigns
638*8490SPaul.Guo@Sun.COM  * the PHY type.
639*8490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
640*8490SPaul.Guo@Sun.COM  *
641*8490SPaul.Guo@Sun.COM  * Searches for and identifies the SFP module.  Assigns appropriate PHY type.
642*8490SPaul.Guo@Sun.COM  */
643*8490SPaul.Guo@Sun.COM s32
644*8490SPaul.Guo@Sun.COM ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
645*8490SPaul.Guo@Sun.COM {
646*8490SPaul.Guo@Sun.COM 	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
647*8490SPaul.Guo@Sun.COM 	u32 vendor_oui = 0;
648*8490SPaul.Guo@Sun.COM 	u8 identifier = 0;
649*8490SPaul.Guo@Sun.COM 	u8 comp_codes_1g = 0;
650*8490SPaul.Guo@Sun.COM 	u8 comp_codes_10g = 0;
651*8490SPaul.Guo@Sun.COM 	u8 oui_bytes[4] = {0, 0, 0, 0};
652*8490SPaul.Guo@Sun.COM 	u8 transmission_media = 0;
653*8490SPaul.Guo@Sun.COM 
654*8490SPaul.Guo@Sun.COM 	status = hw->phy.ops.read_i2c_eeprom(hw,
655*8490SPaul.Guo@Sun.COM 	    IXGBE_SFF_IDENTIFIER, &identifier);
656*8490SPaul.Guo@Sun.COM 
657*8490SPaul.Guo@Sun.COM 	if (status == IXGBE_ERR_SFP_NOT_PRESENT) {
658*8490SPaul.Guo@Sun.COM 		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
659*8490SPaul.Guo@Sun.COM 		goto out;
660*8490SPaul.Guo@Sun.COM 	}
661*8490SPaul.Guo@Sun.COM 
662*8490SPaul.Guo@Sun.COM 	if (identifier == IXGBE_SFF_IDENTIFIER_SFP) {
663*8490SPaul.Guo@Sun.COM 		hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES,
664*8490SPaul.Guo@Sun.COM 		    &comp_codes_1g);
665*8490SPaul.Guo@Sun.COM 		hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES,
666*8490SPaul.Guo@Sun.COM 		    &comp_codes_10g);
667*8490SPaul.Guo@Sun.COM 		hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA,
668*8490SPaul.Guo@Sun.COM 		    &transmission_media);
669*8490SPaul.Guo@Sun.COM 
670*8490SPaul.Guo@Sun.COM 		/*
671*8490SPaul.Guo@Sun.COM 		 * ID  Module
672*8490SPaul.Guo@Sun.COM 		 * ============
673*8490SPaul.Guo@Sun.COM 		 * 0    SFP_DA_CU
674*8490SPaul.Guo@Sun.COM 		 * 1    SFP_SR
675*8490SPaul.Guo@Sun.COM 		 * 2    SFP_LR
676*8490SPaul.Guo@Sun.COM 		 */
677*8490SPaul.Guo@Sun.COM 		if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE)
678*8490SPaul.Guo@Sun.COM 			hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
679*8490SPaul.Guo@Sun.COM 		else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
680*8490SPaul.Guo@Sun.COM 			hw->phy.sfp_type = ixgbe_sfp_type_sr;
681*8490SPaul.Guo@Sun.COM 		else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
682*8490SPaul.Guo@Sun.COM 			hw->phy.sfp_type = ixgbe_sfp_type_lr;
683*8490SPaul.Guo@Sun.COM 		else
684*8490SPaul.Guo@Sun.COM 			hw->phy.sfp_type = ixgbe_sfp_type_unknown;
685*8490SPaul.Guo@Sun.COM 
686*8490SPaul.Guo@Sun.COM 		/* Determine PHY vendor */
687*8490SPaul.Guo@Sun.COM 		if (hw->phy.type == ixgbe_phy_unknown) {
688*8490SPaul.Guo@Sun.COM 			hw->phy.id = identifier;
689*8490SPaul.Guo@Sun.COM 			hw->phy.ops.read_i2c_eeprom(hw,
690*8490SPaul.Guo@Sun.COM 			    IXGBE_SFF_VENDOR_OUI_BYTE0, &oui_bytes[0]);
691*8490SPaul.Guo@Sun.COM 			hw->phy.ops.read_i2c_eeprom(hw,
692*8490SPaul.Guo@Sun.COM 			    IXGBE_SFF_VENDOR_OUI_BYTE1, &oui_bytes[1]);
693*8490SPaul.Guo@Sun.COM 			hw->phy.ops.read_i2c_eeprom(hw,
694*8490SPaul.Guo@Sun.COM 			    IXGBE_SFF_VENDOR_OUI_BYTE2, &oui_bytes[2]);
695*8490SPaul.Guo@Sun.COM 
696*8490SPaul.Guo@Sun.COM 			vendor_oui =
697*8490SPaul.Guo@Sun.COM 			    ((oui_bytes[0] <<
698*8490SPaul.Guo@Sun.COM 			    IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
699*8490SPaul.Guo@Sun.COM 			    (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
700*8490SPaul.Guo@Sun.COM 			    (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
701*8490SPaul.Guo@Sun.COM 
702*8490SPaul.Guo@Sun.COM 			switch (vendor_oui) {
703*8490SPaul.Guo@Sun.COM 			case IXGBE_SFF_VENDOR_OUI_TYCO:
704*8490SPaul.Guo@Sun.COM 				if (transmission_media &
705*8490SPaul.Guo@Sun.COM 				    IXGBE_SFF_TWIN_AX_CAPABLE)
706*8490SPaul.Guo@Sun.COM 					hw->phy.type = ixgbe_phy_tw_tyco;
707*8490SPaul.Guo@Sun.COM 				break;
708*8490SPaul.Guo@Sun.COM 			case IXGBE_SFF_VENDOR_OUI_FTL:
709*8490SPaul.Guo@Sun.COM 				hw->phy.type = ixgbe_phy_sfp_ftl;
710*8490SPaul.Guo@Sun.COM 				break;
711*8490SPaul.Guo@Sun.COM 			case IXGBE_SFF_VENDOR_OUI_AVAGO:
712*8490SPaul.Guo@Sun.COM 				hw->phy.type = ixgbe_phy_sfp_avago;
713*8490SPaul.Guo@Sun.COM 				break;
714*8490SPaul.Guo@Sun.COM 			default:
715*8490SPaul.Guo@Sun.COM 				if (transmission_media &
716*8490SPaul.Guo@Sun.COM 				    IXGBE_SFF_TWIN_AX_CAPABLE)
717*8490SPaul.Guo@Sun.COM 					hw->phy.type = ixgbe_phy_tw_unknown;
718*8490SPaul.Guo@Sun.COM 				else
719*8490SPaul.Guo@Sun.COM 					hw->phy.type = ixgbe_phy_sfp_unknown;
720*8490SPaul.Guo@Sun.COM 				break;
721*8490SPaul.Guo@Sun.COM 			}
722*8490SPaul.Guo@Sun.COM 		}
723*8490SPaul.Guo@Sun.COM 		status = IXGBE_SUCCESS;
724*8490SPaul.Guo@Sun.COM 	}
725*8490SPaul.Guo@Sun.COM 
726*8490SPaul.Guo@Sun.COM out:
727*8490SPaul.Guo@Sun.COM 	return (status);
728*8490SPaul.Guo@Sun.COM }
729*8490SPaul.Guo@Sun.COM 
730*8490SPaul.Guo@Sun.COM 
731*8490SPaul.Guo@Sun.COM /*
732*8490SPaul.Guo@Sun.COM  * ixgbe_get_sfp_init_sequence_offsets - Checks the MAC's EEPROM to see
733*8490SPaul.Guo@Sun.COM  * if it supports a given SFP+ module type, if so it returns the offsets to the
734*8490SPaul.Guo@Sun.COM  * phy init sequence block.
735*8490SPaul.Guo@Sun.COM  * @hw: pointer to hardware structure
736*8490SPaul.Guo@Sun.COM  * @list_offset: offset to the SFP ID list
737*8490SPaul.Guo@Sun.COM  * @data_offset: offset to the SFP data block
738*8490SPaul.Guo@Sun.COM  */
739*8490SPaul.Guo@Sun.COM s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
740*8490SPaul.Guo@Sun.COM     u16 *list_offset, u16 *data_offset)
741*8490SPaul.Guo@Sun.COM {
742*8490SPaul.Guo@Sun.COM 	u16 sfp_id;
743*8490SPaul.Guo@Sun.COM 
744*8490SPaul.Guo@Sun.COM 	if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
745*8490SPaul.Guo@Sun.COM 		return (IXGBE_ERR_SFP_NOT_SUPPORTED);
746*8490SPaul.Guo@Sun.COM 
747*8490SPaul.Guo@Sun.COM 	if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
748*8490SPaul.Guo@Sun.COM 		return (IXGBE_ERR_SFP_NOT_PRESENT);
749*8490SPaul.Guo@Sun.COM 
750*8490SPaul.Guo@Sun.COM 	if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) &&
751*8490SPaul.Guo@Sun.COM 	    (hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
752*8490SPaul.Guo@Sun.COM 		return (IXGBE_ERR_SFP_NOT_SUPPORTED);
753*8490SPaul.Guo@Sun.COM 
754*8490SPaul.Guo@Sun.COM 	/* Read offset to PHY init contents */
755*8490SPaul.Guo@Sun.COM 	hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset);
756*8490SPaul.Guo@Sun.COM 
757*8490SPaul.Guo@Sun.COM 	if ((!*list_offset) || (*list_offset == 0xFFFF))
758*8490SPaul.Guo@Sun.COM 		return (IXGBE_ERR_PHY);
759*8490SPaul.Guo@Sun.COM 
760*8490SPaul.Guo@Sun.COM 	/* Shift offset to first ID word */
761*8490SPaul.Guo@Sun.COM 	(*list_offset)++;
762*8490SPaul.Guo@Sun.COM 
763*8490SPaul.Guo@Sun.COM 	/*
764*8490SPaul.Guo@Sun.COM 	 * Find the matching SFP ID in the EEPROM
765*8490SPaul.Guo@Sun.COM 	 * and program the init sequence
766*8490SPaul.Guo@Sun.COM 	 */
767*8490SPaul.Guo@Sun.COM 	hw->eeprom.ops.read(hw, *list_offset, &sfp_id);
768*8490SPaul.Guo@Sun.COM 
769*8490SPaul.Guo@Sun.COM 	while (sfp_id != IXGBE_PHY_INIT_END_NL) {
770*8490SPaul.Guo@Sun.COM 		if (sfp_id == hw->phy.sfp_type) {
771*8490SPaul.Guo@Sun.COM 			(*list_offset)++;
772*8490SPaul.Guo@Sun.COM 			hw->eeprom.ops.read(hw, *list_offset, data_offset);
773*8490SPaul.Guo@Sun.COM 			if ((!*data_offset) || (*data_offset == 0xFFFF)) {
774*8490SPaul.Guo@Sun.COM 				DEBUGOUT("SFP+ module not supported\n");
775*8490SPaul.Guo@Sun.COM 				return (IXGBE_ERR_SFP_NOT_SUPPORTED);
776*8490SPaul.Guo@Sun.COM 			} else {
777*8490SPaul.Guo@Sun.COM 				break;
778*8490SPaul.Guo@Sun.COM 			}
779*8490SPaul.Guo@Sun.COM 		} else {
780*8490SPaul.Guo@Sun.COM 			(*list_offset) += 2;
781*8490SPaul.Guo@Sun.COM 			if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id))
782*8490SPaul.Guo@Sun.COM 				return (IXGBE_ERR_PHY);
783*8490SPaul.Guo@Sun.COM 		}
784*8490SPaul.Guo@Sun.COM 	}
785*8490SPaul.Guo@Sun.COM 
786*8490SPaul.Guo@Sun.COM 	if (sfp_id == IXGBE_PHY_INIT_END_NL) {
787*8490SPaul.Guo@Sun.COM 		DEBUGOUT("No matching SFP+ module found\n");
788*8490SPaul.Guo@Sun.COM 		return (IXGBE_ERR_SFP_NOT_SUPPORTED);
789*8490SPaul.Guo@Sun.COM 	}
790*8490SPaul.Guo@Sun.COM 
791*8490SPaul.Guo@Sun.COM 	return (IXGBE_SUCCESS);
792*8490SPaul.Guo@Sun.COM }
793