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